In general, Google's coding standard is used, and we strongly encourage to read it.
You can find all the steps needed to build & install Antares Simulator in the documentation website or its sources.
Below are our specific (but not all!) exceptions to the Google's coding standard:
- All C++ code should conform to the C++20 standard.
- We use
.cpp
files and.h
for headers, in UTF-8 encoding. - For new files we use CamelCase, like
FileReader.cpp
. - We use
#pragma once
instead of the#define
Guard in header files. - Includes are sorted and grouped by directory, there should be newlines between different directories.
- Order of directories in includes: "current_dir/current_file.h", includes from other dirs sorted by dependencies (e.g. indexer, then coding, then base), "defines.h", C++ standard library headers, boost headers.
- We ARE using C++ exceptions. Feel free to define your own exceptions, derived from
std::exception
or any child class. - We are using all features of C++17 and C++20
- We try to limit the usage of boost libraries which require linking (and prefer C++20 types over their boost counterparts).
Naming and formatting
-
We ALWAYS use 4 spaces indent and don't use tabs.
-
We don't have strict limits on line width, but keep it reasonable to fit on the screen. The advised width is that written in the src/.clang-format file (currently 100).
-
Doxygen-style comments can be used.
-
Use left-to-right order for variables/params:
const string& s
(reference to the const string). -
In one line
if
,for
,while
we use brackets. -
Space after the keyword in conditions and loops. Space after
;
infor
loop. -
Space between binary operators:
x = y * y + z * z
. -
Space after double dash.
-
We use
using
keyword instead oftypedef
. -
We do not use the Systems Hungarian Notation: do not add the "p" suffix to your pointer variable names and the "T" prefix or suffix to your type names.
-
Compile-time constants must be named in CamelCase, starting with a lower-case
k
, e.g.kCompileTimeConstant
and marked asconstexpr
when possible. -
Functions (free or member) should be named using
lowerCamelCase
, e.gisPrime(unsigned int n)
. -
Values of enum classes must be named in CAPITAL, e.g.
enum class Color { RED, GREEN, LIGHT_BLUE };
. -
Macros and C-style enums should be avoided. If necessary, they must be named in UPPER_CASE, and enum values must be prefixed with a capitalized enum name.
Note that macros complicate debugging, and old-style enums have dangerous implicit conversions to integers, and tend to clutter containing namespaces. Avoid them when possible - use
const
orconstexpr
instead of macros, and enum classes instead of enums.
We write code without warnings on clang++, g++ and MSVC !
When using static
variables, be aware that some of Antares Simulator's functions run on multiple threads. Please avoid introducing global variables.
Yuni is a C++ framework that fullfiled some of the lacking features pre-C++11. Even though you'll see it used widely through the existing code base, we recommend against using it for new code. It is namespaced under Yuni
.
Currently, CI is run only for specific branch names:
feature/*
features/*
fix/*
release/*
issue-*
doc/*
If you create a branch with a different name, no CI will be run, but you will receive a notification indicating that your branch name is incorrect.
In order to avoid pushing with invalid branch name, a git hook is provided for pre-commit check.
This hook is available in the .githooks
directory.
By default, git use hooks in .git/hooks
directory which is not under version control. You can
define a new hooks directory with this command in Antares Simulator root directory :
git config core.hooksPath .githooks
A pull request name must be self-explanatory: this will be the default commit title when merging.
Please provide a description in the head comment of the PR. This description will be the details of the merge commit. The description should be short but proportional to the length or complexity of the PR. Try to explain the motivation of the PR (why) and the method employed (how).
When a pull request is opened, please set it to draft if it is still being worked on or not ready for review.
If your Pull Request changes a part of the code that is documented, please update the documentation also, in the "docs" directory.
Most of our coding style is specified in a configuration file for ClangFormat.
To automatically format a file, install clang-format
and run:
clang-format -i file.cpp file.hpp other_file.cpp
clang-format 18.1.3 is the reference version, but any 18.x version should work as well. We strongly advise that you configure your IDE / text editor to automatically format code according to the clang-format style. Non-conforming code can't be merged to the develop branch.
You may also use script src/format-code.sh to format all the code. Generated code (ANTLR, etc.) won't be automatically formatted.
#pragma once
#include <math>
uint16_t constexpr kBufferSize = 255;
// C-style enums are ALL_CAPS. But remember that C++11 enum classes are preferred.
enum Type
{
TYPE_INTEGER,
TYPE_FLOAT,
TYPE_STRING
};
using TMyTypeStartsWithCapitalTLetter = double;
class ComplexClass
{
public:
Complex(double rePart, double imPart):
re(rePart),
im(imPart)
{
}
double Modulus() const
{
const double rere = re * re;
const double imim = im * im;
return sqrt(rere + imim);
}
double OneLineMethod() const
{
return re;
}
private:
double re;
double im;
};
namespace
{
void lowerCamelCaseFunctionName(int lowerCamelCaseVar)
{
static int counter = 0;
counter += lowerCamelCaseVar;
}
} // namespace
namespace lower_case
{
template<typename TypenameWithoutAffixes>
void SomeFoo(int a, int b, TypenameWithoutAffixes /* We avoid compilation warnings. */)
{
for (int i = 0; i < a; ++i)
{
// IMPORTANT! We DON'T use one-liners for if statements for easier debugging.
// The following syntax is invalid: if (i < b) Bar(i);
if (i < b)
{
Bar(i);
}
else
{
Bar(i);
Bar(b);
// Commented out the call.
// Bar(c);
}
}
}
} // namespace lower_case
// Switch formatting.
int Foo(int a)
{
switch (a)
{
case 1:
Bar(1);
break;
case 2:
{
Bar(2);
break;
}
case 3:
default:
Bar(3);
break;
}
return 0;
}
// Loops formatting.
if (condition)
{
foo();
}
else
{
bar();
}
if (condition)
{
if (condition)
{
foo();
}
else
{
bar();
}
}
for (size_t i = 0; i < size; ++i)
{
foo(i);
}
while (true)
{
if (condition)
{
break;
}
}
// Space after the keyword.
if (condition)
{
}
for (size_t i = 0; i < 5; ++i)
{
}
while (condition)
{
}
switch (i)
{
}
// Space between operators, and don't use space between unary operator and expression.
x = 0;
x = -5;
++x;
x--;
x *= 5;
if (x && !y)
{
}
v = w * x + y / z;
v = w * (x + z);
// Space after double dash. And full sentences in comments.
- If you see outdated code which can be improved, DO IT NOW (but in a separate pull request or commit)!
- Your code should work at least on [ubuntu|windows] platforms.
- Your code should compile with a C++20 compiler (currently supported clang++/g++/MSVC)
- Consult with the dev team before using any new 3party library
- Cover your code with unit tests. See examples for existing libraries
- Check Base and Coding libraries for most of the basic functions
- Ask your team if you have any questions
- Release builds contain debugging information (for profiling), production builds do not
- If you don't have enough time to make it right, leave a
// TODO(DeveloperName): need to fix it
comment
- Use
Antares::logs.[level]() << message
for logging, below is more detailed description for level:logs.info() << msg
- always prints log messagelogs.debug() << msg
- logs only in DEBUGlogs.warning() << msg
- the same aslogs.info()
but catches your attentionlogs.error()
- the same aslogs.warning()
, but triggers an error when loading a study, with exceptionslogs.fatal()
- same aslogs.error()