Coding Guidelines

March 30, 2016 ยท View on GitHub

Back to: README > developers guide >

Coding Guidelines

  • Indenting should use 3 spaces (not tabs!).
  • Brackets should start on the opening statement (if, for,...) except for function blocks.
  • Labels, classes, cases should all be indented.
  • Spaces should be used inside parenthesis (e.g., ( 5 ) not (5) )
  • If in doubt you can use astyle (http://astyle.sourceforge.net). Check script/astyle-nanox.sh script.
  • All files (sources, headers, Makefile.am) MUST have the proper license header (see script/preamble.txt). You can use headache to help you.
  • Type names should (in general) be defined inside the scope that uses them.
  • Error problems should be reported through the exception mechanism.
  • Do not declare static members in the core library outside of the System class unless you know very well what you are doing (this can mess the initialization process).
  • Use STL containers an STL algorithms when possible. Beware though, of thread-safety implications with STL.
  • If an argument should never be NULL declare it as a reference (when possible).
  • Remember to define default values for arguments where it makes sense (i.e. most of the time is that value).
  • Avoid the usage of macros unless strictly necessary. Consider templates and inline functions first.
  • Use static functions when possible (particularly inside plugins).
  • Enum types should in general be defined inside the class that uses them.

Naming Conventions

  • All core library classes must be defined in the nanos namespace.
  • All plugin classes must be defined in the nanos::ext namespace:
   namespace nanos {
   namespace ext {
     class PluginClass
     {
        ...
     };
   }}
  • Class names should have all words capitalized with no _ (e.g. !MyClassName)
  • Class methods should have all words capitalized with no _ except for the first one (e.g. myMethod)
  • Class data members should start with _ and have all words capitalized except the first one (e.g. _myData)
  • Other variables (globals, locals, parameters,...) should have no words capitalized using _ to separate them (e.g. my_data)
  • Type names should have no words capitalized using _ to separate them and ending with _t (e.g. my_type_t)
  • Define typedefs for template containers used for data members (e.g. typedef std::vector<T*> my_type_t;)
  • Define typedefs for enum types used for data members (e.g. typedef enum{X,Y,Z} my_type_t;)
  • External symbols (functions and type names) MUST be prefixed with nanos_ (e.g. nanos_wd_t)

Classes and Structs

  • Constructors, destructors and assignment operators
    • All classes MUST have an explicit default constructor and copy constructor.
    • Remember to initialize all data members in the constructors. When possible do so in the initialization list and not in the constructor body.
    • All classes MUST have an explicit destructor unless they have no data members.
    • All classes MUST have an explicit assignment operator.
    • If you implement an assignment operator always check if a self-assignment ( a = a; ) is handled correctly. Mark so in the code with a comment.
    • If you think the class should not have any of them declare as private
  • As a rule of thumb, all data members should be private with get/set methods defined in the headers to increase inlining. Consider it deeply before declaring a data member shared or friend to another class.
  • All classes that implement a virtual method MUST declare their destructor to be virtual.
  • Do NOT call virtual methods from inside constructors or destructors (see http://www.artima.com/cppsource/nevercall.html)
  • Use the named parameter idiom when possible to set object properties (see WorkDescriptor::tied for an example).

Methods and Functions

  • Function declarations (or definitions) MUST have an space between function name and the opening parentheses:
   type_t myMethod (type_foo_t foo, ..., type_bar_t bar);
  • Function calls have no spaces between function name and the opening parentheses:
   myMethod(foo, ..., bar);
  • Parameters (or arguments) in multiple lines should be indented to be below the previous line parameters:
   type_t myMethod (type_foo_t foo, ..., type_bar_t bar,
                    type_baz_t baz);
  • Use of default parameters is preferred over overloading a method or function (when possible).

Conditional

  • Compare pointers to NULL:
   if ( p != NULL ) {
      ...
   }
  • and not:
   if (!p) {
      ...
   }
  • Compare integer to the appropriate value:
   if ( i > 0 ) {
      ...
   }
  • and not:
   if (i) {
      ...
   }
  • Do not compare booleans to true/false:
   if ( myBoolean ) {
      ...
   }
  • and not:
   if ( myBoolean == true ) {
      ...
   }
  • Else [else-if] statement will close and open brackets in the same line:
   if ( cond ) {
      ...
   } else {
      ... 
   }

Other Programming Patterns

  • Avoid if possible any kind of atomic operation (atomic updates, locks, cas, ...). If necessary use the double-checked locking optimization:
   if ( cond ) {
      lock++;
      if ( cond ) {
         // do whatever
      }
      lock--;
   }

Code Documentation

Documenting Classes and Data Members

Documenting Functions and Methods

  • Use doxygen to document all function and method definitions.
    • A brief summary (one sentence) declaring the function main purpose (mandatory).
    • A list of parameters (with its type [in], [out] or [in,out]) including a short description (mandatory, if any).
    • The returning value of the function (mandatory, if non-void).
    • A more detailed function description (when needed).
    • Use the ''See Also'' section to refer other documented functions, types, structures... (when needed)
  • A doxygen example:
//! \brief Brief function description
//! \param [type] param1 Param 1 description
//! \param [type] param2 Param 2 description
//! ...
//! \param [type] paramN Param N description
//! \return Return value description
//! \par Description:
//! You can use several lines to describe the function. Doxygen will text-justify the provided
//! description in order to fit it properly in the web page.
//!
//! \sa SeeAlsoItem1, SeeAlsoItem2, ... SeeAlsoItemN
void nanosFunction ( type1_t param1, type2_t param2, ... ,typeN_t paramN )
{
   ...
}
  • Use doxygen to document as well data members, enum values and global variables.
type1_t _data1 //!< data1 description
type2_t _data2 //!< data2 description
...
typeN_t _dataN //!< dataN description
  • Document parts of your code where what is happening may not be obvious.
	// copy all q elements into p, q is zero-terminated
	while ( *p++ = *q++ ); 
  • Use FIXME (#issue) and TODO (#issue) to mark as 'defect' or 'task' respectively.
   // FIXME: (#104) Memory is requiered to be aligned to 8 bytes in some architectures, temporary solved using: ((s+7)>>3)<<3
   int size_to_allocate = ( ( *uwd == NULL ) ? sizeof( WD ) : 0 ) + ( ( data != NULL && *data == NULL ) ? (((data_size+7)>>3)<<3) : 0 ) +
                          sizeof( DD* ) * num_devices + dd_size ; 

Commandline and environment variables

  • All parameters names should start with -nth (e.g. -nth-pes ) and they should be lowercase
  • Use '-' in parameter names to separate words
  • If it's not a core parameter it should also include a plugin prefix (e.g., -nth-smp-stack-size, -nth-wfsch-fifo )
  • All environment variable should start with NTH and they should be uppercase
  • Use '_' in enviroment variables to separate words