RAMSES Documentation  27.0.130
Information for RAMSES users and developers
Code Style Guide for RAMSES modules

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:
    class C_foobar;
  • Correct:
    class FooBar;
  • 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:
    #define MY_SPECIAL_MACRO
  • 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 // __BAD_EXAMPLE_H__
  • 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
    {
    [ramses code]
    } // 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:
    namespace ramses
    {
    [ramses code]
    } // namespace ramses
  • 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 Get_Value();
    };
    @ UInt32
    one component of type uint32_t per data element
  • Correct:
    class MyClass
    {
    UInt32 getValue() const;
    };
  • Style Checker: N/A

Structs should have only public members, which don't have a m_ prefix.

  • Rationale: Readability, Consistency, Simplicity
  • Wrong:
    struct ThisLooksLikeAClass
    {
    UInt32 doComplicatedLogic();
    private:
    UInt32 m_foo;
    };
  • Correct:
    struct MyStruct
    {
    UInt32 foo;
    UInt32 bar;
    };
  • Style Checker: N/A

Member variables start with prefix "m_", followed by camel case name starting with small letter.

  • Rationale: Readability, Consistency
  • Wrong:
    class MyClass
    {
    UInt32 myCoolVar;
    };
  • Correct:
    class MyClass
    {
    UInt32 m_myCoolVar;
    };
  • 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:
    // TODO some text
  • Correct:
    // TODO(Timo) some text
  • 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):
    void func(Int32 /*value*/)
    {
    }
  • 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;
    // or in constructor
    };
  • 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:
    typedef int Index;
  • Correct:
    using Index = int;
  • 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

  • Rationale: Performance

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