Skip to content

Latest commit

 

History

History
320 lines (275 loc) · 8.73 KB

File metadata and controls

320 lines (275 loc) · 8.73 KB

OpenVic C++ Style Guidelines

Table of Contents

  1. Why Style?

    1.1. General Principles

    1.2 File Formatting

  2. Conventions

    2.1. Naming Conventions

    2.2 Do's and Don'ts

1. Why Style?

“Programs are meant to be read by humans and only incidentally for computers to execute.”

The purpose of this styleguide is to give a clear framework for other contributors, to minimize ambiguity, and to have a consistent way to convey the intent of code.

1.1. General Principles

1.2. File Formatting

Source code files should adhere to the following:

  • Encoded in UTF-8
  • Use tabs for indentation
  • Use LF for end-of-line sequences
  • No trailing whitespace (Lines which end in spaces or tabs)
  • Any #include directives should be at the top of the file
  • Any header files have the .hpp file extension
  • Any implementation files have the .cpp file extension
  • Code should be within the OpenVic namespace (or a nested namespace)
  • Any submodules or third-party utilities should be in the OpenVic/extension/deps directory
  • Groups of related source files should be kept in a sub-directory of OpenVic/extension/src
  • Any lines that are longer than 120 characters in length should be split across multiple lines

2. Conventions

2.1 Naming Conventions

Item Writing Convention Example
Class names Pascal Case MyCoolExample
Struct names Pascal Case MyCoolExample
Variable and Attribute names Camel Case myCoolExample
Function and Method names Camel Case myCoolExample
Constants Macro Case MY_COOL_EXAMPLE
Macros Macro Case MY_COOL_EXAMPLE
Class or container type aliases Pascal Case MyCoolExample
Builtin or numeric type aliases Camel Case ( _t suffix) myCoolExample_t
Enum names Pascal Case MyCoolExample
Enum values Pascal Case MyCoolExample

