1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
# C++ Style Guide
In general, [Google's coding standard](https://google.github.io/styleguide/cppguide.html) is used, and we strongly encourage to read it.
Below are our specific (but not all!) exceptions to the Google's coding standard:
- All code should conform to C++11 standard (not C++14 or higher). If target platform does not support all features of C++11, older C++ standard should be used.
- We use `.cpp` and `.hpp` files, not `.cc` and `.h` (`.c` and `.h` are used for C code), in UTF-8 encoding.
- File names are lowercase with underscores, like `file_reader.cpp`.
- We use `#pragma once` instead of the `#define` Guard in header files.
- We don't include system, std and boost headers directly, use `#include "std/<wrapper.hpp>"`.
- Includes are sorted and grouped by directory, there should be newlines between different directories.
- Order of directories in includes: "current_dir/current_file.hpp", other includes from the same dir, includes from other dirs sorted by dependencies: `coding, geometry, base, std, "defines.hpp", 3party` should go last in that order.
- We ARE using C++ exceptions.
- We are using all features of C++11 (the only known exception is thread_local which is not fully supported on all platforms).
- We don't use boost libraries which require linking (and prefer C++11 types over their boost counterparts).
Naming and formatting
- We ALWAYS use two spaces indent and don't use tabs.
- We don't have hardcoded line width, but keep it reasonable to fit on the screen.
- 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`.
- Don't specify `std::` and `boost::` prefixes (headers in std/ folder already have `using std::string`).
- Use right-to-left order for variables/params: `string const & s` (reference to the const string).
- In one line `if`, `for`, `while` we do not use brackets. If one line `for` or `while` is combined with one line `if`, do use brackets for cycle.
- Space after the keyword in conditions and loops. Space after `;` in `for` loop.
- Space between binary operators: `x = y * y + z * z`.
- Space after double dash.
- We use `using` keyword instead of `typedef`.
- Compile-time constants must be named in camelCase, starting with a lower-case `k`, e.g. `kCompileTimeConstant` and marked as `constexpr` when 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 `const` or `constexpr` instead of macros, and enum classes instead of enums.
**We write code without warnings!**
## ClangFormat
Most of our coding style is specified in a configuration file for [ClangFormat](http://clang.llvm.org/docs/ClangFormat.html).
To automatically format a file, install `clang-format` and run:
clang-format -i file.cpp file.hpp other_file.cpp
## Formatting Example/Guide/Reference
```cpp
#pragma once
#include "std/math.hpp"
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 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 <class TTemplateTypeStartsWithCapitalTLetter>
void SomeFoo(int a, int b,
TTemplateTypeStartsWithCapitalTLetter /* 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 the separate pull request)! Make this awesome world even more better!
- Your code should work at least on [mac|win|linux|android][x86|x86_64], [ios|android][armv7|arm64] architectures
- Your code should compile well with gcc 4.8+ and clang 3.5+
- Try to 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@maps.me mailing list to ask all developers and bugs@maps.me mailing list to post bugs
- Release builds contain debugging information (for profiling), production builds are not
- If you don't have enough time to make it right, leave a `// TODO(DeveloperName): need to fix it` comment
### Some useful macros:
- `#ifdef DEBUG | RELEASE | OMIM_PRODUCTION`
- `#ifdef OMIM_OS_ANDROID | OMIM_OS_IPHONE | OMIM_OS_MAC` (and some other useful OS-related macros, see `std/target_os.hpp`)
- Use `ASSERT(expression, (out message))` and `ASSERT_XXXXXX` macros often to check code validity in DEBUG builds
- Use `CHECK(expression, (out message))` and `CHECK_XXXXXX` macros to check code validity in all builds
- Use `LOG(level, (message))` for logging, below is more detailed description for level:
* `LINFO` - always prints log message
* `LDEBUG` - logs only in DEBUG
* `LWARNING` - the same as `LINFO` but catches your attention
* `LERROR` - the same as `LWARNING`, but crashes in DEBUG and works in RELEASE
* `LCRITICAL` - the same as `LERROR` and ALWAYS crashes
- Need scope guard? Check `MY_SCOPE_GUARD(name, func)`
- Use `std::array::size()` to calculate plain C-array's size
- Declare your own exceptions with `DECLARE_EXCEPTION(name, baseException)`, where `baseException` is usually `RootException`
- Throw exceptions with `MYTHROW(exceptionName, (message))`
- A lot of useful string conversion utils are in `base/string_utils.hpp`
|