annotate flang/docs/C++style.md @ 207:2e18cbf3894f

LLVM12
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Jun 2021 06:07:14 +0900
parents
children 5f17cb93ff66
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
1 <!--===- docs/C++style.md
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
2
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
3 Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
4 See https://llvm.org/LICENSE.txt for license information.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
5 SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
6
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
7 -->
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
8
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
9 # Flang C++ Style Guide
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
11 ```eval_rst
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
12 .. contents::
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
13 :local:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
14 ```
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
15
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
16 This document captures the style guide rules that are followed in the Flang codebase.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
17
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
18 ## In brief:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
19 * Use *clang-format*
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
20 from llvm 7
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
21 on all C++ source and header files before
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
22 every merge to master. All code layout should be determined
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
23 by means of clang-format.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
24 * Where a clear precedent exists in the project, follow it.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
25 * Otherwise, where [LLVM's C++ style guide](https://llvm.org/docs/CodingStandards.html#style-issues)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
26 is clear on usage, follow it.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
27 * Otherwise, where a good public C++ style guide is relevant and clear,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
28 follow it. [Google's](https://google.github.io/styleguide/cppguide.html)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
29 is pretty good and comes with lots of justifications for its rules.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
30 * Reasonable exceptions to these guidelines can be made.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
31 * Be aware of some workarounds for known issues in older C++ compilers that should
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
32 still be able to compile f18. They are listed at the end of this document.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
33
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
34 ## In particular:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
35
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
36 Use serial commas in comments, error messages, and documentation
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
37 unless they introduce ambiguity.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
38
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
39 ### Error messages
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
40 1. Messages should be a single sentence with few exceptions.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
41 1. Fortran keywords should appear in upper case.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
42 1. Names from the program appear in single quotes.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
43 1. Messages should start with a capital letter.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
44 1. Messages should not end with a period.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
45
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
46 ### Files
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
47 1. File names should use dashes, not underscores. C++ sources have the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
48 extension ".cpp", not ".C" or ".cc" or ".cxx". Don't create needless
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
49 source directory hierarchies.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
50 1. Header files should be idempotent. Use the usual technique:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
51 ```
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
52 #ifndef FORTRAN_header_H_
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
53 #define FORTRAN_header_H_
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
54 // code
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
55 #endif // FORTRAN_header_H_
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
56 ```
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
57 1. `#include` every header defining an entity that your project header or source
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
58 file actually uses directly. (Exception: when foo.cpp starts, as it should,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
59 with `#include "foo.h"`, and foo.h includes bar.h in order to define the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
60 interface to the module foo, you don't have to redundantly `#include "bar.h"`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
61 in foo.cpp.)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
62 1. In the source file "foo.cpp", put its corresponding `#include "foo.h"`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
63 first in the sequence of inclusions.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
64 Then `#include` other project headers in alphabetic order; then C++ standard
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
65 headers, also alphabetically; then C and system headers.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
66 1. Don't use `#include <iostream>`. If you need it for temporary debugging,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
67 remove the inclusion before committing.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
68
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
69 ### Naming
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
70 1. C++ names that correspond to well-known interfaces from the STL, LLVM,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
71 and Fortran standard
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
72 can and should look like their models when the reader can safely assume that
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
73 they mean the same thing -- e.g., `clear()` and `size()` member functions
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
74 in a class that implements an STL-ish container.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
75 Fortran intrinsic function names are conventionally in ALL CAPS.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
76 1. Non-public data members should be named with leading miniscule (lower-case)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
77 letters, internal camelCase capitalization, and a trailing underscore,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
78 e.g. `DoubleEntryBookkeepingSystem myLedger_;`. POD structures with
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
79 only public data members shouldn't use trailing underscores, since they
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
80 don't have class functions from which data members need to be distinguishable.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
81 1. Accessor member functions are named with the non-public data member's name,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
82 less the trailing underscore. Mutator member functions are named `set_...`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
83 and should return `*this`. Don't define accessors or mutators needlessly.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
84 1. Other class functions should be named with leading capital letters,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
85 CamelCase, and no underscores, and, like all functions, should be based
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
86 on imperative verbs, e.g. `HaltAndCatchFire()`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
87 1. It is fine to use short names for local variables with limited scopes,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
88 especially when you can declare them directly in a `for()`/`while()`/`if()`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
89 condition. Otherwise, prefer complete English words to abbreviations
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
90 when creating names.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
91
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
92 ### Commentary
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
93 1. Use `//` for all comments except for short `/*notes*/` within expressions.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
94 1. When `//` follows code on a line, precede it with two spaces.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
95 1. Comments should matter. Assume that the reader knows current C++ at least as
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
96 well as you do and avoid distracting her by calling out usage of new
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
97 features in comments.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
98
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
99 ### Layout
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
100 Always run `clang-format` on your changes before committing code. LLVM
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
101 has a `git-clang-format` script to facilitate running clang-format only
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
102 on the lines that have changed.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
103
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
104 Here's what you can expect to see `clang-format` do:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
105 1. Indent with two spaces.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
106 1. Don't indent public:, protected:, and private:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
107 accessibility labels.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
108 1. Never use more than 80 characters per source line.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
109 1. Don't use tabs.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
110 1. Don't indent the bodies of namespaces, even when nested.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
111 1. Function result types go on the same line as the function and argument
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
112 names.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
113
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
114 Don't try to make columns of variable names or comments
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
115 align vertically -- they are maintenance problems.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
116
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
117 Always wrap the bodies of `if()`, `else`, `while()`, `for()`, `do`, &c.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
118 with braces, even when the body is a single statement or empty. The
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
119 opening `{` goes on
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
120 the end of the line, not on the next line. Functions also put the opening
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
121 `{` after the formal arguments or new-style result type, not on the next
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
122 line. Use `{}` for empty inline constructors and destructors in classes.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
123
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
124 If any branch of an `if`/`else if`/`else` cascade ends with a return statement,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
125 they all should, with the understanding that the cases are all unexceptional.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
126 When testing for an error case that should cause an early return, do so with
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
127 an `if` that doesn't have a following `else`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
128
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
129 Don't waste space on the screen with needless blank lines or elaborate block
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
130 commentary (lines of dashes, boxes of asterisks, &c.). Write code so as to be
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
131 easily read and understood with a minimum of scrolling.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
132
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
133 Avoid using assignments in controlling expressions of `if()` &c., even with
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
134 the idiom of wrapping them with extra parentheses.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
135
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
136 In multi-element initializer lists (especially `common::visitors{...}`),
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
137 including a comma after the last element often causes `clang-format` to do
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
138 a better jobs of formatting.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
139
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
140 ### C++ language
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
141 Use *C++17*, unless some compiler to which we must be portable lacks a feature
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
142 you are considering.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
143 However:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
144 1. Never throw or catch exceptions.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
145 1. Never use run-time type information or `dynamic_cast<>`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
146 1. Never declare static data that executes a constructor.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
147 (This is why `#include <iostream>` is contraindicated.)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
148 1. Use `{braced initializers}` in all circumstances where they work, including
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
149 default data member initialization. They inhibit implicit truncation.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
150 Don't use `= expr` initialization just to effect implicit truncation;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
151 prefer an explicit `static_cast<>`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
152 With C++17, braced initializers work fine with `auto` too.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
153 Sometimes, however, there are better alternatives to empty braces;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
154 e.g., prefer `return std::nullopt;` to `return {};` to make it more clear
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
155 that the function's result type is a `std::optional<>`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
156 1. Avoid unsigned types apart from `size_t`, which must be used with care.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
157 When `int` just obviously works, just use `int`. When you need something
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
158 bigger than `int`, use `std::int64_t` rather than `long` or `long long`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
159 1. Use namespaces to avoid conflicts with client code. Use one top-level
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
160 `Fortran` project namespace. Don't introduce needless nested namespaces within the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
161 project when names don't conflict or better solutions exist. Never use
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
162 `using namespace ...;` outside test code; never use `using namespace std;`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
163 anywhere. Access STL entities with names like `std::unique_ptr<>`,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
164 without a leading `::`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
165 1. Prefer `static` functions over functions in anonymous namespaces in source files.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
166 1. Use `auto` judiciously. When the type of a local variable is known,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
167 monomorphic, and easy to type, be explicit rather than using `auto`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
168 Don't use `auto` functions unless the type of the result of an outlined member
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
169 function definition can be more clear due to its use of types declared in the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
170 class.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
171 1. Use move semantics and smart pointers to make dynamic memory ownership
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
172 clear. Consider reworking any code that uses `malloc()` or a (non-placement)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
173 `operator new`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
174 See the section on Pointers below for some suggested options.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
175 1. When defining argument types, use values when object semantics are
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
176 not required and the value is small and copyable without allocation
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
177 (e.g., `int`);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
178 use `const` or rvalue references for larger values (e.g., `std::string`);
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
179 use `const` references to rather than pointers to immutable objects;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
180 and use non-`const` references for mutable objects, including "output" arguments
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
181 when they can't be function results.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
182 Put such output arguments last (_pace_ the standard C library conventions for `memcpy()` & al.).
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
183 1. Prefer `typename` to `class` in template argument declarations.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
184 1. Prefer `enum class` to plain `enum` wherever `enum class` will work.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
185 We have an `ENUM_CLASS` macro that helps capture the names of constants.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
186 1. Use `constexpr` and `const` generously.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
187 1. When a `switch()` statement's labels do not cover all possible case values
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
188 explicitly, it should contain either a `default:;` at its end or a
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
189 `default:` label that obviously crashes; we have a `CRASH_NO_CASE` macro
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
190 for such situations.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
191 1. On the other hand, when a `switch()` statement really does cover all of
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
192 the values of an `enum class`, please insert a call to the `SWITCH_COVERS_ALL_CASES`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
193 macro at the top of the block. This macro does the right thing for G++ and
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
194 clang to ensure that no warning is emitted when the cases are indeed all covered.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
195 1. When using `std::optional` values, avoid unprotected access to their content.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
196 This is usually by means of `x.has_value()` guarding execution of `*x`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
197 This is implicit when they are function results assigned to local variables
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
198 in `if`/`while` predicates.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
199 When no presence test is obviously protecting a `*x` reference to the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
200 contents, and it is assumed that the contents are present, validate that
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
201 assumption by using `x.value()` instead.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
202 1. We use `c_str()` rather than `data()` when converting a `std::string`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
203 to a `const char *` when the result is expected to be NUL-terminated.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
204 1. Avoid explicit comparisions of pointers to `nullptr` and tests of
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
205 presence of `optional<>` values with `.has_value()` in the predicate
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
206 expressions of control flow statements, but prefer them to implicit
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
207 conversions to `bool` when initializing `bool` variables and arguments,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
208 and to the use of the idiom `!!`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
209
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
210 #### Classes
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
211 1. Define POD structures with `struct`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
212 1. Don't use `this->` in (non-static) member functions, unless forced to
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
213 do so in a template member function.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
214 1. Define accessor and mutator member functions (implicitly) inline in the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
215 class, after constructors and assignments. Don't needlessly define
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
216 (implicit) inline member functions in classes unless they really solve a
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
217 performance problem.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
218 1. Try to make class definitions in headers concise specifications of
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
219 interfaces, at least to the extent that C++ allows.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
220 1. When copy constructors and copy assignment are not necessary,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
221 and move constructors/assignment is present, don't declare them and they
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
222 will be implicitly deleted. When neither copy nor move constructors
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
223 or assignments should exist for a class, explicitly `=delete` all of them.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
224 1. Make single-argument constructors (other than copy and move constructors)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
225 'explicit' unless you really want to define an implicit conversion.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
226
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
227 #### Pointers
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
228 There are many -- perhaps too many -- means of indirect addressing
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
229 data in this project.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
230 Some of these are standard C++ language and library features,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
231 while others are local inventions in `lib/Common`:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
232 * Bare pointers (`Foo *p`): these are obviously nullable, non-owning,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
233 undefined when uninitialized, shallowly copyable, reassignable, and often
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
234 not the right abstraction to use in this project.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
235 But they can be the right choice to represent an optional
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
236 non-owning reference, as in a function result.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
237 Use the `DEREF()` macro to convert a pointer to a reference that isn't
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
238 already protected by an explicit test for null.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
239 * References (`Foo &r`, `const Foo &r`): non-nullable, not owning,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
240 shallowly copyable, and not reassignable.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
241 References are great for invisible indirection to objects whose lifetimes are
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
242 broader than that of the reference.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
243 Take care when initializing a reference with another reference to ensure
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
244 that a copy is not made because only one of the references is `const`;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
245 this is a pernicious C++ language pitfall!
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
246 * Rvalue references (`Foo &&r`): These are non-nullable references
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
247 *with* ownership, and they are ubiquitously used for formal arguments
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
248 wherever appropriate.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
249 * `std::reference_wrapper<>`: non-nullable, not owning, shallowly
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
250 copyable, and (unlike bare references) reassignable, so suitable for
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
251 use in STL containers and for data members in classes that need to be
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
252 copyable or assignable.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
253 * `common::Reference<>`: like `std::reference_wrapper<>`, but also supports
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
254 move semantics, member access, and comparison for equality; suitable for use in
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
255 `std::variant<>`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
256 * `std::unique_ptr<>`: A nullable pointer with ownership, null by default,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
257 not copyable, reassignable.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
258 F18 has a helpful `Deleter<>` class template that makes `unique_ptr<>`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
259 easier to use with forward-referenced data types.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
260 * `std::shared_ptr<>`: A nullable pointer with shared ownership via reference
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
261 counting, null by default, shallowly copyable, reassignable, and slow.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
262 * `Indirection<>`: A non-nullable pointer with ownership and
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
263 optional deep copy semantics; reassignable.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
264 Often better than a reference (due to ownership) or `std::unique_ptr<>`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
265 (due to non-nullability and copyability).
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
266 Can be wrapped in `std::optional<>` when nullability is required.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
267 Usable with forward-referenced data types with some use of `extern template`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
268 in headers and explicit template instantiation in source files.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
269 * `CountedReference<>`: A nullable pointer with shared ownership via
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
270 reference counting, null by default, shallowly copyable, reassignable.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
271 Safe to use *only* when the data are private to just one
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
272 thread of execution.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
273 Used sparingly in place of `std::shared_ptr<>` only when the overhead
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
274 of that standard feature is prohibitive.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
275
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
276 A feature matrix:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
277
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
278 | indirection | nullable | default null | owning | reassignable | copyable | undefined type ok? |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
279 | ----------- | -------- | ------------ | ------ | ------------ | -------- | ------------------ |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
280 | `*p` | yes | no | no | yes | shallowly | yes |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
281 | `&r` | no | n/a | no | no | shallowly | yes |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
282 | `&&r` | no | n/a | yes | no | shallowly | yes |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
283 | `reference_wrapper<>` | no | n/a | no | yes | shallowly | yes |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
284 | `Reference<>` | no | n/a | no | yes | shallowly | yes |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
285 | `unique_ptr<>` | yes | yes | yes | yes | no | yes, with work |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
286 | `shared_ptr<>` | yes | yes | yes | yes | shallowly | no |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
287 | `Indirection<>` | no | n/a | yes | yes | optionally deeply | yes, with work |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
288 | `CountedReference<>` | yes | yes | yes | yes | shallowly | no |
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
289
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
290 ### Overall design preferences
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
291 Don't use dynamic solutions to solve problems that can be solved at
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
292 build time; don't solve build time problems by writing programs that
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
293 produce source code when macros and templates suffice; don't write macros
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
294 when templates suffice. Templates are statically typed, checked by the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
295 compiler, and are (or should be) visible to debuggers.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
296
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
297 ### Exceptions to these guidelines
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
298 Reasonable exceptions will be allowed; these guidelines cannot anticipate
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
299 all situations.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
300 For example, names that come from other sources might be more clear if
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
301 their original spellings are preserved rather than mangled to conform
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
302 needlessly to the conventions here, as Google's C++ style guide does
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
303 in a way that leads to weirdly capitalized abbreviations in names
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
304 like `Http`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
305 Consistency is one of many aspects in the pursuit of clarity,
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
306 but not an end in itself.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
307
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
308 ## C++ compiler bug workarounds
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
309 Below is a list of workarounds for C++ compiler bugs met with f18 that, even
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
310 if the bugs are fixed in latest C++ compiler versions, need to be applied so
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
311 that all desired tool-chains can compile f18.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
312
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
313 ### Explicitly move noncopyable local variable into optional results
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
314
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
315 The following code is legal C++ but fails to compile with the
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
316 default Ubuntu 18.04 g++ compiler (7.4.0-1ubuntu1~18.0.4.1):
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
317
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
318 ```
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
319 class CantBeCopied {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
320 public:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
321 CantBeCopied(const CantBeCopied&) = delete;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
322 CantBeCopied(CantBeCopied&&) = default;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
323 CantBeCopied() {}
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
324 };
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
325 std::optional<CantBeCopied> fooNOK() {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
326 CantBeCopied result;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
327 return result; // Legal C++, but does not compile with Ubuntu 18.04 default g++
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
328 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
329 std::optional<CantBeCopied> fooOK() {
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
330 CantBeCopied result;
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
331 return {std::move(result)}; // Compiles OK everywhere
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
332 }
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
333 ```
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
334 The underlying bug is actually not specific to `std::optional` but this is the most common
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
335 case in f18 where the issue may occur. The actual bug can be reproduced with any class `B`
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
336 that has a perfect forwarding constructor taking `CantBeCopied` as argument:
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
337 `template<typename CantBeCopied> B(CantBeCopied&& x) x_{std::forward<CantBeCopied>(x)} {}`.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
338 In such scenarios, Ubuntu 18.04 g++ fails to instantiate the move constructor
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
339 and to construct the returned value as it should, instead it complains about a
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
340 missing copy constructor.
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
341
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
342 Local result variables do not need to and should not be explicitly moved into optionals
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
343 if they have a copy constructor.