# Contributing new code - Please do the following *before* sending a pull request: - Merge upstream code (if any) back into your own branch - Run formatters/linters # Git - Push as often as possible - Development is done on separate branches, these follow a pattern of `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
GoodBad
```cpp // crepe startup message std::string message = "Hello, world!"; ``` ```cpp // crêpe startup message std::string message = "こんにちは世界"; ```
- Class names are always singular
GoodBad
```cpp class Foo {}; ``` ```cpp class Cars {}; ```
- 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
GoodBad
```cpp int add(int a, int b) { // add numbers int out = a + b; return out; } ``` ```cpp int add(int a, int b) { int out = a + b; // add numbers return out; } ```
- 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 > [!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).
GoodBad
```cpp #include #include #include "api/Sprite.h" #include "util/log.h" #include "SDLContext.h" ``` ```cpp #include #include "SDLContext.h" #include "util/log.h" #include #include "api/Sprite.h" ```
- `using namespace` may not be used in header files, only in source files.
GoodBad
example.h: ```cpp namespace crepe { void foo(); } ``` example.cpp: ```cpp #include "example.h" using namespace crepe; void foo() {} ``` example.h: ```cpp namespace crepe { template T foo(); } ``` example.hpp: ```cpp #include "example.h" using namespace crepe; template T foo(); ```
- Getter and setter functions are appropriately prefixed with `get_` and `set_`.
GoodBad
```cpp class Foo { public: int get_speed() const; void set_speed(int speed); private: int speed; }; ``` ```cpp class Foo { public: int speed() const; void set_speed(int speed); private: int speed; }; ```
- 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:
GoodBad
```cpp class Foo { Foo & get_instance() { static Foo instance; return instance; } }; ``` ```cpp Foo Foo::instance {}; class Foo { static Foo instance; Foo & get_instance() { return Foo::instance; } }; ```
- Member variable default values should be directly defined in the class/struct declaration instead of using the constructor.
GoodBad
```cpp class Foo { int speed = 0; }; ``` ```cpp 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: ```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(); ``` - When fetching a singleton instance ```cpp auto & mgr = crepe::api::Config::get_instance(); ``` - Only use member initializer lists for non-trivial types.
GoodBad
```cpp class Foo { public: Foo() : bar("baz") {} private: std::string bar; }; ``` ```cpp class Foo { public: Foo() : bar(0) {} private: int bar; }; ```
- C++-style structs should define default values for all non-trivial fields.
GoodBad
```cpp struct Foo { int bar; std::string baz; }; ``` ```cpp struct Foo { int bar = 0; std::string baz; }; ```
- Declare incomplete classes instead of including the relevant header where possible (i.e. if you only need a reference or raw pointer).
GoodBad
```cpp class Bar; class Foo { Bar & bar; }; ``` ```cpp #include "Bar.h" class Foo { Bar & bar; }; ```
- Template functions are only *declared* in a `.h` header, and *defined* in a matching `.hpp` header.
GoodBad
add.h: ```cpp template T add(T a, T b); #include "add.hpp" ``` add.hpp: ```cpp #include "add.h" template T add(T a, T b) { return a + b; } ``` add.h: ```cpp template T add(T a, T b) { return a + b; } ```
- Where possible, end (initializer) lists with a trailing comma (e.g. with structs, enums)
GoodBad
```cpp enum Color { Red, Green, Blue, }; ``` ```cpp enum Color { Red, Green, Blue }; ```
- `#pragma` should be used instead of include guards
GoodBad
```cpp #pragma once // ... ``` ```cpp #ifndef __INCLUDED_H #define __INCLUDED_H // ... #endif ```
## 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.
GoodBad
```cpp /** * \brief do something * * \param bar Magic number */ void foo(int bar); ``` ```cpp /** * @brief do something * * @param bar Magic number */ void foo(); ```
# Libraries - External libraries should be included as Git submodules under the `lib/` subdirectory - When adding new submodules, please set the `shallow` option to `true` in the [.gitmodules](./.gitmodules) file