Goals
- Good readable code
- Simplify debugging
- Enforcing correctness for obvious code issues
- Consistent code style through all of the RAMSES modules
- Have fully automated code style checking for local and build server usage
Automated Testing
RAMSES ships with a python-based code style checker (in <ramses_root>/scripts/code_style_checker). You should not use it directly, but trigger the target "CHECK_CODE_STYLE" generated by CMake.
Environment | Usage
Visual Studio | right click on "CHECK_CODE_STYLE" (in folder "CMakePredefinedTargets") and choose "Build" Makefiles | make CHECK_CODE_STYLE Ninja | ninja-build CHECK_CODE_STYLE
On invocation, the style checker will issue two warnings per style issue:
- Visual Studio/MSBuild format
- GCC format
This allows various IDEs to pick up the warnings depending on their preferred flavor.
(Unordered) Rules
Each file must contain an accepted license header.
- Rationale: Make sure that proprietary license cannot be missed.
- Wrong:
No source code license in file.
- Correct:
Source file starts with license
- Style Checker: warning
One Class definition per file, filename matches class name.
- Rationale: Readability, Consistency
Types have camel-case name, no prefixes (CClass, SStruct)
- Rationale: Readability, Consistency
- Wrong:
- Correct:
- Style Checker: N/A
Use "I" Prefix for abstract interfaces.
- Rationale: Readability, Consistency
- Correct:
class INode
{
public:
virtual void func1() = 0;
virtual void func2() = 0;
}
- Style Checker: N/A
If possible use enum class over plain enum for type safety. If plain enum is used, prefix with "E" and each value has is prefixed with a full enum type name (exactly).
- Rationale: Readability, Consistency
- Correct:
enum ENodeType
{
ENodeType_Bar,
ENodeType_Foo
};
- Style Checker: warning
When using enum classes, don't use "E" prefix for the type name; value names must NOT be prefixed by type name.
- Rationale: Readability, Consistency
- Correct:
enum class NodeType
{
Foo,
Bar
};
- Style Checker: N/A
Use upper case with underscore for macros.
- Rationale: Readability, Consistency
- Correct:
- Style Checker: N/A
Header files must include header guards with format RAMSES_[PREFIX_]FILENAME_H.
- Rationale: Correctness
- Wrong:
in file BadExample.h
#ifndef __BAD_EXAMPLE_H__
#define __BAD_EXAMPLE_H__
[...]
#endif
- Correct:
in file GoodExample.h
#ifndef RAMSES_GOODEXAMPLE_H
#define RAMSES_GOODEXAMPLE_H
[...]
#endif
- Style Checker: warning
Never use tabs, indent with 4 spaces.
- Rationale: Readability, Consistency
- Style Checker: warning
Static member methods use camel case naming with capital first letter.
- Rationale: Readability, Consistency
- Wrong:
class UtilClass
{
public:
static void doAwesomeStuff();
}
- Correct:
class UtilClass
{
public:
static void DoAwesomeStuff();
}
- Style Checker: N/A
Static const variables use camel case naming with capital first letter.
- Rationale: Readability, Consistency
- Wrong:
class Constants
{
public:
static const int some_var = 0;
}
- Correct:
class Constants
{
public:
static const int SomeVar = 0;
}
- Style Checker: N/A
All non public API RAMSES code lives in ramses_internal namespace.
- Rationale: Correctness, Consistency
- Correct:
namespace ramses_internal
{
}
The RAMSES namespace contains all client side objects and functions used to implement RAMSES applicat...
Definition: AnimatedProperty.h:15
- Style Checker: N/A
RAMSES API code lives in ramses namespace.
- Rationale: Correctness, Consistency
- Correct:
- Style Checker: N/A
All files end with an empty line.
- Rationale: Correctness, Consistency
- Style Checker: warning
Member functions use camel case, starting with small first letter. Prefer a name starting with a verb.
- Rationale: Readability, Consistency
- Wrong:
class MyClass
{
};
@ UInt32
one component of type uint32_t per data element
- Correct:
- Style Checker: N/A
Structs should have only public members, which don't have a m_ prefix.
- Rationale: Readability, Consistency, Simplicity
- Wrong:
struct ThisLooksLikeAClass
{
private:
};
- Correct:
- Style Checker: N/A
Member variables start with prefix "m_", followed by camel case name starting with small letter.
- Rationale: Readability, Consistency
- Wrong:
- Correct:
- Style Checker: N/A
Always use const wherever possible.
Mutable is allowed in specific cases (caching, locks) but must keep 'logical' constness - changes may not be visible to the outside.
- Rationale: Correctness, Debugging, Compiler friendly
- Wrong:
class MyClass
{
Bool isValid();
String process(String& str);
String& getCurrentMsg();
};
- Correct:
class MyClass
{
Bool isValid() const;
String process(const String& str) const;
const String& getCurrentMsg() const;
};
- Style Checker: N/A
Comments have form "// TODO(<creator_name>) text".
- Rationale: Developers should take responsibility for TODOs in code and be able to answer questions on the issue.
- Wrong:
- Correct:
- Style Checker: N/A
Avoid unused variables where possible, mark with macro UNUSED(x) when needed.
- Rationale: Correctness
- Wrong:
void func(Int32 value)
{
}
- Correct (use for permanent solutions, comment out or delete):
- Correct (only temporarily or technical necessity)
void func(Int32 value)
{
UNUSED(value);
}
- Style Checker: N/A (is detected by compiler)
Remove any spaces at the of lines.
- Rationale: Consistency, Correctness
- Style Checker: warning
Only do one definition per line.
- Rationale: Debugging
- Wrong:
Int32* a = NULL, b, c = 5;
- Correct:
Int32* a = NULL;
Int32 b = 0;
Int32 c = 5;
- Style Checker: warning
Only one statement per line.
- Rationale: Debugging
- Wrong:
case 4: doSomething(); a += 5; checkForFoo();
- Correct:
case 4:
doSomething();
a += 5;
checkForBlub();
break;
- Style Checker: Disabled
Curly braces on dedicated lines.
- Rationale: Readability, Consistency
- Wrong:
while (running) {
[...]
}
- Correct:
while (running)
{
[...]
}
- Style Checker: warning
Always use virtual and override, final keywords where appropriate.
- Rationale: Correctness, Consistency
- Style Checker: N/A
Avoid empty lines at start and end of code blocks.
- Rationale: Readability
- Wrong:
class MyClass
{
MyClass();
};
- Correct:
class MyClass
{
MyClass();
};
- Style Checker: N/A
Don't add extra whitespaces in argument lists, just one space after a comma.
- Rationale: Readability, Consistency
- Wrong:
void func( Int32 arg1 , Bool arg2 );
- Correct:
void func(Int32 arg1, Bool arg2);
- Style Checker: N/A
Initialize primitive types, especially pointers. Prefer init in class declaration.
- Rationale: Consistency, Safety
- Wrong:
Foo* myFoo;
int i;
class myClass
{
Foo* m_foo;
int m_val;
};
- Correct:
Foo* myFoo = nullptr;
int i = 0;
class myClass
{
Foo* m_foo = nullptr;
int m_val = 0;
};
- Style Checker: N/A
Avoid raw pointers.
- Rationale: Safety
- Wrong:
int *arr = new int[size];
int arrStatic[3];
Foo *foo = new Foo;
delete foo;
- Correct:
std::vector<int> arr(size);
std::array<int, 3> arrStatic{ x, y, z };
std::unique_ptr<Foo> foo{ new Foo };
- Style Checker: N/A
Class initialization list - one member variable per line
- Rationale: Readability, Consistency, Debugging
- Wrong:
MyClass::MyClass() : BaseClass(param, param2), m_bmw(1), m_merc(2), m_audi(3) {}
- Correct:
MyClass::MyClass()
: BaseClass(param, param2)
, m_bmw(1)
, m_merc(2)
, m_audi(3)
{
}
- Style Checker: N/A
Avoid using typedef, prefer using "using" instead
- Rationale: Readability
- Wrong:
- Correct:
- Style Checker: N/A
Don't use "using namespace MyNamespace;" in global namespace and in headers
- Rationale: Readability, Consistency
- Style Checker: N/A
Prefer the rule of 5 for constructors and assignment operators
- Rationale: Readability, Consistency
- Style Checker: N/A
Constructors have to be explicit when one argument only
- Rationale: Robustness
- Wrong:
class MyClass
{
MyClass();
MyClass(int num);
};
- Correct:
class MyClass
{
MyClass();
explicit MyClass(int num);
};
- Style Checker: N/A
Don't use exceptions, if you have to call exception-throwing functions make sure they don't throw exceptions in your code for your inputs.
- Rationale: Compatibility
- Wrong:
try
{
helperMap.at(key) = 5;
}
catch(...)
[...]
- Correct:
auto it = helperMap.find(key);
if (it != helperMap.end())
{
*it = 5;
}
- Style Checker: N/A
Types which are only used in one translation unit (.cpp file) must be put in anonymous namespace
- Rationale: Robustness
- Style Checker: N/A
Functions which are only used in one translation unit (.cpp file) must be put in anonymous
namespace or declared static
- Rationale: Robustness
- Style Checker: N/A
Anonymous namespace must not be used in header files
- Rationale: Performance, Correctness
- Style Checker: N/A
Class definition - public, protected, private in that order.
Generally: Types first, Methods, followed by member variables.
- Rationale: Readability, Consistency
- Wrong:
class MyClass()
{
public:
Int32 m_val;
private:
void compute();
public:
virtual void base0Method();
};
- Correct:
class MyClass()
{
public:
virtual void base0Method();
virtual void base1Method();
protected:
void protMethod();
Int32 m_val;
private:
void compute();
Data m_data;
};
- Style Checker: N/A
Good practices
Use reserve() for all containers, when possible to estimate element count
Use STL algorithms when applicable (e.g. find_if instead of range-based for)
- Rationale: Performance, Stability
Use modern pointer conventions - avoid shared pointers, use unique_ptr instead of new/delete etc.
- Rationale: Performance, Stability