7.1 KiB
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
In general, Google's coding standard is used, and we strongly encourage to read it.
Below are our specific (but not all!) exceptions to the Google's coding standard:
- All C++ code should conform to the C++23 standard.
- We use
.cppand.hppfiles, not.ccand.h(.cand.hare used for C code), in UTF-8 encoding. - File names are lowercase with underscores, like
file_reader.cpp. - We use
#pragma onceinstead of the#defineGuard 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.hpp", includes from other dirs sorted by dependencies (e.g. indexer, then coding, then base), "defines.hpp", C++ standard library headers, boost headers, 3party.
- We ARE using C++ exceptions.
- We are using all features of C++17 and C++23 except
std::filesystem,std::to_chars,std::from_charsandstd::formatwhich are not fully supported on all platforms. - We try to limit the usage of boost libraries which require linking (and prefer C++23 types over their boost counterparts).
Naming and formatting
-
We ALWAYS use two 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 .clang-format file (currently 100).
-
Doxygen-style comments can be used.
-
Underscores are allowed only in prefixes for member variables and namespace names, like
int m_countriesCount; namespace utf_parser. -
Use right-to-left order for variables/params:
string const & s(reference to the const string). -
In one line
if,for,whilewe do not use brackets, even if a one linefororwhileis combined with one lineif. -
Space after the keyword in conditions and loops. Space after
;inforloop. -
Space between binary operators:
x = y * y + z * z. -
Space after double dash.
-
We use
usingkeyword 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.kCompileTimeConstantand marked asconstexprwhen possible. -
Values of enum classes must be named in CamelCase, e.g.
enum class Color { Red, Green, LightBlue };. -
Macros and C-style enums 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
constorconstexprinstead of macros, and enum classes instead of enums.
We write code without warnings!
Formatting Example/Guide/Reference
#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) : m_re(rePart), m_im(imPart) {}
double Modulus() const
{
double const rere = m_re * m_re;
double const imim = m_im * m_im;
return sqrt(rere + imim);
}
double OneLineMethod() const { return m_re; }
private:
// We use the "m_" prefix for member variables.
double m_re;
double m_im;
};
namespace
{
void CamelCaseFunctionName(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.
Tips and Hints
- 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 [mac|linux|android][x86|x86_64], [ios|android][x86|armv7|arm64] architectures
- Your code should compile with C++23 compiler
- Avoid using any new 3party library if it is not fully tested and supported on all our platforms
- 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
- Use dev@comaps.app mailing list to ask all developers and bugs@comaps.app mailing list to post bugs
- 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 itcomment
Some useful macros:
#ifdef DEBUG | RELEASE#ifdef OMIM_OS_ANDROID | OMIM_OS_IPHONE | OMIM_OS_MAC(and some other useful OS-related macros, seestd/target_os.hpp)- Use
ASSERT(expression, (out message))andASSERT_XXXXXXmacros often to check code validity in DEBUG builds - Use
CHECK(expression, (out message))andCHECK_XXXXXXmacros to check code validity in all builds - Use
LOG(level, (message))for logging, below is more detailed description for level:LINFO- always prints log messageLDEBUG- logs only in DEBUGLWARNING- the same asLINFObut catches your attentionLERROR- the same asLWARNING, but crashes in DEBUG and works in RELEASELCRITICAL- the same asLERRORand ALWAYS crashes
- Need scope guard? Check
SCOPE_GUARD(name, func) - Use
std::array::size()to calculate plain C-array's size - Declare your own exceptions with
DECLARE_EXCEPTION(name, baseException), wherebaseExceptionis usuallyRootException - Throw exceptions with
MYTHROW(exceptionName, (message)) - A lot of useful string conversion utils are in
base/string_utils.hpp