xref: /aosp_15_r20/external/openscreen/docs/style_guide.md (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard# Open Screen Library Style Guide
2*3f982cf4SFabien Sanglard
3*3f982cf4SFabien SanglardThe Open Screen Library follows the [Chromium C++ coding style](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++.md)
4*3f982cf4SFabien Sanglardwhich, in turn, defers to the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html).
5*3f982cf4SFabien SanglardWe also follow the [Chromium C++ Do's and Don'ts](https://sites.google.com/a/chromium.org/dev/developers/coding-style/cpp-dos-and-donts).
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien SanglardC++14 language and library features are allowed in the Open Screen Library
8*3f982cf4SFabien Sanglardaccording to the [C++14 use in Chromium](https://chromium-cpp.appspot.com)
9*3f982cf4SFabien Sanglardguidelines.
10*3f982cf4SFabien Sanglard
11*3f982cf4SFabien SanglardIn general Open Screen follows [You Aren't Gonna Need
12*3f982cf4SFabien SanglardIt](https://martinfowler.com/bliki/Yagni.html) principles.
13*3f982cf4SFabien Sanglard
14*3f982cf4SFabien Sanglard## Disallowed Styles and Features
15*3f982cf4SFabien Sanglard
16*3f982cf4SFabien SanglardBlink style is *not allowed* anywhere in the Open Screen Library.
17*3f982cf4SFabien Sanglard
18*3f982cf4SFabien SanglardC++17-only features are currently *not allowed* in the Open Screen Library.
19*3f982cf4SFabien Sanglard
20*3f982cf4SFabien SanglardGCC does not support designated initializers for non-trivial types.  This means
21*3f982cf4SFabien Sanglardthat the `.member = value` struct initialization syntax is not supported unless
22*3f982cf4SFabien Sanglardall struct members are primitive types or structs of primitive types (i.e. no
23*3f982cf4SFabien Sanglardunions, complex constructors, etc.).
24*3f982cf4SFabien Sanglard
25*3f982cf4SFabien Sanglard## Modifications to the Chromium C++ Guidelines
26*3f982cf4SFabien Sanglard
27*3f982cf4SFabien Sanglard- `<functional>` and `std::function` objects are allowed.
28*3f982cf4SFabien Sanglard- `<chrono>` is allowed and encouraged for representation of time.
29*3f982cf4SFabien Sanglard- Abseil types are allowed based on the allowed list in [DEPS](
30*3f982cf4SFabien Sanglard  https://chromium.googlesource.com/openscreen/+/refs/heads/master/DEPS).
31*3f982cf4SFabien Sanglard- However, Abseil types **must not be used in public APIs**.
32*3f982cf4SFabien Sanglard- `<thread>` and `<mutex>` are allowed, but discouraged from general use as the
33*3f982cf4SFabien Sanglard  library only needs to handle threading in very specific places;
34*3f982cf4SFabien Sanglard  see [threading.md](threading.md).
35*3f982cf4SFabien Sanglard- Following YAGNI principles, only implement comparison operator overloads as
36*3f982cf4SFabien Sanglard  needed; for example, implementing operator< for use in an STL container does
37*3f982cf4SFabien Sanglard  not require implementing all comparison operators.
38*3f982cf4SFabien Sanglard
39*3f982cf4SFabien Sanglard## Code Syntax
40*3f982cf4SFabien Sanglard
41*3f982cf4SFabien Sanglard- Braces are optional for single-line if statements; follow the style of
42*3f982cf4SFabien Sanglard  surrounding code.
43*3f982cf4SFabien Sanglard- Using-declarations are banned from headers.  Type aliases should not be
44*3f982cf4SFabien Sanglard  included in headers, except at class scope when they form part of the class
45*3f982cf4SFabien Sanglard  definition.
46*3f982cf4SFabien Sanglard    - Exception: Using-declarations for convenience may be put into a shared
47*3f982cf4SFabien Sanglard      header for internal library use.  These may only be included in
48*3f982cf4SFabien Sanglard      .cc files.
49*3f982cf4SFabien Sanglard    - Exception: if a class has an associated POD identifier (int/string), then
50*3f982cf4SFabien Sanglard      declare a type alias at namespace scope for that identifier instead of using
51*3f982cf4SFabien Sanglard      the POD type.  For example, if a class Foo has a string identifier, declare
52*3f982cf4SFabien Sanglard      `using FooId = std::string` in foo.h.
53*3f982cf4SFabien Sanglard
54*3f982cf4SFabien Sanglard## Copy and Move Operators
55*3f982cf4SFabien Sanglard
56*3f982cf4SFabien SanglardUse the following guidelines when deciding on copy and move semantics for
57*3f982cf4SFabien Sanglardobjects:
58*3f982cf4SFabien Sanglard
59*3f982cf4SFabien Sanglard- Objects with data members greater than 32 bytes should be move-able.
60*3f982cf4SFabien Sanglard- Known large objects (I/O buffers, etc.) should be be move-only.
61*3f982cf4SFabien Sanglard- Variable length objects should be move-able
62*3f982cf4SFabien Sanglard  (since they may be arbitrarily large in size) and, if possible, move-only.
63*3f982cf4SFabien Sanglard- Inherently non-copyable objects (like sockets) should be move-only.
64*3f982cf4SFabien Sanglard
65*3f982cf4SFabien Sanglard### Default Copy and Move Operators
66*3f982cf4SFabien Sanglard
67*3f982cf4SFabien SanglardWe [prefer the use of `default` and `delete`](https://sites.google.com/a/chromium.org/dev/developers/coding-style/cpp-dos-and-donts#TOC-Prefer-to-use-default)
68*3f982cf4SFabien Sanglardto declare the copy and move semantics of objects.  See
69*3f982cf4SFabien Sanglard[Stroustrup's C++ FAQ](http://www.stroustrup.com/C++11FAQ.html#default)
70*3f982cf4SFabien Sanglardfor details on how to do that.
71*3f982cf4SFabien Sanglard
72*3f982cf4SFabien SanglardClasses should prefer [member
73*3f982cf4SFabien Sanglardinitialization](https://en.cppreference.com/w/cpp/language/data_members#Member_initialization)
74*3f982cf4SFabien Sanglardfor POD members (as opposed to value initialization in the constructor).  Every POD
75*3f982cf4SFabien Sanglardmember must be initialized by every constructor, of course, to prevent
76*3f982cf4SFabien Sanglard(https://en.cppreference.com/w/cpp/language/default_initialization)[default
77*3f982cf4SFabien Sanglardinitialization] from setting them to indeterminate values.
78*3f982cf4SFabien Sanglard
79*3f982cf4SFabien Sanglard### User Defined Copy and Move Operators
80*3f982cf4SFabien Sanglard
81*3f982cf4SFabien SanglardClasses should follow the [rule of three/five/zero](https://en.cppreference.com/w/cpp/language/rule_of_three).
82*3f982cf4SFabien Sanglard
83*3f982cf4SFabien SanglardThis means that if they implement a destructor or any of the copy or move
84*3f982cf4SFabien Sanglardoperators, then all five (destructor, copy & move constructors, copy & move
85*3f982cf4SFabien Sanglardassignment operators) should be defined or marked as `delete`d as appropriate.
86*3f982cf4SFabien SanglardFinally, polymorphic base classes with virtual destructors should `default` all
87*3f982cf4SFabien Sanglardconstructors, destructors, and assignment operators.
88*3f982cf4SFabien Sanglard
89*3f982cf4SFabien SanglardNote that operator definitions belong in the source (`.cc`) file, including
90*3f982cf4SFabien Sanglard`default`, with the exception of `delete`, because it is not a definition,
91*3f982cf4SFabien Sanglardrather a declaration that there is no definition, and thus belongs in the header
92*3f982cf4SFabien Sanglard(`.h`) file.
93*3f982cf4SFabien Sanglard
94*3f982cf4SFabien Sanglard## Passing Objects by Value or Reference
95*3f982cf4SFabien Sanglard
96*3f982cf4SFabien SanglardIn most cases, pass by value is preferred as it is simpler and more flexible.
97*3f982cf4SFabien SanglardIf the object being passed is move-only, then no extra copies will be made.  If
98*3f982cf4SFabien Sanglardit is not, be aware this may result in unintended copies.
99*3f982cf4SFabien Sanglard
100*3f982cf4SFabien SanglardTo guarantee that ownership is transferred, pass by rvalue reference for objects
101*3f982cf4SFabien Sanglardwith move operators.  Often this means adding an overload that takes a const
102*3f982cf4SFabien Sanglardreference as well.
103*3f982cf4SFabien Sanglard
104*3f982cf4SFabien SanglardPass ownership via `std::unique_ptr<>` for non-movable objects.
105*3f982cf4SFabien Sanglard
106*3f982cf4SFabien SanglardRef: [Google Style Guide on Rvalue References](https://google.github.io/styleguide/cppguide.html#Rvalue_references)
107*3f982cf4SFabien Sanglard
108*3f982cf4SFabien Sanglard## Noexcept
109*3f982cf4SFabien Sanglard
110*3f982cf4SFabien SanglardWe prefer to use `noexcept` on move constructors.  Although exceptions are not
111*3f982cf4SFabien Sanglardallowed, this declaration [enables STL optimizations](https://en.cppreference.com/w/cpp/language/noexcept_spec).
112*3f982cf4SFabien Sanglard
113*3f982cf4SFabien SanglardTODO(https://issuetracker.google.com/issues/160731444): Enforce this
114*3f982cf4SFabien Sanglard
115*3f982cf4SFabien SanglardAdditionally, GCC requires that any type using a defaulted `noexcept` move
116*3f982cf4SFabien Sanglardconstructor/operator= has a `noexcept` copy or move constructor/operator= for
117*3f982cf4SFabien Sanglardall of its members.
118*3f982cf4SFabien Sanglard
119*3f982cf4SFabien Sanglard## Template Programming
120*3f982cf4SFabien Sanglard
121*3f982cf4SFabien SanglardTemplate programming should be not be used to write generic algorithms or
122*3f982cf4SFabien Sanglardclasses when there is no application of the code to more than one type.  When
123*3f982cf4SFabien Sanglardsimilar code applies to multiple types, use templates sparingly and on a
124*3f982cf4SFabien Sanglardcase-by-case basis.
125*3f982cf4SFabien Sanglard
126*3f982cf4SFabien Sanglard## Unit testing
127*3f982cf4SFabien Sanglard
128*3f982cf4SFabien SanglardFollow Google’s testing best practices for C++.  Design classes in such a way
129*3f982cf4SFabien Sanglardthat testing the public API is sufficient.  Strive to follow this guidance,
130*3f982cf4SFabien Sanglardtrading off with the amount of public API surfaces needed and long-term
131*3f982cf4SFabien Sanglardmaintainability.
132*3f982cf4SFabien Sanglard
133*3f982cf4SFabien SanglardRef: [Test Behavior, Not Implementation](https://testing.googleblog.com/2013/08/testing-on-toilet-test-behavior-not.html)
134*3f982cf4SFabien Sanglard
135*3f982cf4SFabien Sanglard## Open Screen Library Features
136*3f982cf4SFabien Sanglard
137*3f982cf4SFabien Sanglard- For public API functions that return values or errors, please return
138*3f982cf4SFabien Sanglard  [`ErrorOr<T>`](https://chromium.googlesource.com/openscreen/+/master/platform/base/error.h).
139*3f982cf4SFabien Sanglard- In the implementation of public APIs invoked by the embedder, use
140*3f982cf4SFabien Sanglard  `OSP_DCHECK(TaskRunner::IsRunningOnTaskRunner())` to catch thread safety
141*3f982cf4SFabien Sanglard  problems early.
142*3f982cf4SFabien Sanglard
143*3f982cf4SFabien Sanglard### Helpers for `std::chrono`
144*3f982cf4SFabien Sanglard
145*3f982cf4SFabien SanglardOne of the trickier parts of the Open Screen Library is using time and clock
146*3f982cf4SFabien Sanglardfunctionality provided by [`platform/api/time.h`](https://chromium.googlesource.com/openscreen/+/refs/heads/master/platform/api/time.h).
147*3f982cf4SFabien Sanglard
148*3f982cf4SFabien Sanglard- When working extensively with `std::chrono` types in implementation code,
149*3f982cf4SFabien Sanglard  [`util/chrono_helpers.h`](https://chromium.googlesource.com/openscreen/+/refs/heads/master/util/chrono_helpers.h)
150*3f982cf4SFabien Sanglard  can be included for access to type aliases for
151*3f982cf4SFabien Sanglard  common `std::chrono` types, so they can just be referred to as `hours`,
152*3f982cf4SFabien Sanglard  `milliseconds`, etc. This header also includes helpful conversion functions,
153*3f982cf4SFabien Sanglard  such as `to_milliseconds` instead of
154*3f982cf4SFabien Sanglard  `std::chrono::duration_cast<std::chrono::milliseconds>`.
155*3f982cf4SFabien Sanglard  `util/chrono_helpers.h` can only be used in library-internal code, and
156*3f982cf4SFabien Sanglard  this is enforced by DEPS.
157*3f982cf4SFabien Sanglard- `Clock::duration` is defined currently as `std::chrono::microseconds`, and
158*3f982cf4SFabien Sanglard  thus is generally not suitable as a time type (developers generally think in
159*3f982cf4SFabien Sanglard  milliseconds). Prefer casting from explicit time types using
160*3f982cf4SFabien Sanglard  `Clock::to_duration`, e.g. `Clock::to_duration(seconds(2))`
161*3f982cf4SFabien Sanglard  instead of using `Clock::duration` types directly.
162*3f982cf4SFabien Sanglard
163*3f982cf4SFabien Sanglard### OSP_CHECK and OSP_DCHECK
164*3f982cf4SFabien Sanglard
165*3f982cf4SFabien SanglardThese are provided in [`platform/api/logging.h`](https://chromium.googlesource.com/openscreen/+/refs/heads/master/platform/api/logging.h)
166*3f982cf4SFabien Sanglardand act as run-time assertions (i.e., they
167*3f982cf4SFabien Sanglardtest an expression, and crash the program if it evaluates as false). They are
168*3f982cf4SFabien Sanglardnot only useful in determining correctness, but also serve as inline
169*3f982cf4SFabien Sanglarddocumentation of the assumptions being made in the code. They should be used in
170*3f982cf4SFabien Sanglardcases where they would fail only due to current or future coding errors.
171*3f982cf4SFabien Sanglard
172*3f982cf4SFabien SanglardThese should *not* be used to sanitize non-const data, or data otherwise derived
173*3f982cf4SFabien Sanglardfrom external inputs. Instead, one should code proper error-checking and
174*3f982cf4SFabien Sanglardhandling for such things.
175*3f982cf4SFabien Sanglard
176*3f982cf4SFabien SanglardOSP_CHECKs are "turned on" for all build types. However, OSP_DCHECKs are only
177*3f982cf4SFabien Sanglard"turned on" in Debug builds, or in any build where the `dcheck_always_on=true`
178*3f982cf4SFabien SanglardGN argument is being used. In fact, at any time during development (including
179*3f982cf4SFabien SanglardRelease builds), it is highly recommended to use `dcheck_always_on=true` to
180*3f982cf4SFabien Sanglardcatch bugs.
181*3f982cf4SFabien Sanglard
182*3f982cf4SFabien SanglardWhen OSP_DCHECKs are "turned off" they effectively become code comments: All
183*3f982cf4SFabien Sanglardsupported compilers will not generate any code, and they will automatically
184*3f982cf4SFabien Sanglardstrip-out unused functions and constants referenced in OSP_DCHECK expressions
185*3f982cf4SFabien Sanglard(unless they are "extern" to the local module); and so there is absolutely no
186*3f982cf4SFabien Sanglardrun-time/space overhead when the program runs. For this reason, a developer need
187*3f982cf4SFabien Sanglardnot explicitly sprinkle "#if OSP_DCHECK_IS_ON()" guards all around any
188*3f982cf4SFabien Sanglardfunctions, variables, etc. that will be unused in "DCHECK off" builds.
189*3f982cf4SFabien Sanglard
190*3f982cf4SFabien SanglardUse OSP_DCHECK and OSP_CHECK in accordance with the
191*3f982cf4SFabien Sanglard[Chromium guidance for DCHECK/CHECK](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++.md#check_dcheck_and-notreached).
192