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