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