diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-05 14:21:45 +0100 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-05 14:21:45 +0100 |
commit | 9572c5b35de2d13dbe7f942e3ecc50d28b36e9b8 (patch) | |
tree | eaaf0b99569c836c6cb7915c83ddbf28a0b47a80 /contributing.md | |
parent | 8839d428b76bb1bf4a5318751a78867d6ef7c4a2 (diff) |
update contributing.md
Diffstat (limited to 'contributing.md')
-rw-r--r-- | contributing.md | 467 |
1 files changed, 259 insertions, 208 deletions
diff --git a/contributing.md b/contributing.md index 4c347bb..38a83fd 100644 --- a/contributing.md +++ b/contributing.md @@ -11,351 +11,402 @@ `name/feature` (i.e. `loek/dll-so-poc` or `jaro/class2`) - The master branch is considered stable, and should always contain a working/compiling version of the project - - TODO: tagging / versions - # Code style +- Formatting nitty-gritty is handled by clang-format/clang-tidy (run `make + format` in the root folder of this repository to format all sources files) - ASCII only + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good + // crepe startup message std::string message = "Hello, world!"; - - // Bad - std::string message = "こんにちは世界"; ``` + </td><td> + ```cpp + // crêpe startup message + std::string message = "こんにちは世界"; + ``` + </td></tr></table> - Class names are always singular + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - class Car {}; - - // Bad - class Cars {}; + class Foo {}; ``` - -- Explanatory comments are placed above the line(s) they are explaining + </td><td> ```cpp - // Good - // This function adds two numbers - int add(int a, int b) { - return a + b; - } - - // Bad - int add(int a, int b) { - return a + b; // This function adds two numbers - } + class Cars {}; ``` - -- Source files should only contain comments that plainly state what the code is supposed to do + </td></tr></table> +- Source files contain the following types of comments: + - What is the code supposed to do (optional) + - Implementation details (if applicable) +- Header files contain the following types of comments: + - Usage documentation (required) + - Implementation details (if they affect the header) + - Design/data structure decisions (if applicable) +- Comments are placed *above* the line(s) they are explaining + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - // Initialize the engine - engine.init(); - - // Bad - // Initialize the engine with default settings and prepare it for running - engine.init(); + int add(int a, int b) { + // add numbers + int out = a + b; + return out; + } ``` - -- Explanatory comments in headers may be used to clarify implementation design decisions + </td><td> ```cpp - // Good - // This class handles the rendering process - class Renderer { - // This method initializes the rendering context - void init_context(); - }; - - // Bad - class Renderer { - void init_context(); // This method initializes the rendering context - }; + int add(int a, int b) { + int out = a + b; // add numbers + return out; + } ``` - -- Formatting nitty-gritty is handled by clang-format/clang-tidy (run `make format` in the root folder of this repository to format all sources files) - - -- Header includes are split into paragraphs separated by a blank line. The order is: + </td></tr></table> +- Header includes are split into paragraphs separated by a blank line. The + order is: 1. system headers (using `<`brackets`>`) 2. relative headers NOT in the same folder as the current file 3. relative headers in the same folder as the current file - ```cpp - // Good - #include <iostream> - - #include "utils/helper.h" - - #include "main.h" - - // Bad - #include "main.h" - #include <iostream> - #include "utils/helper.h" - ``` + > [!NOTE] + > When using libraries of which the header include order is important, make + > sure to separate the include statements using a blank line (clang-format + > may sort include statements, but does not sort across empty lines). -- When using libraries of which the header include order is important, make sure to separate the include statements using a blank line (clang-format may sort include statements, but does not sort across empty lines). + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good + #include <SDL2/SDL.h> #include <iostream> - - #include <boost/algorithm/string.hpp> - - // Bad - #include <iostream> - #include <boost/algorithm/string.hpp> - ``` -- All engine-related code is implemented under the `crepe` namespace, user-facing APIs under `crepe::api` (the folder structure should also reflect this). + #include "api/Sprite.h" + #include "util/log.h" + #include "SDLContext.h" + ``` + </td><td> + ```cpp + #include <SDL2/SDL.h> + #include "SDLContext.h" + #include "util/log.h" + #include <iostream> + #include "api/Sprite.h" + ``` + </td></tr></table> - `using namespace` may not be used in header files, only in source files. + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> + example.h: ```cpp - // Good - // header.h namespace crepe { - void init(); + void foo(); } + ``` - // source.cpp - #include "header.h" - using namespace crepe; - void init() {} - - // Bad - // header.h + example.cpp: + ```cpp + #include "example.h" using namespace crepe; - void init(); + void foo() {} ``` + </td><td> -- Do not (indirectly) include private *dependency* headers in API header files, as these are no longer accessible when the engine is installed - + example.h: ```cpp - // Good - // api.h - namespace crepe::api { - void start(); + namespace crepe { + template <typename T> + T foo(); } + ``` - // Bad - // api.h - #include "private_dependency.h" - namespace crepe::api { - void start(); - } + example.hpp: + ```cpp + #include "example.h" + using namespace crepe; + template <typename T> + T foo(); ``` + </td></tr></table> - Getter and setter functions are appropriately prefixed with `get_` and `set_`. + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - class Car { + class Foo { public: - int get_speed() const; - void set_speed(int speed); + int get_speed() const; + void set_speed(int speed); private: - int speed; + int speed; }; - // Bad - class Car { + ``` + </td><td> + + ```cpp + class Foo { public: - int speed() const; - void speed(int speed); + int speed() const; + void set_speed(int speed); private: - int speed; + int speed; }; ``` + </td></tr></table> -- Doxygen commands are used with a backslash instead of an at-sign (i.e. `\brief` instead of `@brief`) +- A singleton's instance is always accessed using a getter function that + instantiates its own class as a static variable within the getter function + scope, instead of storing the instance as a member variable directly: + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - /// \brief This function adds two numbers - int add(int a, int b); - - // Bad - /// @brief This function adds two numbers - int add(int a, int b); + class Foo { + Foo & get_instance() { + static Foo instance; + return instance; + } + }; ``` - -- A singleton's instance is always accessed using a getter function that instantiates its own class as a static variable within the getter function scope, instead of storing the instance as a member variable directly: + </td><td> ```cpp - class Bad { - static Bad instance; - Bad & get_instance() { return instance; } - }; + Foo Foo::instance {}; - class Good { - Good & get_instance() { - static Good instance; - return instance; - } + class Foo { + static Foo instance; + Foo & get_instance() { return Foo::instance; } }; + ``` + </td></tr></table> -- Member variable default values should be directly defined in the class declaration instead of using the constructor. +- Member variable default values should be directly defined in the class/struct + declaration instead of using the constructor. + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - class Car { - private: - int speed = 0; + class Foo { + int speed = 0; }; - // Bad - class Car { - private: - int speed; - Car() : speed(0) {} - }; ``` - -- Header files declare either a single class or symbols within a single namespace. + </td><td> ```cpp - // Good - // car.h - namespace crepe { - class Car {}; - } - - // Bad - // car.h - namespace crepe { - class Car {}; - class Engine {}; - } + class Foo { + Foo() : speed(0) {} + int speed; + }; ``` - -- Use of the `auto` type is not allowed, with the following exceptions: - - When naming the item type in a range-based for loop - - When calling template factory methods that explicitly name the return type in the function call signature + </td></tr></table> + +- Use of the `auto` type is *not* allowed, with the following exceptions: + - When naming the item type in a range-based for loop: + + ```cpp + for (auto & item : foo()) { + // ... + } + ``` + - When calling template factory methods that explicitly name the return type + in the function call signature + ```cpp + auto ptr = make_unique<Foo>(); + ``` - When fetching a singleton instance - - ```cpp - // Good - for (auto item : items) {} - - auto instance = Singleton::get_instance(); - - // Bad - auto speed = car.get_speed(); - ``` + ```cpp + auto & mgr = crepe::api::Config::get_instance(); + ``` - Only use member initializer lists for non-trivial types. + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - class Car { + class Foo { public: - Car() : engine("V8") {} + Foo() : bar("baz") {} private: - std::string engine; + std::string bar; }; - // Bad - class Car { + ``` + </td><td> + + ```cpp + class Foo { public: - Car() : speed(0) {} + Foo() : bar(0) {} private: - int speed; + int bar; }; ``` + </td></tr></table> - C++-style structs should define default values for all non-trivial fields. + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - struct Car { - std::string model = "Unknown"; + struct Foo { + int bar; + std::string baz; }; - - // Bad - struct Car { - std::string model; - Car() : model("Unknown") {} + ``` + </td><td> + + ```cpp + struct Foo { + int bar = 0; + std::string baz; }; ``` + </td></tr></table> -- Declare incomplete classes instead of including the relevant header where possible (i.e. if you only need a reference or pointer type). +- Declare incomplete classes instead of including the relevant header where + possible (i.e. if you only need a reference or raw pointer). + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good - class Engine; - class Car { - Engine* engine; + class Bar; + class Foo { + Bar & bar; }; - // Bad - #include "engine.h" - class Car { - Engine* engine; + ``` + </td><td> + + ```cpp + #include "Bar.h" + class Foo { + Bar & bar; }; ``` + </td></tr></table> -- Template functions are only declared in a `.h` header, and defined in a matching `.hpp` header. +- Template functions are only *declared* in a `.h` header, and *defined* in a + matching `.hpp` header. + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> + add.h: ```cpp - // Good - // add.h template <typename T> T add(T a, T b); + + #include "add.hpp" + ``` - // add.hpp + add.hpp: + ```cpp #include "add.h" + template <typename T> T add(T a, T b) { - return a + b; + return a + b; } - - // Bad - // add.h + ``` + </td><td> + + add.h: + ```cpp template <typename T> T add(T a, T b) { - return a + b; + return a + b; } ``` + </td></tr></table> -- Where possible, end (initializer) lists with a trailing comma (e.g. with structs, enums) +- Where possible, end (initializer) lists with a trailing comma (e.g. with + structs, enums) + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp - // Good enum Color { - Red, - Green, - Blue, + Red, + Green, + Blue, }; - // Bad + ``` + </td><td> + + ```cpp enum Color { - Red, - Green, - Blue + Red, + Green, + Blue }; ``` + </td></tr></table> +- `#pragma` should be used instead of include guards + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> -## CMakeLists specific + ```cpp + #pragma once + + // ... + ``` + </td><td> + + ```cpp + #ifndef __INCLUDED_H + #define __INCLUDED_H + + // ... + + #endif + ``` + </td></tr></table> + +## CMakeLists-specific - Make sure list arguments (e.g. sources, libraries) given to commands (e.g. `target_sources`, `target_link_libraries`) are on separate lines. This makes resolving merge conflicts when multiple sources were added by different people to the same CMakeLists.txt easier. +# Structure + +- All engine-related code is implemented under the `crepe` namespace, + user-facing APIs under `crepe::api` (the folder structure should also reflect + this). +- Do not (indirectly) include private *dependency* headers in API header files, + as these are no longer accessible when the engine is installed +- Header files declare either a single class or symbols within a single + namespace. +- TODO: folder structure + # Documentation - All documentation is written in U.S. English +- Doxygen commands are used with a backslash instead of an at-sign. + <table><tr><th>Good</th><th>Bad</th></tr><tr><td> + + ```cpp + /** + * \brief do something + * + * \param bar Magic number + */ + void foo(int bar); + ``` + </td><td> + + ```cpp + /** + * @brief do something + * + * @param bar Magic number + */ + void foo(); + ``` + </td></tr></table> # Libraries |