1# C++ Coding Style and Conventions
2
3## General Philosophy
4
5Being an extensive and complicated language, there are often differences of
6opinions on "good" and "bad" C++ code.  Bjarne Stroustrup has said "Within C++
7is a smaller, simpler, safer language struggling to get out."  We are striving
8to write in this variant of C++ and are therefore following the "C++ Core
9Guidelines" that Bjarne and Herb Sutter introduced at CppCon 2015.
10
11Beyond a set of rules that help codify "good" and "bad" C++, we have general
12principles that help us align the software we develop with the constraints
13within the problem domain being solved by OpenBMC.  These are:
14 1. Code should be clear and concise.
15 2. Code should be written with modern practices.
16 3. Code should be performant.
17
18### Code should be clear and concise
19
20> Brevity is the soul of wit.
21
22It is important that code be optimized for the reviewer and maintainer and not
23for the writer.  Solutions should avoid tricks that detract from the clarity
24of reviewing and understanding it.
25
26Modern practices allow C++ to be an expressive, but concise, language.  We tend
27to favor solutions which succinctly represent the problem in as few lines as
28possible.
29
30When there is a conflict between clarity and conciseness, clarity should win
31out.
32
33### Code should be written with modern practices
34
35We strive to keep our code conforming to and utilizing of the latest in C++
36standards.  Today, that means all C++ code should be compiled using C++20
37compiler settings.  As the C++23 standard is finalized and compilers support
38it, we will move to it as well.
39
40We also strive to keep the codebase up-to-date with the latest recommended
41practices by the language designers.  This is reflected by the choice in
42following the C++ Core Guidelines.
43
44[[Not currently implemented]] We finally desire to have computers do our
45thinking for us wherever possible.  This means having Continuous Integration
46tests on each repository so that regressions are quickly identified prior to
47merge. It also means having as much of this document enforced by tools as
48possible by, for example, clang-format and clang-tidy.
49
50For those coming to the project from pre-C++11 environments we strongly
51recommend the book "Effective Modern C++" as a way to get up to speed on the
52differences between C++98/03 and C++11/14/17/20.
53
54### Code should be performant.
55
56OpenBMC targets embedded processors that typically have 32-64MB of flash and
57similar processing power of a typical smart-watch available in 2016.  This
58means that there are times where we must limit library selection and/or coding
59techniques to compensate for this constraint.  Due to the current technology,
60performance evaluation is done in order of { code size, cpu utilization, and
61memory size }.
62
63From a macro-optimization perspective, we expect all solutions to have an
64appropriate algorithmic complexity for the problem at hand.  Therefore, an
65`O(n^3)` algorithm may be rejected even though it has good clarity when an
66`O(n*lg(n))` solution exists.
67
68## Global Guidelines and Practices
69
70Please follow the guidelines established by the C++ Core Guidelines (CCG).
71
72https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md
73
74[[ Last reviewed revision is 53bc78f ]]
75
76Exceptions:
77
78### Guideline Support Library (GSL)
79
80We do not currently utilize the Guideline Support Library provided by the CCG.
81Any recommendation within the CCG of GSL conventions may be ignored at this
82time.
83
84### Style recommendations
85
86The following are not followed:
87 * NL.10 Avoid CamelCase
88 * NL.17 Use K&R-derived layout
89
90## Library and Feature Specifics
91
92Additional recommendations within the OpenBMC project on specific language
93features or libraries.
94
95### Exceptions
96
97We do use exceptions as a basis for error handling within OpenBMC.
98
99### Boost
100
101Use of boost is allowed, under the following circumstances:
1021. Use is done as a header-only library.  This allows unused functions and
103   methods to be removed by the compiler at link time, and avoids adding large
104amounts of overhead and flash usage.
1052. Implementers should include the lowest level header required to solve the
106   problem at hand.  This allows uses to be found and moved forward when new
107standards are available, as well as reduce compile times, and decrease the
108possibility of accidental use.  (ie, #include <boost/container/flat_map.hpp>
109not #include <boost/container.hpp>)
1103. The module used should not have an equivalent in the std namespace that meets
111   the same requirements for implementation or clarity:  For example,
112std::chrono should be preferred over boost::chrono.  std::array over
113boost::array.
1144. Use does not conflict with any of the core tenants of this coding standard
115   (clarity, modern practices, or performance).
116
117### iostream
118
119The iostream conventions of using 'operator<<' contribute to an increased code
120size over printf-style operations, due to individual function calls for each
121appended value.  We therefore do not use iostreams, or iostream-style APIs,
122for logging.
123
124There are cases when using an iostream utility (such as sstream) can result in
125clearer and similar-sized code.  iostream may be used in those situations.
126
127## Coding Style
128
129Indentation, naming practices, etc.
130
131### General
132
133* Line length should be limited to 80 characters.
134* Indentation should be done with 4 space characters.
135* Files should use Unix-style newlines (\n).
136
137### Clang Formatting
138
139Individual OpenBMC repositories can use [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
140if desired. The OpenBMC CI infrastructure will automatically verify the
141code formatting on code check-in if a .clang_format file is found
142within the root directory of the repository. This allows for automatic
143validation of code formatting upon check-in.
144
145If a custom configuration is desired, such as using different clang formatting
146for C and C++ files, a format-code.sh script can be created, which can for
147example use different .clang* files as input depending on the file type.
148The format-code.sh script will be executed as part of CI if found in the root
149directory of the repository, and will check that there are no files that were
150modified after running it (same check as running clang).
151
152OpenBMC requires a clang-format of version 6.0 or greater. An example of
153how to run clang-format against all code in your repo can be found by
154referencing the [tool](https://github.com/openbmc/openbmc-build-scripts/blob/master/scripts/format-code.sh) used by CI.
155
156[Example .clang-format](https://www.github.com/openbmc/docs/blob/master/style/cpp/.clang-format)
157
158### Bracket style
159
160* Utilize 'Allman' style brackets.  Brackets are on their own line at the same
161  indentation level as the statement that creates the scope.
162
163```
164if (condition)
165{
166    ...
167}
168```
169
170```
171void foo()
172{
173    ...
174}
175```
176
177* Even one line conditional and loop statements should have brackets.
178
179```
180/// Wrong.
181if (condition)
182    do_something;
183
184/// Correct
185if (condition)
186{
187    do_something;
188}
189```
190
191### Indentation
192
193* Content within a namespace should be at the same indentation level as the
194  namespace itself.
195
196```
197namespace foo
198{
199
200content
201
202}
203```
204
205* Content within a class / struct should be indented.
206
207```
208class Foo
209{
210    public:
211        Foo();
212}
213```
214
215* Content within a function / conditional / loop should be indented.
216
217```
218void foo()
219{
220    while (1)
221    {
222        if (bar())
223        {
224            ...
225        }
226    }
227}
228```
229
230* Switch / case statements should be indented.
231
232```
233switch (foo)
234{
235    case bar:
236    {
237        bar();
238        break;
239    }
240
241    case baz:
242    {
243        baz();
244        break;
245    }
246}
247```
248
249* Labels should be indented so they appear at 1 level less than the current
250  indentation, rather than flush to the left.  (This is not to say that goto
251  and labels are preferred or should be regularly used, but simply when they
252  are used, this is how they are to be used.)
253
254```
255void foo()
256{
257    if (bar)
258    {
259        do
260        {
261            if (baz)
262            {
263                goto exit;
264            }
265
266        } while(1);
267
268    exit:
269        cleanup();
270    }
271}
272```
273
274### Naming Conventions.
275
276* We generally abstain from any prefix or suffix on names.
277* Acronyms should be same-case throughout and follow the requirements as
278  in their appropriate section.
279
280```
281/// Correct.
282SomeBMCType someBMCVariable = bmcFunction();
283
284/// Wrong: type and variable are mixed-case, function isn't lowerCamelCase.
285SomeBmcType someBmcVariable = BMCFunction();
286```
287
288### Header Ordering
289
290Header inclusion order for a header file:
291```
292local headers (e.g. "daemon_sys.hpp")
293c-libraries
294cpp-libraries (including openbmc libraries)
295```
296
297Header inclusion order for a source file:
298```
299source.hpp (if applicable)
300local headers
301c-libraries
302cpp-libraries
303```
304
305All in alphabetically sorted order.
306
307#### Files
308
309* C++ headers should end in ".hpp".  C headers should end in ".h".
310* C++ files should be named with lower_snake_case.
311
312#### Types
313
314* Prefer 'using' over 'typedef' for type aliases.
315* Structs, classes, enums, and typed template parameters should all be in
316  UpperCamelCase.
317* Prefer namespace scoping rather than long names with prefixes.
318* A single-word type alias within a struct / class may be lowercase to match
319  STL conventions (`using type = T`) while a multi-word type alias should be
320  UpperCamelCase (`using ArrayOfT = std::array<T, N>`).
321* Exception: A library API may use lower_snake_case to match conventions of the
322  STL or an underlying C library it is abstracting.  Application APIs should
323  all be UpperCamelCase.
324* Exception: A for-convenience template type alias of a template class may end
325  in `_t` to match the conventions of the STL.
326
327```
328template <typename T>
329class Foo
330{
331    using type = std::decay_t<T>;
332};
333
334template <typename T> using foo_t = Foo<T>::type;
335```
336
337#### Variables
338
339* Variables should all be lowerCamelCase, including class members, with no
340  underscores.
341
342#### Functions
343
344* Functions should all be lowerCamelCase.
345* Exception: A library API may use lower_snake-case to match conventions of
346  the STL or an underlying C library it is abstracting.  Application APIs
347  should all be lowerCamelCase.
348
349#### Constants
350
351* Constants and enum members should be named like variables in lowerCamelCase.
352
353#### Namespaces
354
355* Namespaces should be lower_snake_case.
356* Top-level namespace should be named based on the containing repository.
357* Favor a namespace called 'details' or 'internal' to indicate the equivalent
358  of a "private" namespace in a header file and anonymous namespaces in a C++
359  file.
360
361### Header Guards
362
363Prefer '#pragma once' header guard over '#ifndef'-style.
364
365### Additional Whitespace
366
367* Follow NL.18: Use C++-style declarator layout.
368
369```
370foo(T& bar, const S* baz); /// Correct.
371foo(T &bar, const S *baz); /// Incorrect.
372```
373
374* Follow NL.15: Use spaces sparingly.
375
376* Insert whitespace after a conditional and before parens.
377
378```
379if (...)
380while (...)
381for (...)
382```
383
384* Insert whitespace around binary operators for readability.
385
386```
387foo((a-1)/b,c-2); /// Incorrect.
388foo((a - 1) / b, c - 2); /// Correct.
389```
390
391* Do not insert whitespace around unary operators.
392```
393a = * b;  /// Incorrect.
394a = & b;  /// Incorrect.
395a = b -> c;  /// Incorrect.
396if (! a)  /// Incorrect.
397```
398
399* Do not insert whitespace inside parens or between a function call and
400  parameters.
401
402```
403foo(x, y); /// Correct.
404foo ( x , y ); /// Incorrect.
405
406do (...)
407{
408} while(0); /// 'while' here is structured like a function call.
409```
410
411* Prefer line-breaks after operators to show continuation.
412```
413if (this1 == that1 &&
414    this2 == that2) /// Correct.
415
416if (this1 == that1
417    && this2 == that2) /// Incorrect.
418```
419
420* Long lines should have continuation start at the same level as the parens or
421  all all items inside the parens should be at a 2-level indent.
422
423```
424reallyLongFunctionCall(foo,
425                       bar,
426                       baz); // Correct.
427
428reallyLongFunctionCall(
429        foo,
430        bar,
431        baz); // Also correct.
432
433reallyLongFunctionCall(
434        foo, bar, baz); // Similarly correct.
435
436reallyLongFunctionCall(foo,
437        bar,
438        baz); // Incorrect.
439```
440
441### Misc Guidelines.
442
443* Always use `size_t` or `ssize_t` for things that are sizes, counts, etc.
444  You need a strong rationale for using a sized type (ex. `uint8_t`) when a
445  size_t will do.
446
447* Use `uint8_t`, `int16_t`, `uint32_t`, `int64_t`, etc. for types where size
448  is important due to hardware interaction.  Do not use them, without good
449  reason, when hardware interaction is not involved; prefer size_t or int
450  instead.
451
452
453