= Code Conventions = [[PageOutline(2-3)]] ---- == General Principles == Code must be written in C++11. All code must compile under -Wall/-W4 compiler flag. Code must compile under the most recent version of GCC and most recent version of MSVC. == Definitions == * member functions are functions that are associated with classes. * data members are variables that are part of classes. == Source Files == === General Conventions === * never use any white spaces or non-ASCII characters in filenames. Also, the following characters are not allowed: & ^ + - @ $ % * ( ) | \ / [ ] { } < > ? ; : , " * for source code files, every filename should reflect the name of the class defined or implemented in it. * source files names should be all lowercase. * if a code standard rule is broken it has to be explicitly documented. * the files must not contain source code that is not in usable ( use sandbox for that ) * code must never be copy/pasted (literally doubled). If two functionalities have the common parts, they must reuse single code portion -- do not duplicate what was done. If some functionality is already implemented, it must be used. If the interface or the implementation of the functionality does not satisfy a developer he should talk about the enhancements, and must not create yet another version. * creating own versions of algorithms already present in STL is only allowed if a serious reason exists. * header files use .hh extension, source files use .cc === Header files === * write comments! Header file comments are written for the user of the module. They are adequate if the test cases for the module can be drawn up on the basis of them. Class and function comments (including parameters and return values) always go in the header file. This means all comments that are meant to be handled by the automatic class documentation generator program Doxygen. * add #ifndef NV_(MODULE_)CLASS_NAME_HH header guard statements in the beginning of a header to protect it against multiple includes from other files. * write the implementation of a single class in a single file (exceptions can be made sometimes for header-only classes). * use the same names for function parameters as you have used in the header file. === Source files === * Write comments! Implementation file comments are written for the maintainer of the module. They are adequate if they meet the following requirements: * They describe class level implementation and clarify all the non-trivial issues. * Member function comments cover explanations for all the non-trivial implementation code. Other functions must also contain parameter and return value comments. * Write the implementation of one class in one file. * Use the same names for function parameters as you have used in the header file. ---- == Directory structure == Each component must be placed in separate directory. Includes and source files are placed in separate directory trees. {{{ \ - common files (readme, install) \doc – documentation (generated by Doxygen) \nv – include files \nv\gl – gl module include files \nv\... \src – source files \src\gl – gl module \src\... \ref – reference material \bin - compiled binaries \tests - test sources \tests\gl_test - gl_test project }}} ---- == Language == === General conventions === * use namespaces * don't use global variables * use constants instead of defines where applicable * pass function parameters as constant references where possible === Naming prefixes === Getter and setter methods should start with "get" and "set", the only exception being Boolean getters which can be prefixed with "is". Conversion functions can start with "as". === Class names === * use an underscore ("_") to separate words * all letters are lowercase (STL/Boost style) === Functions === * parameter names must be mentioned in both declaration and definition. If some parameter is not referenced inside the function, its name must be commented out in the definition, to avoid compilation warnings. * use a const attribute where appropriate to indicate that a function does not change the state of an object or a parameter which is read-only. * each variable declaration should be in a separate line. * use an underscore ("_") to separate words. Do not start a function name with an underscore. === Member functions === * follow the rules above * keep const-correctness! If a member doesn't change it's object, mark it as const === Member data === * member data should be at least protected if not private. Provide accessors for data that needs to be public instead of making it public ( this is the only header inlined code that is acceptable as long as it consists of a single line ). === Pointer and references === * when declaring or defining pointers or references, place a specifier (* or &) next to typename, not next to the variable. === Macros and other #defines === * avoid macros in release code. Exception: Debug and test code often requires precompiler macros. Debug flags must be analyzed and kept only if they are useful and well commented. * capitalize all the letters of macros. * use an underscore ("_") to separate words. Do not start a macro name with an underscore. * avoid #defines. Use real constants instead. * exceptions include conditional compilation based on architecture/compiler, and the log/debug macros === Constants === * constant names should be upper-case. * constants should be defined in source files. * each number ( except trivial ones like 0 and 1 ) should be a constant. === Enumerated types === * enums and their members must have relevant, meaningful and unambiguous names. * enumerations names should be upper-case and white spaces should be replaced by underscores. === Global variables === ... are not. === Control structures === * every switch statement must have a default: clause, at least for detecting unexpected switch expressions. Use logging code or some other handler to catch unexpected switch expressions. Case branches without a break or return statement should be avoided. If one has to be used, the flow through must be explicitly indicated by a comment. * always use compound statement braces ({}) in all the control flow statements — if() - else, while(), do/while() and for() — even if there were only a single statement or an empty block. Exceptions for this rule may be made for templated code. '''Example:''' {{{ #!cpp if ( my_variable ) { do_something(); } }}} * control flow statement goto must not be used === Spacing === * all C++ statements within a block of code should be indented exactly one tab deeper than the enclosing block. * tabs are used instead of spaces. * primary operators should be written with no spaces around them. * unary operators should be written with no spaces between them and their operands. Exceptions: new and delete. * all other operators should be written with one space on each side of the operator. '''Example:''' {{{ #!cpp if ( pointer->function() > MAX_VALUE ) { counter++; variable = table[a] + offset; } }}} === Placement of braces and parentheses === * the placement of the "{" and "}" braces must be at the same level of indentation as the control statement. A "{" or "}" is the only character in a given line. Note, that some editor tools can be configured to indent the code according to this rule. * prefer a maximum of 120 characters per line. Longer lines are hard to read and some editors cannot even handle them properly. * parentheses should always have a space on the inside. * there must be no space between a function or macro name and its parenthesized argument(s). * there must be a single space between a keyword (for, if, etc.) and its parenthesized argument(s). * parentheses should always be used where there is potential ambiguity. ---- == Commenting conventions == === General commenting conventions === * Doxygen guidelines can be read on the DoxygenConventions page. * comments are to be written in English. * comments must be kept up to date. * comments must be inserted into the code as it is being developed. They must appear with the relevant code. * avoid commenting a matter in many places. * avoid repeating code in comments. * in general, comments should explain why something has been done rather than telling what has been done. However, non-obvious control and data structures should be explained, as well as the programmer's assumptions of the program's state at a certain point, if it's non-obvious. * use C++ style comments (// Comment) for internal documentation and use C style block comments (/* Comment */) for doxygen documentation. Exception - private members can be commented using //< === Special comments === All special comments need to have a description of what they relate to. The proper format is //KEYWORD. The following are widely recognized: * '''// TODO:''' there is work to be done following this part. Describe what needs to be done. * '''// REFACTOR:''' following code needs refactoring. Describe what needs refactoring, and optimally a possible solution. * '''// HACK:''' following code was hacked up quickly, needs refactoring. Describe why a more elegant solution wasn’t used. * '''// SPITBALL:''' following code was hacked up quickly, refactor ASAP, no comment provided. * '''// TRICKY:''' following code is not obvious, or depends on some non-obvious assumptions, do not touch under death penalty. Possibly try to provide an explanation. * '''// DONOTREMOVE:''' this code may not be used but should not be removed. Description of why it should not be removed is optional. * '''// WARNING:''' following code makes some non-obvious assumptions. Document them. ---- == Identifier Names == * all variable and identifiers are all lowercase letter. * macros are always uppercase. * global variables don't exist. * stl_style everywhere. In case of abbrevations all letters are lowercase too (xml_node) * long identifier names almost always (float_data_vector_iterator instead of f_data_viter) * when parameter name would conflict with class data member, prepend parameter with "a" * get/set for accessors, no data members should be public * is/has is acceptable for boolean observers ---- == Control Structures == The control structure indenting is as follows: {{{ #!cpp if ( expression ) { statements; } else { statements; } }}} {{{ #!cpp for ( expression; expression; expression ) { statements; } }}} {{{ #!cpp do { statements; } while ( expression ); }}} {{{ #!cpp while ( expression ) { statements; } }}} {{{ #!cpp switch ( expression ) { case constant: statements; break; default: statements; break; } }}} {{{ #!cpp switch ( expression ) { case constant: single_statement; break; default: single_statement_or_none; break; } // if return is used, break is not needed }}}