Skip to content
Petr Ohlídal edited this page Oct 22, 2019 · 3 revisions

Discuss here: https://github.com/RigsOfRods/rigs-of-rods/issues/839

Guidelines

  • Variable style: some_variable.
  • Function styleSomeFunction() (CamelCase without underscores). Functions starting with 'Set/Get/Has/Was/Is' are getters/setters - keep them simple.
  • class or struct style: CamelCase. typedef struct is forbidden (meaningless in C++).
  • enum style name is CamelCase, enum members are UPPERCASE_WITH_UNDERSCORES. typedef enum is forbidden (meaningless in C++).
  • using directives are forbidden in headers and generally discouraged. Use explict namespace qualifiers.
  • inline is forbidden except for global functions defined in header files (for sanity - member functions in headers are implicitly inline).
  • C++ standard RTTI is forbidden. If you really need it (we're not a library, why use complex class hierarchies internally?), create a custom one like LLVM style RTTI
  • Singleton pattern is forbidden. We're not making a library. Use plain objects in static memory.
  • Memory management rule#1: If you know the object/data size, use static or stack memory. Don't allocate dynamically without a good reason.
  • Memory management rule#2: If rule#1 cannot apply, employ the RAII pattern: use a std::unique_ptr to manage the memory. Only use std::shared_ptr if there is actual shared ownership!
  • When calling class methods, always use explicit this->, to distinguish methods from global functions.
  • Only do bare minimum of work in constructors and destructors. For complex inits, use factory functions.
  • Exception specifications (i.e. 'throws()') are forbidden. Read http://www.gotw.ca/publications/mill22.htm
  • Use 4 spaces for both indentation and alignment. Tabs are forbidden.
  • For pointers, only nullptr is allowed as empty value - never use 0 or NULL
  • Always use {} with if() and loops, to avoid bugs like this.
  • Name bool variables using short yes/no question, for example m_is_initialized instead of m_initialized.
  • Properties are obfuscated getter/setter functions, don't mimick them in C++.
  • use Doxygen tags /// and //!< to document the sources.

The template

Header:


/*                                                   //STYLE: License block
    This source file is part of Rigs of Rods
    Copyright 2005-2012 Pierre-Michel Ricordel
    Copyright 2007-2012 Thomas Fischer
    Copyright 2013-2016 Petr Ohlidal
    
    For more information, see http://www.rigsofrods.com/
    
    Rigs of Rods is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 3, as
    published by the Free Software Foundation.
    
    Rigs of Rods is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with Rigs of Rods.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
    @file   CodingStyleTemplate.h
    @brief  Wiki coding style template
    @author CrazyTrucker
    @date   05/2014
*/
                                             //STYLE: blank line!
#pragma once                                         //STYLE: header guard (we don't use header guard macros anymore)
                                                     //STYLE: blank line!
#include "RoRPrerequisites.h"                        //STYLE: RoR includes.
#include "BeamData.h"                                //    Try minimizing the dependencies between headers
#include "Flexable.h"                                //    Take advantage of forward declarations
#include "MaterialFunctionMapper.h"
                                                     //STYLE: blank line!
#include <OgreVector3.h>                             //STYLE: External includes
#include <OgreQuaternion.h>                          //    Again, try minimizing the dependencies between headers
#include <OgreHardwareVertexBuffer.h>                //    Including individual OGRE headers is preferred to including Ogre.h
#include <OgreMesh.h>
                                                     //STYLE: blank line!

namespace CodingTemplate                             //STYLE: Namespace
{                                                    //    NOTE: No indentation in namespace!

/// Brief description (must be ended with dot).
/// Detailed description.
struct CodingStyleDemoStruct
{                                                   //STYLE: { on new line.
    CodingStyleDemoStruct():                        //STYLE: Initializing constructor.
        struct_member_variable(0),
        another_member_variable(0.f)
    {}
                                                    //STYLE: blank line!
    int   struct_member_variable; //!< Description  //STYLE: variables and documentation. Mind the alignment.
    float another_member_variable; //!< Description
};


/// Brief description (must be ended with dot).       //STYLE: Class, inheritance
/// Detailed description.                             //    **REMEMBER!** Public inheritance means **IS-A!**
class CodingStyleDemoClass: public BaseDemoClass      //    "class B: public A" means "B is also A" !!
{
                                                    //STYLE: blank line before member struct!
    /// Just for little cleaner code...
    struct MemberStructure                          //STYLE: member struct
    {
        SubStructure(int stuff)                     //STYLE: Parametrized constructor
            stuff(stuff)
        {}

        int stuff;
    };
                                                    //STYLE: blank line!
public:  
                                                    //STYLE: blank line!
    CodingStyleDemoClass():
        m_private_member_variable(0),
        m_another_private_variable(0.f),
        m_example_pointer(nullptr),                 //STYLE: use 'nullptr' keyword for NULL pointers
        m_example_calculator(nullptr)
    {}
                                                    //STYLE: blank line!
    enum PossibleOptions                            //STYLE: enum
    {
        OPTION_BEGIN                                //STYLE: special option
        OPTION_FOO //!< Description                 //STYLE: all options have equal prefix
        OPTION_BAR //!< Description
        OPTION_BAZ //!< Description
        OPTION_END                                  //STYLE: special option
        OPTION_INVALID = 0xFFFFFFFF                 //STYLE: special option and value
    };

    static const unsigned int DEPOT_SERVICE       = BITMASK(1); //STYLE: bit flags
    static const unsigned int DEPOT_MASS_SEND     = BITMASK(2); //    Use BITMASK() from RoRPrerequisites.h
    static const unsigned int DEPOT_DONT_CANCEL   = BITMASK(3); //    Do NOT use enums for bitflags
    static const unsigned int DEPOT_LOCATE_HANGAR = BITMASK(4); //      because it blocks using | operator
                                                    //STYLE: blank line!

                                                    //STYLE: blank line!
public:
                                                    //STYLE: blank line!
    char public_member;                             //STYLE: public member
                                                    //STYLE: blank line!
    int GetPrivateMemberVariable()                  //STYLE: function (getter)
    {
        return m_private_member_variable;           //STYLE: Don't use {{this->}} to access members
    }

    /// Returns highest number
    int FunctionWithManyArguments(                  //STYLE: Functions with too long argument list
        int first_argument,                         //    ... will be split to multiple lines.
        int second_argument,
        int third_argument,
        int fourth_argument,                        //    NOTE: Define your functions in .cpp files
        int fifth_argument,                         //    ... to decrease compile dependencies!
        int last_argument                           //    One-line getters (as above) are fine though.
    );
    
    int  GetMemberValue() { return m_private_member_variable; }  //STYLE: Getter function -> `Get` in name
                                                    
    int  ComputeHighestNumberUsingBranches(int a, int b, int c); //STYLE: Not a getter -> no `Get` in name
    int  ComputeHighestNumberUsingConditionals(int a, int b, int c, int d, int e, int f);
    int  AddNumbers(int a, int b);
    bool IsPointerNotNull();                        //STYLE: A `bool` method is named as yes/no question.
                                                    //STYLE: blank line!
private:
                                                    //STYLE: privates are prefixed m_. Mind the alignment.
    int                m_private_member_variable; 
    float              m_another_private_variable;
    PointedClass*      m_example_pointer;           //STYLE: pointer member ~ * at datatype
    ExampleCalculator* m_example_calculator;    

};

} // namespace CodingTemplate                       //STYLE: End of namespace.

Source:

                                                     //STYLE: blank line!
#include "CodingTemplate.hpp"                        //STYLE: The associated header on first line.
                                                     //STYLE: blank line!
#include "AnotherHeader.hpp"                         //STYLE: RoR includes.
                                                     //STYLE: blank line!
#include "OgreMaterialManager.h"                     //STYLE: External includes

namespace CodingTemplate                             //STYLE: Namespace
{                                                    //    NOTE: No indentation in namespace!

int CodingStyleDemoClass::FunctionWithManyArguments( //STYLE: Functions with too long argument list
    int first_argument,                              //    ... will be split to multiple lines.
    int second_argument,
    int third_argument,
    int fourth_argument,
    int fifth_argument,
    int last_argument
)
{
    int a = this->GetHighestNumberUsingBranches(     // STYLE: using explicit this->
        first_argument,                              //    to distinguis member functions
        second_argument,                             //    and global functions
        third_argument
    );

    int b = this->GetHighestNumberUsingBranches(     // STYLE: Explicit this->
        fourth_argument,
        fifth_argument,
        last_argument
    );

    return (a > b) ? a : b;
}

int CodingStyleDemoClass:::ComputeHighestNumberUsingBranches(int a, int b, int c)
{
    if (a < b)                                       //STYLE: if() statements
    {                                                //    {} must always be present
        if (b < c)                                   //    {} must always be on new line
        {                                            //    NOTE: Always consider using conditionals (below)
            return c;
        }
        else
        {
            return b;
        }
    }
    else
    {
        if (a < c)
        {
            return c;
        }
        else
        {
            return a;
        }
    }
}

int CodingStyleDemoClass::ComputeHighestNumberUsingConditionals(int a, int b, int c, int d, int e, int f)
{
    int highest = (a > b) ? a : b;                   //STYLE: conditional assignments
    highest = (highest > c) ? highest : c;           //    Use them! :)
    highest = (highest > d) ? highest : d;
    highest = (highest > e) ? highest : e;
    return (highest > f) ? highest : f;
}

bool CodingStyleDemoClass::IsPointerNotNull()
{                                                    //STYLE: NULL pointer test
    return (m_example_calculator != nullptr)         //    Using {{if (pointer)}} conditions is forbidden
{                                                    //    ... only bools can be tested this way.

int CodingStyleDemoClass::AddNumbers(int a, int b)
{
    assert (m_example_calculator != nullptr);        //STYLE: NULL pointer debug test

    return m_example_calculator->Add(a, b);          //STYLE: Don't use {{this->}} to access members
}

} // namespace CodingTemplate                        //STYLE: End of namespace.