-
Notifications
You must be signed in to change notification settings - Fork 40
Coding standards
- Page width is approximately 120 characters. Screens are wide nowadays and 80 characters is an obsolete restriction.
- Indentation: 4 spaces (no tabs). Exception: class access modifiers are indented with 2 spaces.
class A
{
private:
int n_;
public:
A();
};
- Comments are inserted before the code with slash-star style starting with the lower case:
/* call a very important function */
do_something();
- Spaces between operators:
if (i < 5) {
j = 5;
} else {
j = 1;
}
for (int k = 0; k < 3; k++) {
}
int lm = l * l + l + m;
double d = std::abs(e);
int k = idx[3];
- Spaces between function arguments:
double d = some_func(a, b, c);
but not
double d=some_func(a,b,c);
and not
double d = some_func( a, b, c );
- Spaces between template arguments, but not between <,> brackets:
std::vector<std::array<int, 2>> vec;
but not
std::vector< std::array< int, 2 > > vec;
- Curly braces for classes and functions start form the new line:
class A
{
....
};
inline int num_points()
{
return num_points_;
}
- Curly braces for if-statements, for-loops, switch-case statements, etc. start at the end of the line:
for (int i: {0, 1, 2}) {
some_func(i);
}
if (a == 0) {
std::printf("a is zero");
} else {
std::printf("a is not zero");
}
switch (i) {
case 1: {
do_something();
break;
}
case 2: {
do_something_else();
break;
}
}
- Even single line 'if' statements and 'for' loops must have the curly braces:
if (i == 4) {
some_variable = 5;
}
for (int k = 0; k < 10; k++) {
do_something(k);
}
- Reference and pointer symbols are part of type:
std::vector<double>& vec = make_vector();
double* ptr = &vec[0];
auto& atom = unit_cell().atom(ia);
- Const modifier follows the type declaration:
std::vector<int> const& idx() const
{
return idx_;
}
/* or */
auto const& atom = unit_cell().atom(ia);
- Names of class members end with underscore:
class A
{
private:
int lmax_;
};
- Setter method starts from set_, getter method is a variable name itself:
class A
{
private:
int lmax_;
public:
int lmax() const
{
return lmax_;
}
void set_lmax(int lmax__)
{
lmax_ = lmax__;
}
};
However, the new style for setter methods is preferable:
class A
{
private:
int lmax_;
public:
/// Get lmax
int lmax() const
{
return lmax_;
}
/// Set lmax
int lmax(int lmax__)
{
lmax_ = lmax__;
return lmax_;
}
};
- Order of class members: private, protected, public
class A
{
private:
int lmax_;
void bar();
protected:
void foo();
public:
int lmax() const
{
return lmax_;
}
};
- Single-line functions should not be flattened:
struct A
{
int lmax() const
{
return lmax_;
}
};
but not
struct A
{
int lmax() const { return lmax_; }
};
- Header guards have a standard name: double underscore + file name in capital letters + double underscore
#ifndef __HEADER_HPP__
#define __HEADER_HPP__
...
#endif // __HEADER_HPP__
- Variable names are all in lowercase and underscore-separated (aka 'snake_case'):
int num_bands;
std::complex<double> beta_psi;
but not
int NumBands;
/* or */
std::complex<double> BetaPsi;
/* or */
std::complex<double> Another_BetaPsi;
We use clang-format utility to enforce the basic formatting style. The .clang-format config file in the source root folder has the following definitions:
---
Language: Cpp
Standard: Cpp11
BreakBeforeBraces: 'Custom'
# Control of individual brace wrapping cases
BraceWrapping: {
AfterClass: 'true'
AfterControlStatement: 'false'
AfterEnum : 'true'
AfterFunction : 'true'
AfterNamespace : 'false'
AfterStruct : 'true'
AfterUnion : 'true'
BeforeCatch : 'false'
BeforeElse : 'false'
IndentBraces : 'false'
}
IndentCaseLabels: 'true'
AccessModifierOffset: -2
IndentWidth: 4
ColumnLimit: 120
UseTab: Never
AllowShortFunctionsOnASingleLine: 'None'
AllowShortIfStatementsOnASingleLine : 'false'
AllowShortLoopsOnASingleLine: 'false'
KeepEmptyLinesAtTheStartOfBlocks: 'true'
AlwaysBreakTemplateDeclarations: 'Yes'
PointerAlignment: Left
AllowAllParametersOfDeclarationOnNextLine: 'true'
AlignConsecutiveAssignments: 'true'
AlignConsecutiveDeclarations: 'false'
SortIncludes: 'false'
BinPackParameters: 'true'
BinPackArguments: 'true'
MaxEmptyLinesToKeep: 1
BreakConstructorInitializersBeforeComma: 'true'
#BreakConstructorInitializersStyle: 'BeforeComma'
ConstructorInitializerIndentWidth: 4
Cpp11BracedListStyle: 'true'
#AlwaysBreakAfterReturnType: None
AlwaysBreakAfterReturnType: 'TopLevelDefinitions'
...
The script 'clang_format.x' takes one argument (input source file) and produces a formatted output file with extra .fmt extension.
Problem: all 'standard' naming conventions are not satisfactory. For example, we have a class which does a DFT ground state. Following the common naming conventions it could be named like this:
- DFTGroundState
- DftGroundState
- dft_ground_state
Last two are bad, because DFT (and not Dft or dft) is a well recognized abbreviation. First one is bad because capital G adds to DFT and we automatically read DFTG round state.
Solution: we can propose the following: DFTgroundState or DFT_ground_state. The first variant still doesn't look very good because one of the words is capitalized (State) and one (ground) - is not. So we pick the second variant: DFT_ground_state (by the way, this is close to the Bjarne Stroustrup's naming convention, where he uses first capital letter and underscores, for example class Io_obj
).
Some other examples:
- class Ground_state (composed of two words)
- class FFT_interface (composed of an abbreviation and a word)
- class Interface_XC (composed of a word and abbreviation)
- class Spline (single word)
Exceptions are allowed if it makes sense. For example, low level utility classes like 'mdarray' (multi-dimensional array) or 'pstdout' (parallel standard output) are named with small letters.
Below is the list of standard names for some of the loop variables:
l - index of orbital quantum number
m - index of azimuthal quantum number
lm - combined index of (l,m) quantum numbers
ia - index of atom
ic - index of atom class
iat - index of atom typy
ir - index of r-point (real space point inside FFT grid or radial mesh)
ig - index of G-vector
idxlo - index of local orbital
idxrf - index of radial function
xi - combined index of lm and idxrf (product of angular and radial functions)
ik - index of k-point
itp - index of (theta, phi) spherical angles
The _loc suffix is often added to the variables to indicate that they represent the local fraction of the elements assigned to a given MPI rank.