Skip to content

Coding Style

Kyle Shannon edited this page Jun 17, 2016 · 2 revisions

C/C++ code style

This is a legacy document. Starting with WindNinja 3.1.0, WindNinja follows the LLVM style guide. See #148 for links and more information.

`clang-format` can be used to format code. The default with no arguments can be used. To force code conformance, install `scripts/git/pre-commit` in `.git/hooks`. This will disallow non-conforming code commits (changes only). You must install `clang-format` and update the name in the script (ubuntu uses clang-format-3.6 for example).

Variable, type, enum, etc. naming will be updated ad-hoc, same as automatic style formatting. New code should conform, and by 3.2 or there abouts, all code touched should conform.

***DEPRECATED***

C++ usage

Currently we use a limited set of C++ features:

  • Classes
  • Templating
  • Polymorphism
  • Inheritance
  • Standard Containers

Templating shouldn’t be added (we don’t need it anywhere). We currently use templating for our low-level georeferenced AsciiGrid class and it’s data member for different types. I can’t imagine we’ll need more.

Polymorphism should only be used where it counts, mainly to abstract different input types (see Initialize). Virtual interfaces should be created (don’t forget the virtual destructor).

Inheritance should be used judiciously, preferably no multiple inheritance, see polymorphism.

Standard containers. Standard containers (std::string, std::vector, etc.) are convenient. It would be a good idea to add a very simple class for our needs.

Exceptions. We use exceptions. If you catch an exception, and cannot be absolutely sure that things can be fixed, you must rethrow. Hopefully it gets to a place we can regroup, and try again. This is how the GUI works, it is able to recover and start again.

Whitespace

  • No tabs
  • indent = 4 spaces

Line Endings

  • Use unix style line endings only (\n), not windows (\r\n) or mac (whatever they use)
  • Set your editor to not clip whitespace, this causes a change on that line and diff’ing becomes difficult.

Filenames

  • All lower case(from now on)
    mynewheader.h
    or
    my_newheader.h
    are both fine.

Preprocessor definitions

  • Left margin aligned
  • If you are creating (#define) make sure it is a good name
  • If the ifdef code is more than one line, comment the related directives (#else, #endif, etc.).

#define NINJA_ENABLE_SOME_FEATURE

#ifdef NINJA_ENABLE_SOME_FEATURE
    UseSomeFeature();
    UseAnotherFeature();
#else /* NINJA_ENABLE_SOME_FEATURE */
    UseNotAsCoolFeature();
#endif /* NINJA_ENABLE_SOME_FEATURE */

Variables

  • Use camel notation, first letter lower case.
    
    int myInteger;
    double myFloatTimesTwo;
    
  • Some gdal related functions use hungarian notation prefixes, this is not necessary:
    
    double adfGeoTransform[6];
    int nBand;
    double *padfData;
    

Counters/index variables can be standard values:


int i, j, k, counter;

Classes

  • Use camel notation, first letter upper case:
    
    class MyClassThatDoesEverything
    {
    public:
        int i;
    private:
        int j;
    };
    

Functions

  • Use camel notation, first letter upper case (if possible).
  • Spacing in argument lists is your preference, ie:
    
    int MyFunction( int a, int b );
    

    or
    
    int MyFunction(int a, int b);
    

    are both fine. Try to stay with whatever the established method is in any given file.

Operators

  • For clarity, place spaces on either side of operators:
    
    float f = 10.0 * x;
    

    This is not necessary for unary operators:
    
    int i;
    int j;
    int *k;
    j = i++;
    k = &j;
    *k++;
    

Control Statements

  • All control statements should have braces, no exceptions. This avoids a stupid bug issue like this:
    Current code:
    
    float i = x * 2;
    if( i < 25 )
        i * 1.5
    

    And someone has to add some functionality, there is a chance they will add code w/o adding braces:
    
    float i = x * 2;
    if( i < 25 )
        i * 1.5
        i + 0.003
    

    instead of the proper way:
    
    float i = x * 2;
    if( i < 25 )
    {
        i * 1.5
        i + 0.003
    }
    

It is just safer to always add braces when the statement is added.

Namespaces

  • Use namespaces explicitly, or rename them.
  • If we do define a WindNinja namespace, that should be the only one. I do not like nested namespaces.
  • Don’t use using without explicitly renaming
  • Don’t use using namespace std;, it defeats the purpose of namespaces, and causes unforeseen namespace clashes.
  • You can explicitly import object/functions though, ie using namespace std::cout, std::cin, etc.

Examples:



#ifndef MY_GOOD_CODE_GUARD_H_
#define MY_GOOD_CODE_GUARD_H_

#include "some_file.h"

namespace my_space = MyReallyLongSuperCoolNamespace::WithAnother::Stupid::ToLong::Namespace;
using namespace std::cout;

/** 
 * @brief Explicitly defined brief description
 *
 * Other info
 */

class MyClass : public SomeOther
    : public AnotherClass
{
public:
    int myInt;
    char *myString;

private:
    void MyFunc(int one, int secondInt);
};

for(int i = 0; i < someInt; i++)
{
    if(i == 10)
    {
        i = i * 10;
    }
}

/**
 * \brief Calculate the area of a rectangle(brief description.
 *
 * Calulate the area of a rectangle using the length of
 * two of the rectangle's sides.  A more detailed 
 * description can go here.  This can span many lines and 
 * may contain any type of information.
 *
 * @note a little note about something
 * @warning a warning about the fx
 *
 * @param a length of one side of the rectangle
 * @param b length of the other side of the rectangle
 * @return area of the rectangle
 */
double area( double a, double b )
{
    return a * b;
}

#endif /* MY_GOOD_CODE_GUARD_H_ */

  • See attachment for more doxygen information