2.2 Do's and Don'ts

  • Keep the opening scope brace on the same line

     //Correct
     if (condition) {
     	//Cool things here
     }
    
     //Incorrect
     if (condition)
     {
     	//cool things here
     }
  • With arithmetic, relational, and logical operators keep spaces between variables and literals

     //Correct
     int myNumber = (someVariable + 10) % 3;
    
     //Incorrect
     int myNumber=(someVariable+10)%3;
  • Prefix and postfix operators should be immediately attached to the affected variable

     //Correct
     for (int x = 0; x < 10; x++) {
     	//Something cool
     }
    
     //Incorrect
     for (int x = 0; x < 10; x ++ ) {
     	//Something cool
     }
  • The content of classes should appear in the following order:

    • Type Aliases
    • Static (class-wide) attributes
    • Attributes
    • Constructors and Destructors
    • Static (class-wide) methods
    • Methods
     class Human {
     	public:
     	using name_t = std::string;
    
     	private:
     	static size_t numberOfHumans;
    
     	public:
     	name_t name;
     	size_t age;
     	size_t familyMembers;
    
     	Human();
     	~Human();
    
     	static bool isMoreHumansThan(size_t number);
    
    
     	private:
     	void coolPrivateMethod();
    
     	public:
     	void coolPublicMethod();
     	void anotherCoolPublicMethod();
    
     	inline bool isVotingAge() const {
     		return age >= 18;
     	}
     };
  • Class visibility specifiers should be followed by the next declaration on a new line at the same indentation level

    • Group methods and attributes by their visibility specifier from most to least restrictive (private, protected, then public)
     class ExampleClass {
     	//Attributes...
    
     	private:
     	void firstPrivateMethod();
     	void secondPrivateMethod();
     	void thirdPrivateMethod();
    
     	protected:
     	void firstProtectedMethod();
     	void secondProtectedMethod();
     	void thirdProtectedMethod();
    
     	public:
     	void firstPublicMethod();
     	void secondPublicMethod();
     	void thirdPublicMethod();
     };
  • Methods which do not mutate an object's state should be marked as a const method

     //Correct
     bool RGBColour::isColourBlack() const {
     	return redChannel == 0 && greenChannel == 0 && blueChannel == 0;
     }
    
     //Incorrect
     bool RGBColour::isColourBlack() {
     	return redChannel == 0 && greenChannel == 0 && blueChannel == 0;
     }
  • When argument or parameter lists are too long to easily fit on one line: begin the argument list on the next line, two indentation levels higher than the function's indentation.

     //Correct
     callingAFunctionWithAVeryLongNameAndManyArguments(
     		longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree,
     		longArgumentNameFour, longArgumentNameFive, longArgumentNameSix,
     		longArgumentNameSeven, longArgumentNameEight);
    
     //Incorrect
     callingAFunctionWithAVeryLongNameAndManyArguments(longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree, longArgumentNameFour, longArgumentNameFive, longArgumentNameSix, longArgumentNameSeven, longArgumentNameEight);
  • In header files, put #pragma once at the top of the file, not C-style header guards

     //Correct
     #pragma once
     /*
     header contents here
     */
    
     //Incorrect
     #ifndef MY_COOL_HEADER_H
     #define MY_COOL_HEADER_H
     /*
     header contents here
     */
     #endif
  • Use enum classes, not plain enums

     //Correct
     enum class Colours { Red, Green, Blue, CharcoalGrey };
    
     //Incorrect
     enum Colours { Red, Green, Blue, CharcoalGrey };
  • Use type aliases, not typedefs

     //Correct
     using MyContainer = std::vector<int>;
     using byte_t = unsigned char;
    
     //Incorrect
     typedef std::vector<int> MyContainer;
     typedef unsigned char byte_t;
  • Use explicit types, do not use auto

     //Correct
     std::pair<int, int> coordinate = getPlayerLocation();
    
     //Incorrect
     auto coordinate = getPlayerLocation();
  • Do not use C-style casts, instead use C++ casts (ie: static_cast, const_cast, reinterpret_cast)

    • dynamic_cast should only be used with caution
     //Correct
     int myNumber = static_cast<int>(someFloatValue);
    
     //Incorrect
     int myNumber = (int) someFloatValue;
  • When declaring a pointer, put the asterisk immediately after the type, followed by a space and the variable name

     //Correct
     int* myPointer = &myNumber;
    
     //Incorrect
     int * myPointer = &myNumber;
     int *myPointer = &myNumber;
     int*myPointer = &myNumber;
  • Do not declare multiple pointer variables on a single line

     //Correct
     int* p1;
     int* p2;
    
     //Incorrect
     int *p1, *p2;
  • Keep the initialization of a variable and its declaration as close as possible, ideally on the same line.

     //Correct
     int myNumber = 23;
    
     //Incorrect
     int myNumber;
     myNumber = 23;
  • For constant values that are computable at compile-time, use constexpr instead of the const keyword

     //Correct
     constexpr size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256;
    
     //Incorrect
     const size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256;
  • The name of functions returning a boolean value should start with is or has; whichever makes the most sense.

     //Correct
     bool isEven(int num) {
     	return num % 2 == 0;
     }
    
     //Incorrect
     bool even(int num) {
     	return num % 2 == 0;
     }
  • When a function parameter is being passed by const reference, put one space between the type and const&. If a parameter is passed by mutable reference do not put a space between the type and the &

     //Correct for a const reference
     bool hasLargeNumber(std::vector<int> const& numbers) {
     	//some cool stuff
     	return true;
     }
    
     //Incorrect for a const reference
     bool hasLargeNumber(std::vector<int>const& numbers) {
     	//some cool stuff
     	return true;
     }
    
     //Correct for a mutable reference
     bool hasLargeNumber(std::vector<int>& numbers) {
     	//some cool stuff
     	return true;
     }
    
     //Incorrect for a mutable reference
     bool hasLargeNumber(std::vector<int> & numbers) {
     	//some cool stuff
     	return true;
     }
  • The include order should be: C++ standard headers, followed by Godot headers, then OpenVic headers

    • C++ standard headers and Godot headers should be enclosed by angle brackets <>
    • OpenVic headers should be enclosed by double quotes ""
    //Correct
    #include <vector>
    #include <string>
    #include <godot_cpp/classes/object.hpp>
    #include <godot_cpp/core/class_db.hpp>
    #include "openvic/src/SampleHeader.hpp"
    #include "openvic/src/SampleHeader2.hpp"
    
    //Incorrect
    #include "openvic/src/SampleHeader.hpp"
    #include <godot_cpp/classes/object.hpp>
    #include "openvic/src/SampleHeader2.hpp"
    #include <godot_cpp/core/class_db.hpp>
    #include <vector>
    #include <string>