# 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
Good | Bad |
---|
```cpp
// crepe startup message
std::string message = "Hello, world!";
```
|
```cpp
// crêpe startup message
std::string message = "こんにちは世界";
```
|
- Class names are always singular
Good | Bad |
---|
```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
Good | Bad |
---|
```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).
Good | Bad |
---|
```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.
Good | Bad |
---|
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_`.
Good | Bad |
---|
```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:
Good | Bad |
---|
```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.
Good | Bad |
---|
```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.
Good | Bad |
---|
```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.
Good | Bad |
---|
```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).
Good | Bad |
---|
```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.
Good | Bad |
---|
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)
Good | Bad |
---|
```cpp
enum Color {
Red,
Green,
Blue,
};
```
|
```cpp
enum Color {
Red,
Green,
Blue
};
```
|
- `#pragma` should be used instead of include guards
Good | Bad |
---|
```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.
Good | Bad |
---|
```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