This document describes the style of code in AnKi 3D Engine. The code is written primarily in C++ with some HLSL and python as well.
- Comments in C++ & HLSL
- Comments in python
- Naming conventions in C++ & HLSL
- Naming conventions in python
- Naming conventions for files and directories
- C++ rules
- HLSL rules
- Code formatting in C++ & HLSL
- Code formatting in python
All comments are C++ like (double slash):
// Some comment
And for doxygen comments in C++ only:
/// @brief blah blah
/// @param blah blah
Whatever the PEP 8 guide proposes.
Variables, functions and methods are lower camelCase.
functionDoSomething(someVariableA, someVariableB);
All types are PascalCase and that includes classes, structs, typedefs and enums.
enum MyEnum {...};
class MyClass {...};
using MyType = int;
All constexpr expressions start with a k
and that includes enumerants.
constexpr int kMyConstant = ...;
enum MyEnum
{
kEnumerantA
};
All macros and defines should be SCREAMING_SNAKE_CASE and they should have an ANKI_
prefix.
#define ANKI_ASSERT(expr)
#define ANKI_MAX_SOMETHING ...
All template typedefs should start with T
. The rule doesn't apply in constant template arguments.
template<typename TSomething, typename TOther, U32 kSomeConst>
All function and method names should form a sentence with at least one verb.
doSomething(...);
getSomething();
calculateSomething(...);
Using some hungarian notations.
- Constants start with
k
as mentioned above. - All member variables have the
m_
prefix. That applies to classes and structs. - All global variables have the
g_
prefix.
In HLSL there are more exceptions:
- All groupshared variables use the
s_
prefix.
Variables that act as a measure for quantity should have the count
suffix. Not num
or numberOf
or similar.
int appleCount = ...; // YES
int appleNum = ...; // NO
int numApples = ...; // NO
Whatever the PEP 8 guide proposes.
Filenames and directories should be PascalCase. The extensions of the files are lowercase.
Source/ThreadHive.h
Shaders/MyShaderProgram.ankiprog
Some/Path/Script.py
Header files that contain inline methods/functions (for template classes for example) should have the .inl.h
extension.
Header files that contain definitions (are included multiple types with different permutations) should have the .def.h
extension.
Always use strongly typed enums. If you need to relax the rules use the ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS
macro.
enum class MyEnum : U32 {...};
ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MyEnum);
Never use typedef
to define types. Use using
instead.
using U32 = uint32_t;
using Func = void(*)(int, int);
Never use C-style casting. Use static_cast, reinterpret_cast or const_cast for most cases and constructor-like cast for fudmental types.
Derived* d = static_cast<Derived*>(base);
uint i = uint(1.1f); // uint is fudmental type
Always use constexpr
when applicable. Never use defines for constants.
constexpr uint kSomeConst = ...; // YES!!
#define SOME_CONST ... // NO
Always use class
and never use struct
. Since it's difficult to come up with rules on when to use struct over class, always use class and be done with it.
class MyTrivialType
{
public:
int m_x;
int m_y;
};
Avoid using auto
. It's only allowed in some templates and in iterators. auto makes reviewing code difficult.
auto i = 10; // NO
auto it = list.getBegin(); // ... FINE
Includes should always have the full file path. This avoids issues with files of similar name. Also, non-AnKi includes follow AnKi includes.
#include <AnKi/Util/Thread.h>
#include <AnKi/Util/WeakArray.h>
#include <AnKi/Util/Allocator.h>
#include <cstdio>
Never use public nested classes. Only private nested classes are allowed. Nested classes cannot be forward declared. Nested typedefs are fine.
class MyClass
{
public:
// NO!!!!!!!!!!!
class Nested {...};
// OK
using SomeTypedef = U32;
private:
// OK, it's private
class Nested {...};
// Also OK, it's private
class
{
...
} m_myUnamedThing;
};
Try to use explicit
in constructors for extra safety. Don't use explicit on copy constructors.
AnKi uses const correctness throughout and that's mandatory. Always use const
. The only place where you don't have to is for function and method parameters.
uint doSomething(uint noNeedForConst)
{
const uint bla = noNeedForConst + 10;
return blah;
}
Access types in a class have a specified order. First public
then protected
and last private
. There are some exceptions where this rule has to break.
class MyClass
{
public:
...
protected:
...
private:
...
};
Always use AnKi's fudmental types (U32, I32, F32, Bool etc etc). For integers and if you don't care about the size of the integer you can use the type U
for unsinged or I
for signed. Both of them are at least 32bit.
for(U32 i = 0; i < 10; ++i) {...}
U32 i = ...;
If you have to overload the operator Bool always use explicit operator Bool
operator overloading. Omitting the explicit
may lead to bugs.
explicit operator Bool() const {...}
The use of references and pointers is govern by some rules. Always use references except when you transfer or share ownership. Pointers are also allowed for optional data that can be nullptr.
// ptr is a pointer so you CAN NOT destroy after a call to doSomething is done
// ref is a reference so you CAN destroy after a call to doSomething is done
void Foo::doSomething(TypeA* ptr, TypeB& ref)
{
// Store the ptr somewhere
m_someMember = ptr;
// Won't store the ref
ref += ...;
}
Always use nullptr
and never NULL.
void* ptr = nullptr;
Never use C style arrays. Use the Array<>
template instead.
Array<MyType, 10> myArray; // YES
MyType myArray[10]; // NO
Don't use STL. AnKi has a replacement for most STL templates. There are some exceptions though.
- Can use
type_traights
. - Some from
utility
eg std::move. - Some from
algorithm
eg std::sort.
Always try to comment parts of the source code. Self documenting code is never enough.
void someFunction(...)
{
// Now do X
...
// Now do Y
...
}
Always use override
or final
on virtual methods and try to use final
on classes when applicable.
class Foo final
{
public:
void myVirtual(...) override {...}
};
Always use curly braces on single line expressions.
// NO!!!!!!!!!!!
if(something) doSomething();
// YES!!!!!!!!!!!!!!
if(something)
{
doSomething();
}
Always place the condition of a conditional ternary operator inside parenthesis.
a = b ? 1 : 0; // NO
a = (b) ? 1 : 0; // YES
Same rules as in C++ (when applicable) with one exception: You should use struct
instead of class
for user defined types.
clang-format deals with code formatting. To format all the C++ and HLSL files in the source tree type the following in a terminal:
$ cd /path/to/anki
$ python ./Tools/FormatSource.py
Whatever the PEP 8 guide proposes.