2018-05-01 12:50:34 -07:00
|
|
|
<!--
|
2019-02-28 10:48:41 -08:00
|
|
|
Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
2018-05-01 12:50:34 -07:00
|
|
|
-->
|
|
|
|
|
2018-02-05 15:28:17 -08:00
|
|
|
## In brief:
|
2018-05-16 10:22:33 -07:00
|
|
|
* Use *clang-format* on all C++ source and header files before
|
|
|
|
every merge to master. All code layout should be determined
|
|
|
|
by means of clang-format.
|
2019-02-25 10:45:08 -08:00
|
|
|
* Where [LLVM's C++ style guide](https://llvm.org/docs/CodingStandards.html#style-issues)
|
|
|
|
is clear on usage, follow it.
|
2018-02-05 15:28:17 -08:00
|
|
|
* Otherwise, where a clear precedent exists in the project, follow it.
|
|
|
|
* Otherwise, where a good public C++ style guide is relevant and clear,
|
|
|
|
follow it. [Google's](https://google.github.io/styleguide/cppguide.html)
|
|
|
|
is pretty good and comes with lots of justifications for its rules.
|
2018-10-10 16:45:17 -07:00
|
|
|
* Reasonable exceptions to these guidelines can be made.
|
2018-02-05 15:28:17 -08:00
|
|
|
## In particular:
|
|
|
|
### Files
|
|
|
|
1. File names should use dashes, not underscores. C++ sources have the
|
|
|
|
extension ".cc", not ".C" or ".cpp" or ".cxx". Don't create needless
|
|
|
|
source directory hierarchies.
|
2018-02-06 11:14:53 -08:00
|
|
|
1. Header files should be idempotent. Use the usual technique:
|
|
|
|
```
|
|
|
|
#ifndef FORTRAN_header_H_
|
|
|
|
#define FORTRAN_header_H_
|
|
|
|
// code
|
|
|
|
#endif // FORTRAN_header_H_
|
|
|
|
```
|
|
|
|
1. `#include` every header defining an entity that your project header or source
|
2018-02-05 15:39:52 -08:00
|
|
|
file actually uses directly. (Exception: when foo.cc starts, as it should,
|
2018-02-06 11:14:53 -08:00
|
|
|
with `#include "foo.h"`, and foo.h includes bar.h in order to define the
|
|
|
|
interface to the module foo, you don't have to redundantly `#include "bar.h"`
|
2018-02-05 15:39:52 -08:00
|
|
|
in foo.cc.)
|
2018-05-16 10:22:33 -07:00
|
|
|
1. In the source file "foo.cc", put its corresponding `#include "foo.h"`
|
|
|
|
first in the sequence of inclusions.
|
2018-02-06 11:14:53 -08:00
|
|
|
Then `#include` other project headers in alphabetic order; then C++ standard
|
2018-02-05 15:58:22 -08:00
|
|
|
headers, also alphabetically; then C and system headers.
|
2018-05-16 10:22:33 -07:00
|
|
|
1. Don't use `#include <iostream>`. If you need it for temporary debugging,
|
2018-02-05 16:53:38 -08:00
|
|
|
remove the inclusion before committing.
|
2018-02-05 15:28:17 -08:00
|
|
|
### Naming
|
2019-02-28 10:48:41 -08:00
|
|
|
1. C++ names that correspond to well-known interfaces from the STL and LLVM
|
|
|
|
can and should look like their models when the reader can safely assume that
|
|
|
|
they mean the same thing -- e.g., `clear()` and `size()` member functions
|
|
|
|
in a class that implements an STL-ish container.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Non-public data members should be named with leading miniscule (lower-case)
|
|
|
|
letters, internal camelCase capitalization, and a trailing underscore,
|
2018-02-06 11:14:53 -08:00
|
|
|
e.g. `DoubleEntryBookkeepingSystem myLedger_;`. POD structures with
|
2018-02-05 15:28:17 -08:00
|
|
|
only public data members shouldn't use trailing underscores, since they
|
2018-07-25 15:52:58 -07:00
|
|
|
don't have class functions from which data members need to be distinguishable.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Accessor member functions are named with the non-public data member's name,
|
2018-02-06 11:14:53 -08:00
|
|
|
less the trailing underscore. Mutator member functions are named `set_...`
|
|
|
|
and should return `*this`. Don't define accessors or mutators needlessly.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Other class functions should be named with leading capital letters,
|
|
|
|
CamelCase, and no underscores, and, like all functions, should be based
|
2018-02-06 11:14:53 -08:00
|
|
|
on imperative verbs, e.g. `HaltAndCatchFire()`.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. It is fine to use short names for local variables with limited scopes,
|
2018-02-06 11:14:53 -08:00
|
|
|
especially when you can declare them directly in a `for()`/`while()`/`if()`
|
2018-02-05 15:28:17 -08:00
|
|
|
condition. Otherwise, prefer complete English words to abbreviations
|
|
|
|
when creating names.
|
|
|
|
### Commentary
|
2018-02-06 11:14:53 -08:00
|
|
|
1. Use `//` for all comments except for short `/*notes*/` within expressions.
|
|
|
|
1. When `//` follows code on a line, precede it with two spaces.
|
2018-02-05 15:50:42 -08:00
|
|
|
1. Comments should matter. Assume that the reader knows current C++ at least as
|
2018-02-05 15:28:17 -08:00
|
|
|
well as you do and avoid distracting her by calling out usage of new
|
|
|
|
features in comments.
|
|
|
|
### Layout
|
2018-02-06 11:14:53 -08:00
|
|
|
Always run `clang-format` before committing code. Other developers should
|
|
|
|
be able to run `git pull`, then `clang-format`, and see only their own
|
2018-02-05 15:58:22 -08:00
|
|
|
changes.
|
|
|
|
|
2018-02-06 11:14:53 -08:00
|
|
|
Here's what you can expect to see `clang-format` do:
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Indent with two spaces.
|
2018-02-05 15:39:52 -08:00
|
|
|
1. Don't indent public:, protected:, and private:
|
2018-02-05 15:28:17 -08:00
|
|
|
accessibility labels.
|
|
|
|
1. Never use more than 80 characters per source line.
|
|
|
|
1. Don't use tabs.
|
|
|
|
1. Don't indent the bodies of namespaces, even when nested.
|
|
|
|
1. Function result types go on the same line as the function and argument
|
|
|
|
names.
|
|
|
|
|
|
|
|
Don't try to make columns of variable names or comments
|
|
|
|
align vertically -- they are maintenance problems.
|
|
|
|
|
2018-02-06 11:14:53 -08:00
|
|
|
Always wrap the bodies of `if()`, `else`, `while()`, `for()`, `do`, &c.
|
2018-02-05 15:28:17 -08:00
|
|
|
with braces, even when the body is a single statement or empty. The
|
2018-02-06 11:14:53 -08:00
|
|
|
opening `{` goes on
|
2018-02-05 15:28:17 -08:00
|
|
|
the end of the line, not on the next line. Functions also put the opening
|
2018-02-06 11:14:53 -08:00
|
|
|
`{` after the formal arguments or new-style result type, not on the next
|
|
|
|
line. Use `{}` for empty inline constructors and destructors in classes.
|
2018-02-05 15:28:17 -08:00
|
|
|
|
2018-02-28 14:51:45 -08:00
|
|
|
If any branch of an `if`/`else if`/`else` cascade ends with a return statement,
|
|
|
|
they all should, with the understanding that the cases are all unexceptional.
|
|
|
|
When testing for an error case that should cause an early return, do so with
|
|
|
|
an `if` that doesn't have a following `else`.
|
|
|
|
|
2018-02-05 15:28:17 -08:00
|
|
|
Don't waste space on the screen with needless blank lines or elaborate block
|
|
|
|
commentary (lines of dashes, boxes of asterisks, &c.). Write code so as to be
|
|
|
|
easily read and understood with a minimum of scrolling.
|
2018-03-13 17:20:40 -07:00
|
|
|
|
|
|
|
Avoid using assignments in controlling expressions of `if()` &c., even with
|
|
|
|
the idiom of wrapping them with extra parentheses.
|
2018-11-29 09:27:34 -08:00
|
|
|
|
|
|
|
In multi-element initializer lists (especially `common::visitors{...}`),
|
|
|
|
including a comma after the last element often causes `clang-format` to do
|
|
|
|
a better jobs of formatting.
|
2018-02-05 15:28:17 -08:00
|
|
|
### C++ language
|
|
|
|
Use *C++17*, unless some compiler to which we must be portable lacks a feature
|
|
|
|
you are considering.
|
2018-07-25 15:52:58 -07:00
|
|
|
However:
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Never throw or catch exceptions.
|
2018-02-06 11:14:53 -08:00
|
|
|
1. Never use run-time type information or `dynamic_cast<>`.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Never declare static data that executes a constructor.
|
2018-02-06 11:14:53 -08:00
|
|
|
(This is why `#include <iostream>` is contraindicated.)
|
2018-07-25 15:13:40 -07:00
|
|
|
1. Use `{braced initializers}` in all circumstances where they work, including
|
2018-02-05 15:28:17 -08:00
|
|
|
default data member initialization. They inhibit implicit truncation.
|
2018-02-06 11:14:53 -08:00
|
|
|
Don't use `= expr` initialization just to effect implicit truncation;
|
|
|
|
prefer an explicit `static_cast<>`.
|
2018-07-11 10:26:53 -07:00
|
|
|
With C++17, braced initializers work fine with `auto` too.
|
2018-07-25 15:13:40 -07:00
|
|
|
Sometimes, however, there are better alternatives to empty braces;
|
|
|
|
e.g., prefer `return std::nullopt;` to `return {};` to make it more clear
|
|
|
|
that the function's result type is a `std::optional<>`.
|
2018-02-06 11:14:53 -08:00
|
|
|
1. Avoid unsigned types apart from `size_t`, which must be used with care.
|
|
|
|
When `int` just obviously works, just use `int`. When you need something
|
|
|
|
bigger than `int`, use `std::int64_t` rather than `long` or `long long`.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Use namespaces to avoid conflicts with client code. Use one top-level
|
2018-07-25 15:52:58 -07:00
|
|
|
`Fortran` project namespace. Don't introduce needless nested namespaces within the
|
2018-02-05 15:28:17 -08:00
|
|
|
project when names don't conflict or better solutions exist. Never use
|
2018-07-25 15:52:58 -07:00
|
|
|
`using namespace ...;` outside test code; never use `using namespace std;`
|
|
|
|
anywhere. Access STL entities with names like `std::unique_ptr<>`,
|
|
|
|
without a leading `::`.
|
|
|
|
1. Prefer `static` functions over functions in anonymous namespaces in source files.
|
2018-02-06 11:14:53 -08:00
|
|
|
1. Use `auto` judiciously. When the type of a local variable is known,
|
|
|
|
monomorphic, and easy to type, be explicit rather than using `auto`.
|
2018-07-25 15:52:58 -07:00
|
|
|
Don't use `auto` functions unless the type of the result of an outlined member
|
|
|
|
function definition can be more clear due to its use of types declared in the
|
|
|
|
class.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Use move semantics and smart pointers to make dynamic memory ownership
|
2018-02-06 11:14:53 -08:00
|
|
|
clear. Consider reworking any code that uses `malloc()` or a (non-placement)
|
|
|
|
`operator new`.
|
2018-11-01 13:18:28 -07:00
|
|
|
See the section on Pointers below for some suggested options.
|
2018-02-06 11:14:53 -08:00
|
|
|
1. Use references for `const` arguments; prefer `const` references to values for
|
|
|
|
all but small types that are trivially copyable (e.g., use `const std::string &`
|
|
|
|
and `int`). Use non-`const` pointers for output arguments. Put output arguments
|
|
|
|
last (_pace_ the standard C library conventions for `memcpy()` & al.).
|
|
|
|
1. Prefer `typename` to `class` in template argument declarations.
|
|
|
|
1. Prefer `enum class` to plain `enum` wherever `enum class` will work.
|
2018-07-25 15:52:58 -07:00
|
|
|
We have an `ENUM_CLASS` macro that helps capture the names of constants.
|
2018-02-06 11:14:53 -08:00
|
|
|
1. Use `constexpr` and `const` generously.
|
|
|
|
1. When a `switch()` statement's labels do not cover all possible case values
|
2019-02-25 10:45:08 -08:00
|
|
|
explicitly, it should contain either a `default:;` at its end or a
|
2018-07-25 15:52:58 -07:00
|
|
|
`default:` label that obviously crashes; we have a `CRASH_NO_CASE` macro
|
|
|
|
for such situations.
|
2018-12-05 13:03:39 -08:00
|
|
|
1. When using `std::optional` values, avoid unprotected access to their content.
|
|
|
|
This is usually by means of `x.has_value()` guarding execution of `*x`.
|
|
|
|
This is implicit when they are function results assigned to local variables
|
|
|
|
in `if`/`while` predicates.
|
|
|
|
When no presence test is obviously protecting a `*x` reference to the
|
|
|
|
contents, and it is assumed that the contents are present, validate that
|
|
|
|
assumption by using `x.value()` instead.
|
2018-02-05 15:28:17 -08:00
|
|
|
#### Classes
|
2018-04-03 14:14:39 -07:00
|
|
|
1. Define POD structures with `struct`.
|
2018-07-25 15:13:40 -07:00
|
|
|
1. Don't use `this->` in (non-static) member functions, unless forced to
|
2018-07-25 15:52:58 -07:00
|
|
|
do so in a template member function.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Define accessor and mutator member functions (implicitly) inline in the
|
|
|
|
class, after constructors and assignments. Don't needlessly define
|
|
|
|
(implicit) inline member functions in classes unless they really solve a
|
|
|
|
performance problem.
|
|
|
|
1. Try to make class definitions in headers concise specifications of
|
|
|
|
interfaces, at least to the extent that C++ allows.
|
|
|
|
1. When copy constructors and copy assignment are not necessary,
|
|
|
|
and move constructors/assignment is present, don't declare them and they
|
|
|
|
will be implicitly deleted. When neither copy nor move constructors
|
2018-02-06 11:14:53 -08:00
|
|
|
or assignments should exist for a class, explicitly `=delete` all of them.
|
2018-02-05 15:28:17 -08:00
|
|
|
1. Make single-argument constructors (other than copy and move constructors)
|
2018-07-25 15:52:58 -07:00
|
|
|
'explicit' unless you really want to define an implicit conversion.
|
2018-11-01 13:18:28 -07:00
|
|
|
#### Pointers
|
2018-11-01 13:43:24 -07:00
|
|
|
There are many -- perhaps too many -- means of indirect addressing
|
|
|
|
data in this project.
|
|
|
|
Some of these are standard C++ language and library features,
|
|
|
|
while others are local inventions in `lib/common`:
|
2018-11-02 10:48:20 -07:00
|
|
|
* Bare pointers (`Foo *p`): these are obviously nullable, non-owning,
|
|
|
|
undefined when uninitialized, shallowly copyable, reassignable, and almost
|
|
|
|
never the right abstraction to use in this project.
|
|
|
|
* References (`Foo &r`, `const Foo &r`): non-nullable, not owning,
|
|
|
|
shallowly copyable, and not reassignable.
|
2018-11-01 13:18:28 -07:00
|
|
|
References are great for invisible indirection to objects whose lifetimes are
|
|
|
|
broader than that of the reference.
|
2018-11-02 10:48:20 -07:00
|
|
|
(Sometimes when a class data member should be a reference, but we also need
|
|
|
|
reassignability, it will be declared as a pointer, and its accessor
|
|
|
|
will be defined to return a reference.)
|
2018-11-01 13:18:28 -07:00
|
|
|
* Rvalue references (`Foo &&r`): These are non-nullable references
|
2018-11-01 13:43:24 -07:00
|
|
|
*with* ownership, and they are ubiquitously used for formal arguments
|
2018-11-01 13:18:28 -07:00
|
|
|
wherever appropriate.
|
2018-11-02 10:48:20 -07:00
|
|
|
* `std::unique_ptr<>`: A nullable pointer with ownership, null by default,
|
|
|
|
not copyable, reassignable.
|
2018-11-01 13:18:28 -07:00
|
|
|
* `std::shared_ptr<>`: A nullable pointer with shared ownership via reference
|
2018-11-02 10:48:20 -07:00
|
|
|
counting, null by default, shallowly copyable, reassignable, and slow.
|
2018-11-01 13:18:28 -07:00
|
|
|
* `OwningPointer<>`: A nullable pointer with ownership, better suited
|
|
|
|
for use with forward-defined types than `std::unique_ptr<>` is.
|
2019-03-04 11:23:50 -08:00
|
|
|
Null by default, optionally copyable, reassignable.
|
|
|
|
Does not have direct means for allocating data, and inconveniently requires
|
2018-11-01 13:43:24 -07:00
|
|
|
the definition of an external destructor.
|
|
|
|
* `Indirection<>`: A non-nullable pointer with ownership and
|
2018-11-02 10:48:20 -07:00
|
|
|
optional deep copy semantics; reassignable.
|
2018-11-01 13:43:24 -07:00
|
|
|
Often better than a reference (due to ownership) or `std::unique_ptr<>`
|
2018-11-01 15:06:01 -07:00
|
|
|
(due to non-nullability and copyability).
|
2018-11-02 14:48:28 -07:00
|
|
|
Can be wrapped in `std::optional<>` when nullability is required.
|
2019-03-04 15:15:08 -08:00
|
|
|
* `ForwardReference<>`: A non-nullable `OwningPointer<>`, or a variant of
|
|
|
|
`Indirection<>` that works with forward-declared content types; it's both.
|
2018-11-01 13:18:28 -07:00
|
|
|
* `CountedReference<>`: A nullable pointer with shared ownership via
|
2018-11-02 10:48:20 -07:00
|
|
|
reference counting, null by default, shallowly copyable, reassignable.
|
|
|
|
Safe to use *only* when the data are private to just one
|
2018-11-01 13:43:24 -07:00
|
|
|
thread of execution.
|
2018-11-02 10:48:20 -07:00
|
|
|
Used sparingly in place of `std::shared_ptr<>` only when the overhead
|
2018-11-01 13:43:24 -07:00
|
|
|
of that standard feature is prohibitive.
|
2018-11-02 14:38:27 -07:00
|
|
|
|
|
|
|
A feature matrix:
|
|
|
|
|
2018-11-14 14:35:10 -08:00
|
|
|
| pointer | nullable | default null | owning | reassignable | copyable | undefined type ok? |
|
|
|
|
| ------- | -------- | ------------ | ------ | ------------ | -------- | ------------------ |
|
|
|
|
| `*p` | yes | no | no | yes | shallowly | yes |
|
|
|
|
| `&r` | no | n/a | no | no | shallowly | yes |
|
|
|
|
| `unique_ptr<>` | yes | yes | yes | yes | no | no |
|
|
|
|
| `shared_ptr<>` | yes | yes | yes | yes | shallowly | no |
|
2019-03-04 11:23:50 -08:00
|
|
|
| `OwningPointer<>` | yes | yes | yes | yes | optionally deeply | yes |
|
2018-11-14 14:35:10 -08:00
|
|
|
| `Indirection<>` | no | n/a | yes | yes | optionally deeply | no |
|
2019-03-04 15:15:08 -08:00
|
|
|
| `ForwardReference<>` | no | n/a | yes | yes | optionally deeply | yes |
|
2018-11-14 14:35:10 -08:00
|
|
|
| `CountedReference<>` | yes | yes | yes | yes | shallowly | no |
|
2018-11-02 14:38:27 -07:00
|
|
|
|
2018-11-01 13:18:28 -07:00
|
|
|
### Overall design preferences
|
2018-02-05 15:28:17 -08:00
|
|
|
Don't use dynamic solutions to solve problems that can be solved at
|
|
|
|
build time; don't solve build time problems by writing programs that
|
|
|
|
produce source code when macros and templates suffice; don't write macros
|
|
|
|
when templates suffice. Templates are statically typed, checked by the
|
2018-02-05 15:43:46 -08:00
|
|
|
compiler, and are (or should be) visible to debuggers.
|
2018-10-10 16:45:17 -07:00
|
|
|
### Exceptions to these guidelines
|
|
|
|
Reasonable exceptions will be allowed; these guidelines cannot anticipate
|
|
|
|
all situations.
|
|
|
|
For example, names that come from other sources might be more clear if
|
|
|
|
their original spellings are preserved rather than mangled to conform
|
|
|
|
needlessly to the conventions here, as Google's C++ style guide does
|
|
|
|
in a way that leads to weirdly capitalized abbreviations in names
|
|
|
|
like `Http`.
|
|
|
|
Consistency is one of many aspects in the pursuit of clarity,
|
|
|
|
but not an end in itself.
|