aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author ClarkeCode <33846391+ClarkeCode@users.noreply.github.com>2023-02-15 01:06:14 +0100
committer GitHub <noreply@github.com>2023-02-15 01:06:14 +0100
commitfb0131216fac3a9952892b8b7dfdddb6b451f9de (patch)
tree480fe8b21a9219301b91cbdd0950e8a32db76329
parent6a0158e625eaffbae0f214620a1d728728934033 (diff)
parent436b9bd4d3372bdd96fd4f395f162c8b2f88023a (diff)
Merge pull request #9 from OpenVic2Project/docs-wip
Introduction of C++ styleguide
-rw-r--r--docs/README.md3
-rw-r--r--docs/styleguide-cpp.md320
2 files changed, 323 insertions, 0 deletions
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..bd40237
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,3 @@
+# Documentation
+
+[C++ Style Guidlines](styleguide-cpp.md) \ No newline at end of file
diff --git a/docs/styleguide-cpp.md b/docs/styleguide-cpp.md
new file mode 100644
index 0000000..69471f5
--- /dev/null
+++ b/docs/styleguide-cpp.md
@@ -0,0 +1,320 @@
+# OpenVic2 C++ Style Guidelines
+
+## Table of Contents
+ 1. [Why Style?](styleguide-cpp.md#1-why-style)
+
+ 1.1. [General Principles](styleguide-cpp.md#11-general-principles)
+
+ 1.2 [File Formatting](styleguide-cpp.md#12-file-formatting)
+
+ 2. [Conventions](styleguide-cpp.md#2-conventions)
+
+ 2.1. [Naming Conventions](styleguide-cpp.md#21-naming-conventions)
+
+ 2.2 [Do's and Don'ts](styleguide-cpp.md#22-dos-and-donts)
+
+## 1. Why Style?
+>“Programs are meant to be read by humans and only incidentally for computers to execute.”
+> - H. Abelson and G. Sussman in [*Structure and Interpretation of Computer Programs*](https://en.wikipedia.org/wiki/Structure_and_Interpretation_of_Computer_Programs)
+
+The purpose of this styleguide is to give a clear framework for other contributors, to minimize ambiguity, and to have a consistant way to convey the intent of code.
+
+### 1.1. General Principles
+- Prefer clarity over brevity
+- [Don’t optimize prematurely](https://youtu.be/tKbV6BpH-C8)
+- In cases of ambiguity, use your best judgement
+
+### 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 `OpenVic2` namespace (or a nested namespace)
+- Any submodules or third-party utilities should be in the `OpenVic2/extension/deps` directory
+- Groups of related source files should be kept in a sub-directory of `OpenVic2/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
+ ```c++
+ //Correct
+ if (condition) {
+ //Cool things here
+ }
+
+ //Incorrect
+ if (condition)
+ {
+ //cool things here
+ }
+ ```
+- With arithmetic, relational, and logical operators keep spaces between variables and literals
+ ```c++
+ //Correct
+ int myNumber = (someVariable + 10) % 3;
+
+ //Incorrect
+ int myNumber=(someVariable+10)%3;
+ ```
+- Prefix and postfix operators should be immediately attached to the affected variable
+ ```c++
+ //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) atributes
+ - Attributes
+ - Constructors and Destructors
+ - Static (class-wide) methods
+ - Methods
+
+ ```c++
+ 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`)
+ ```c++
+ 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
+ ```c++
+ //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.
+ ```c++
+ //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
+ ```c++
+ //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
+ ```c++
+ //Correct
+ enum class Colours { Red, Green, Blue, CharcoalGrey };
+
+ //Incorrect
+ enum Colours { Red, Green, Blue, CharcoalGrey };
+ ```
+- Use type aliases, not `typedef`s
+ ```c++
+ //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`
+ ```c++
+ //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
+ ```c++
+ //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
+ ```c++
+ //Correct
+ int* myPointer = &myNumber;
+
+ //Incorrect
+ int * myPointer = &myNumber;
+ int *myPointer = &myNumber;
+ int*myPointer = &myNumber;
+ ```
+- Do not declare multiple pointer variables on a single line
+ ```c++
+ //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.
+ ```c++
+ //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
+ ```c++
+ //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.
+ ```c++
+ //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 referance, 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 `&`
+ ```c++
+ //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 OpenVic2 headers
+ - C++ standard headers and Godot headers should be enclosed by angle brackets `<>`
+ - OpenVic2 headers should be enclosed by double quotes `""`
+ ```c++
+ //Correct
+ #include <vector>
+ #include <string>
+ #include <godot_cpp/classes/object.hpp>
+ #include <godot_cpp/core/class_db.hpp>
+ #include "openvic2/src/SampleHeader.hpp"
+ #include "openvic2/src/SampleHeader2.hpp"
+
+ //Incorrect
+ #include "openvic2/src/SampleHeader.hpp"
+ #include <godot_cpp/classes/object.hpp>
+ #include "openvic2/src/SampleHeader2.hpp"
+ #include <godot_cpp/core/class_db.hpp>
+ #include <vector>
+ #include <string>
+ ```