cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / CONTRIBUTING.adoc
index 11a3fe4ca045d312fe8b32c1486e6daf4fccca7c..171fcb14a6b41eb991f9d3f0569738e69105aeb5 100644 (file)
@@ -2,10 +2,15 @@
 
 = Babeltrace{nbsp}2 contributor's guide
 Jérémie Galarneau, Philippe Proulx
-19 November 2020
+22 February 2024
 :toc: left
 :toclevels: 3
+:icons: font
+:nofooter:
 :bt2: Babeltrace{nbsp}2
+:c-cpp: C/{cpp}
+:cpp11: {cpp}11
+:fmt: pass:[{fmt}]
 
 This is a partial contributor's guide for the
 https://babeltrace.org[{bt2}] project. If you have any
@@ -254,7 +259,7 @@ the `LIBBABELTRACE2_INIT_LOG_LEVEL` environment variable.
 
 This API is based on https://github.com/wonder-mice/zf_log[zf_log], a
 lightweight, yet featureful, MIT-licensed core logging library for C and
-pass:[C++]. The zf_log source files were modified to have the `BT_` and
+{cpp}. The zf_log source files were modified to have the `BT_` and
 `bt_` prefixes, and other small changes, like color support and using
 the project's `BT_DEBUG_MODE` definition instead of the standard
 `NDEBUG`.
@@ -435,7 +440,6 @@ level, for example:
 +
 [source,c]
 ----
-BT_HIDDEN
 char *bt_common_get_home_plugin_path(int log_level);
 ----
 +
@@ -581,10 +585,6 @@ of `+BT_LOG*()+`:
     Library error logging statement, and unconditional error cause
     appending.
 
-`+BT_LIB_LOGF_APPEND_CAUSE("format string", ...)+`::
-    Library fatal logging statement, and unconditional error cause
-    appending.
-
 The macros above accept the typical `printf()` conversion specifiers
 with the following limitations:
 
@@ -937,9 +937,9 @@ BT_LOGD("Bla bla: number=%d", get_number_of_event_classes_with_property_x(...));
 === Guides
 
 [[logging-instrument-c-file-gen]]
-==== Instrument a C source file (generic)
+==== Instrument a {c-cpp} source file (generic)
 
-To instrument a C source file (`.c`):
+To instrument a {c-cpp} source file (`.c`/`.cpp`):
 
 . At the top of the file, before the first `#include` line (if any),
   define your file's <<choose-a-logging-tag,logging tag>> name:
@@ -987,10 +987,10 @@ Examples:
   <<gen-logging-statements,generic logging statement macros>>.
 
 [[logging-instrument-h-file-gen]]
-==== Instrument a C header file (generic)
+==== Instrument a {c-cpp} header file (generic)
 
-To instrument a C header file (`.h`), if you have `static inline`
-functions in it:
+To instrument a {c-cpp} header file (`.h`/`.hpp`), if you have
+`static inline` functions in it:
 
 . Do not include `"logging/log.h"`!
 
@@ -1021,8 +1021,8 @@ int some_function(int x)
 }
 ----
 +
-The C source files which include this header file determine if logging
-is enabled or not for them, and if so, what is their
+The {c-cpp} source files which include this header file determine if
+logging is enabled or not for them, and if so, what is their
 <<choose-a-logging-tag,logging tag>> and <<run-time-log-level,run-time
 log level>> expression.
 
@@ -1040,9 +1040,9 @@ Then, in the file, instrument your code with the
 <<gen-logging-statements,generic logging statement macros>>.
 
 [[logging-instrument-c-file-lib]]
-==== Instrument a library C source file
+==== Instrument a library {c-cpp} source file
 
-To instrument a library C source file (`.c`):
+To instrument a library {c-cpp} source file (`.c`/`.cpp`):
 
 . At the top of the file, before the first `#include` line (if any),
   define your file's <<choose-a-logging-tag,logging tag>> name (this
@@ -1067,10 +1067,10 @@ To instrument a library C source file (`.c`):
   the <<gen-logging-statements,generic logging statement macros>>.
 
 [[logging-instrument-h-file-lib]]
-==== Instrument a library C header file
+==== Instrument a library {c-cpp} header file
 
-To instrument a library C header file (`.h`), if you have `static
-inline` functions in it:
+To instrument a library {c-cpp} header file (`.h`/`.hpp`), if you have
+`static inline` functions in it:
 
 . Do not include `"lib/logging.h"`!
 
@@ -1089,9 +1089,9 @@ inline` functions in it:
   the <<gen-logging-statements,generic logging statement macros>>.
 
 [[logging-instrument-c-file-compcls]]
-==== Instrument a component class C source file
+==== Instrument a component class {c-cpp} source file
 
-To instrument a component class C source file (`.c`):
+To instrument a component class {c-cpp} source file (`.c`/`.cpp`):
 
 . At the top of the file, before the first `#include` line (if any),
   define your file's <<choose-a-logging-tag,logging tag>> name (this tag
@@ -1148,7 +1148,6 @@ struct my_comp {
     /* ... */
 };
 
-BT_HIDDEN
 bt_self_component_status my_comp_init(
         bt_self_component_source *self_comp_src,
         bt_value *params, void *init_method_data)
@@ -1169,10 +1168,10 @@ bt_self_component_status my_comp_init(
   <<comp-logging-statements,component logging statement macros>>.
 
 [[logging-instrument-h-file-compcls]]
-==== Instrument a component class C header file
+==== Instrument a component class {c-cpp} header file
 
-To instrument a component class C header file (`.h`), if you have
-`static inline` functions in it:
+To instrument a component class {c-cpp} header file (`.h`/`.hpp`), if
+you have `static inline` functions in it:
 
 . Do not include `"logging/comp-logging.h"`!
 
@@ -1192,9 +1191,9 @@ To instrument a component class C header file (`.h`), if you have
 [[choose-a-logging-tag]]
 ==== Choose a logging tag
 
-Each logging-enabled C source file must define `BT_LOG_TAG` to a logging
-tag. A logging tag is a namespace to identify the logging messages of
-this specific source file.
+Each logging-enabled {c-cpp} source file must define `BT_LOG_TAG` to a
+logging tag. A logging tag is a namespace to identify the logging
+messages of this specific source file.
 
 In general, a logging tag name _must_ be only uppercase letters, digits,
 and the `-`, `.`, and `/` characters.
@@ -1486,34 +1485,32 @@ backtrace when Valgrind shows errors.
 [[test-env]]
 === Environment
 
-`tests/utils/utils.sh` sets the environment variables for any {bt2}
-test script.
+Running `make check` in the build directory (regardless of whether the build is
+in-tree or out-of-tree) automatically sets up the appropriate environment for
+tests to run in, so nothing more is needed.
+
+If building in-tree, you can run single tests from the tree directly:
 
-`utils.sh` only needs to know the path to the `tests` directory within
-the source and the build directories. By default, `utils.sh` assumes the
-build is in tree, that is, you ran `./configure` from the source's root
-directory, and sets the `BT_TESTS_SRCDIR` and `BT_TESTS_BUILDDIR`
-environment variables accordingly. You can override those variables, for
-example if you build out of tree.
+----
+$ ./tests/plugins/sink.text.pretty/test-enum.sh
+----
 
-All test scripts eventually do something like this to source `utils.sh`,
-according to where they are located relative to the `tests` directory:
+If building out-of-tree, you can get the appropriate environment by sourcing
+the `tests/utils/env.sh` file residing in the build directory against which you
+want to run tests.
 
-[source,bash]
 ----
-if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
-    UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
-else
-    UTILSSH="$(dirname "$0")/../utils/utils.sh"
-fi
+$ source /path/to/my/build/tests/utils/env.sh
+$ ./tests/plugins/sink.text.pretty/test-enum.sh
 ----
 
 ==== Python
 
-You can use the `tests/utils/run_python_bt2` script to run any command
-within an environment making the build's `bt2` Python package available.
+You can use the `tests/utils/run-in-py-env.sh` script to run any command
+within an environment making the build's `bt2` Python package available,
+as well as the testing utility Python modules.
 
-`run_python_bt2` uses <<test-env,`utils.sh`>> which needs to know the
+`run-in-py-env.sh` uses <<test-env,`utils.sh`>> which needs to know the
 build directory, so make sure you set the `BT_TESTS_BUILDDIR`
 environment variable correctly _if you build out of tree_, for example:
 
@@ -1522,10 +1519,10 @@ $ export BT_TESTS_BUILDDIR=/path/to/build/babeltrace/tests
 ----
 
 You can run any command which needs the `bt2` Python package through
-`run_python_bt2`, for example:
+`run-in-py-env.sh`, for example:
 
 ----
-$ ./tests/utils/run_python_bt2 ipython3
+$ ./tests/utils/run-in-py-env.sh ipython3
 ----
 
 === Report format
@@ -1571,13 +1568,13 @@ To run all the `bt2` Python package tests:
 * Run:
 +
 ----
-$ ./tests/utils/run_python_bt2 ./tests/bindings/python/bt2/test_python_bt2
+$ ./tests/utils/run-in-py-env.sh ./tests/bindings/python/bt2/test-python-bt2.sh
 ----
 +
 or:
 +
 ----
-$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \
+$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \
   ./tests/bindings/python/bt2/ -p '*.py'
 ----
 
@@ -1587,7 +1584,7 @@ To run **all the tests** in a test module (for example,
 * Run:
 +
 ----
-$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \
+$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \
   ./tests/bindings/python/bt2 -t test_value
 ----
 
@@ -1597,7 +1594,7 @@ To run a **specific test case** (for example, `RealValueTestCase` within
 * Run:
 +
 ----
-$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \
+$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \
   ./tests/bindings/python/bt2/ -t test_value.RealValueTestCase
 ----
 
@@ -1607,6 +1604,702 @@ To run a **specific test** (for example,
 * Run:
 +
 ----
-$ ./tests/utils/run_python_bt2 python3 ./tests/utils/python/testrunner.py \
+$ ./tests/utils/run-in-py-env.sh python3 ./tests/utils/python/testrunner.py \
   ./tests/bindings/python/bt2/ -t test_value.RealValueTestCase.test_assign_pos_int
 ----
+
+== {cpp} usage
+
+A significant part and, in general, all the new code of {bt2} is written
+in {cpp}.
+
+This section shows what's important to know about {cpp} to contribute
+to {bt2}.
+
+[IMPORTANT]
+====
+{bt2} only has {cpp} sources for _internal_ code.
+
+In other words, libbabeltrace2 _must_ expose a pure C99 API to preserve
+ABI compatibility over time.
+====
+
+=== Standard
+
+The {bt2} project is configured to use the {cpp11} standard.
+
+{cpp11} makes it possible to build {bt2} with a broad range of
+compilers, from GCC{nbsp}4.8 and Clang{nbsp}3.3.
+
+=== Common {cpp} code
+
+Many parts of the project need common {cpp} code. You'll find all of it
+under `src/cpp-common`.
+
+In general, anything under a namespace named `internal` is internal to
+the API containing it. For example, everything under the `bt2::internal`
+namespace is internal to the `bt2` namespace and therefore isn't meant
+to be used outside the `src/cpp-common/bt2` directory.
+
+==== `bt2`: libbabeltrace2 {cpp} bindings
+
+`src/cpp-common/bt2` contains our internal {cpp} bindings of
+the libbabeltrace2 C{nbsp}API, under the `bt2` namespace.
+
+Those bindings are designed to have, as much as possible, no performance
+impact. Anything which inherits `bt2::BorrowedObject` contains a single
+libbabeltrace2 object pointer.
+
+Pass and return borrowed objects _by value_ (copy).
+
+In general, the following holds:
+
+[options="header,autowidth",cols="2"]
+|===
+|{cpp} expression
+|Equivalent C{nbsp}expression
+
+|`bt2::Xyz`
+|`bt_xyz *`
+
+|`const bt2::Xyz`
+|`bt_xyz * const`
+
+|`bt2::ConstXyz`
+|`const bt_xyz *`
+
+|`const bt2::ConstXyz`
+|`const bt_xyz * const`
+|===
+
+==== `bt2c`: general common {cpp} code
+
+Similar to the role of `src/common` for C code.
+
+In general, everything in here is under the `bt2c` namespace.
+
+Notable files are:
+
+`align.hpp`::
+    The `bt2c::align()` function template: a wrapper of
+    `src/common/align.h`.
+
+`c-string-view.hpp`::
+    The `bt2c::CStringView` class: a view on a constant null-terminated
+    C{nbsp}string.
++
+We have this because `bt2s::string_view` doesn't imply null termination,
+only a beginning and a length.
++
+A `bt2c::CStringView` instance is convertible to `const char *` and may
+be empty (the underlying pointer is null).
+
+`call.hpp`::
+    The `bt2c::call()` function template: a partial implementation of
+    https://en.cppreference.com/w/cpp/utility/functional[INVOKE].
++
+We use this mostly to assign the result of calling an immediately
+invoked function expression (lambda) to an `auto` variable without
+risking to assign the lambda itself, should we forget the calling
+parentheses:
++
+[source,cpp]
+----
+const auto res = bt2c::call([&] {
+    /* Complex initialization */
+});
+----
+
+`endian.hpp`::
+    Typed wrappers of `src/compat/endian.h`.
+
+`exc.hpp`::
+    Common exception classes.
+
+`fmt.hpp`::
+    Common https://fmt.dev/[{fmt}] formatters.
+
+`logging.hpp`::
+    The `bt2c::Logger` class and helper `BT_CPPLOG*()` macros for any
+    {cpp} logging.
++
+When possible, prefer using this over the C{nbsp}logging API.
++
+One important benefit is that this API uses {fmt} to format the logging
+message instead of `vsnprintf()`.
+
+`make-span.hpp`::
+    The function template `bt2c::makeSpan()` which is an alternative to
+    https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[CTAD]
+    (a {cpp}17 feature).
+
+`prio-heap.hpp`::
+    The `bt2c::PrioHeap` class template: an efficient heap data
+    structure.
+
+`read-fixed-len-int.hpp`::
+    The function templates `bt2c::readFixedLenInt()`,
+    `bt2c::readFixedLenIntLe()`, and `bt2c::readFixedLenIntBe()`: read a
+    fixed-length integer from a byte buffer.
+
+`safe-ops.hpp`::
+    The `bt2c::safe*()` function templates: arithmetic operations which
+    assert that there's no possible overflow.
+
+`std-int.hpp`::
+    The `bt2c::StdIntT` type alias template: becomes one of the
+    `std::*int*_t` types depending on its parameters.
++
+For example, `bt2c::StdIntT<32, true>` is `std::int32_t`.
+
+`type-traits.hpp`::
+    Common type traits.
+
+`uuid.hpp`::
+    The following classes:
+
+`bt2c::Uuid`:::
+    Container of a 16-byte
+    https://en.wikipedia.org/wiki/Universally_unique_identifier[UUID].
++
+Provides the static `generate()` method as well as conversion to
+`bt2c::UuidView`.
+
+`bt2c::UuidView`:::
+    View on a UUID (not a container).
++
+Provides byte access, comparison, as well as string conversion methods.
++
+Also provides conversion to `bt2c::Uuid`.
+
+`vector.hpp`::
+    The `bt2c::vectorFastRemove()` function template: remove an element
+    from an `std::vector` instance quickly when the order isn't
+    important.
+
+==== `bt2s`: drop-in replacements of {cpp}14 to {cpp}20 STL features
+
+Everything under the `bt2s` namespace has its equivalent under the `std`
+namespace, but in {cpp} versions we don't yet have access to, namely:
+
+`make-unique.hpp`::
+    `bt2s::make_unique()`, a drop-in replacement of `std::make_unique()`
+    ({cpp}14).
+
+`optional.hpp`::
+    Drop-in replacement of the `std::optional` API ({cpp}17).
+
+`span.hpp`::
+    Drop-in replacement of the `std::span` API ({cpp}20).
+
+`string-view.hpp`::
+    Drop-in replacement of the `std::string_view` API ({cpp}17).
+
+==== `vendor`: copies of {cpp} dependencies
+
+This directory contains copies of the source code of {cpp} dependencies
+to avoid packaging issues.
+
+They are:
+
+`fmt`::
+    https://fmt.dev/[{fmt}].
+
+`nlohmann`::
+    https://json.nlohmann.me/[JSON for Modern C++].
+
+`optional-lite`::
+    https://github.com/martinmoene/optional-lite[optional lite].
++
+IMPORTANT: Use the symbols of `src/cpp-common/bt2s/optional.hpp`, under
+the `bt2s` namespace, instead of using this directly.
+
+`span-lite`::
+    https://github.com/martinmoene/span-lite[span lite].
++
+IMPORTANT: Use the symbols of `src/cpp-common/bt2s/span.hpp`, under the
+`bt2s` namespace, instead of using this directly.
++
+TIP: `src/cpp-common/bt2c/make-span.hpp` offers `bt2c::makeSpan()` which
+is an alternative to
+https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[CTAD]
+(a {cpp}17 feature).
+
+`string-view-lite`::
+    https://github.com/martinmoene/string-view-lite[string_view lite].
++
+IMPORTANT: Use the symbols of `src/cpp-common/bt2s/string-view.hpp`,
+under the `bt2s` namespace, instead of using this directly.
+
+`wise_enum`::
+    https://github.com/quicknir/wise_enum[wise_enum].
+
+=== Automake/Libtool requirements
+
+To add a {cpp} source file to a part of the project, use the `.cpp`
+extension and add it to the list of source files in `Makefile.am` as
+usual.
+
+If a program or a shared library has a direct {cpp} source file, then
+Libtool uses the {cpp} linker to create the result, dynamically
+linking important runtime libraries such as libstdc++ and libgcc_s.
+
+Because a Libtool _convenience library_ is just an archive (`.a`), it's
+_not_ dynamically linked to runtime libraries, even if one of its direct
+sources is a {cpp} file. This means that for each program or shared
+library named `my_target` in `Makefile.am` which is linked to a
+convenience library having {cpp} sources (recursively), you _must_ do
+one of:
+
+* Have at least one direct {cpp} source file in the
+  `+*_my_target_SOURCES+` list.
+
+* Add:
++
+----
+nodist_EXTRA_my_target_SOURCES = dummy.cpp
+----
++
+See
+https://www.gnu.org/software/automake/manual/automake.html#Libtool-Convenience-Libraries[Libtool
+Convenience Libraries] to learn more.
+
+For a given program or library, you _cannot_ have a C{nbsp}file and a
+{cpp}{nbsp}file having the same name, for example `list.c` and
+`list.cpp`.
+
+=== Coding style
+
+==== Whitespaces, indentation, and line breaks
+
+All the project's {cpp} files follow the
+https://clang.llvm.org/docs/ClangFormat.html[clang-format]
+https://clang.llvm.org/docs/ClangFormatStyleOptions.html[style] of the
+`.clang-format` file for whitespaces, indentation, and line breaks.
+
+You _must_ format modified and new {cpp} files with clang-format before
+you create a contribution patch.
+
+You need clang-format{nbsp}15 to use the project's `.clang-format` file.
+
+To automatically format all the project's {cpp} files, run:
+
+----
+$ ./tools/format-cpp.sh
+----
+
+To only format the {cpp} files of a given directory:
+
+----
+$ ./tools/format-cpp.sh ./src/cli
+----
+
+Use the `FORMATTER` environment variable to override the default
+formatter (`clang-format{nbsp}-i`):
+
+----
+$ FORMATTER='my-clang-format-15 -i' ./tools/format-cpp.sh
+----
+
+==== Naming
+
+* Use camel case with a lowercase first letter for:
+** Variable names: `size`, `objSize`.
+** Function/method names: `size()`, `formatAndPrint()`.
+
+* Use camel case with an uppercase first letter for:
+** Types: `Pistachio`, `NutManager`.
+** Template parameters: `PlanetT`, `TotalSize`.
+** Enumerators: `Type::SignedInt`, `Scope::Function`.
+
+* Use snake case with uppercase letters for:
+** Definition/macro names: `MARK_AS_UNUSED()`, `SOME_FEATURE_EXISTS`.
+
+* Use only lowercase letters and digits for namespaces: `mylib`, `bt2`.
+
+* Use the `T` suffix for type template parameters and the `V` suffix for
+  non-type template parameters:
++
+[source,cpp]
+----
+template <typename NameT, typename ItemT, unsigned int SizeV = 0>
+----
+
+* Name a template parameter pack `ArgTs`.
++
+[source,cpp]
+----
+template <typename NameT, typename... ArgTs>
+----
+
+* Use an underscore prefix for private and protected methods and member
+  type names: `_tryConnect()`, `_NodeType`.
+
+* Use the prefix `_m` for private and protected member variable names:
+  `_mLogger`, `_mSize`, `_mFieldClass`.
++
+This is to avoid name clashes with private/protected getters/setters.
+
+* Name setters and getters like the property name, without the `set` and
+  `get` prefixes.
+
+* Use the `is` or `has` prefix, if possible, to name the functions which
+  return `bool`.
++
+However, try to keep the name readable. For example, prefer
+`colorIsBlue()` over `isColorBlue()`.
+
+=== Coding convention
+
+In general, the project's contributors make an effort to follow,
+for {cpp11} code:
+
+* The
+  https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md[{cpp} Core Guidelines].
+
+* Scott Meyers's
+  "`https://www.oreilly.com/library/view/effective-modern-c/9781491908419/[Effective Modern {cpp}]`".
+
+Here are a few important reminders:
+
+* Namespace your code.
+
+* Create one header/source file pair per class when possible.
++
+For a class named `MyClass`, name the corresponding files `my-class.hpp`
+and `my-class.cpp`.
+
+* Use the `inline` keyword, not `static inline`, for header-only
+  functions that are not templates.
+
+* When defining a class, use this order:
++
+--
+. Friends (without any preceding access specifier).
+
+. Public types and type aliases.
++
+Private/protected types may be here too if they can't be lower.
+
+. Constructors, whatever their access.
+
+. Destructor (always public).
+
+. Copy-assignment and move-assignment operators.
+
+. Public methods.
+
+. Protected types and type aliases.
+
+. Protected methods.
+
+. Private types and type aliases.
+
+. Private methods.
+
+. Protected data members.
+
+. Private data members.
+--
+
+* Declare variables as close to where they're used as possible.
+
+* In general, try to avoid variables if it doesn't lead to more lines.
++
+For example, given:
++
+[source,cpp]
+----
+const auto size = getSize(myObj, 23);
+auto& obj = this->_objForSize(size);
+
+abc::sendObj(obj, SendOpts::WAIT);
+----
++
+Prefer this:
++
+[source,cpp]
+----
+abc::sendObj(this->_objForSize(getSize(myObj, 23)), SendOpts::WAIT);
+----
+
+* If you really need variables, then scope them to avoid "`leaking`"
+  them:
++
+[source,cpp]
+----
+doSomeStuff(123, &obj);
+
+{
+    const auto status = tryChange(obj);
+
+    BT_CPPLOGD("New status: {}.", status);
+    BT_ASSERT(status == Status::CONTINUE);
+}
+
+doMoreStuff(&obj);
+----
++
+This also means to either use a dedicated, named method/function or to
+use `bt2c::call()` with an immediately invoked function expression
+(lambda) to perform complex initialization of an ideally `const`
+variable:
++
+[source,cpp]
+----
+const auto size = bt2c::call([this] {
+    auto& sender = this->_curSender();
+
+    if (sender.strategy() == Strategy::ACK) {
+        return sender.strategySize();
+    } else if (sender.strategy() == Strategy::NACK) {
+        return 0;
+    }
+
+    return _mDefSize;
+});
+----
+
+* Always use `bt2c::call()` to call an immediately invoked function
+  expression (see the previous point).
+
+* If possible, initialize object members without a default value with
+  the initializer list of a constructor, not in the constructor body.
++
+If the initialization is complex, either use a dedicated, named
+method/function or `bt2c::call()` with an immediately invoked function
+expression (lambda):
++
+[source,cpp]
+----
+MyObj::MyObj(const std::size_t size) :
+    _mSize {size},
+    _mOtherObj {bt2c::call([size] {
+        /* Complex initialization here */
+    })}
+{
+}
+----
+
+* Use `auto` when possible.
++
+Use `auto&` instead of `const auto&` when you know that the type is
+`const` anyway.
++
+Don't use `auto *`.
+
+* Use `const` as much as possible, even for pointers
+  (`+const char * const+`) and numeric values (`const unsigned int`)
+  which never need to change.
+
+* Prefer the `pass:[MyObj myObj {...}]` initialization form over
+  `pass:[auto myObj = MyObj {...}]`.
+
+* Implement simple setters, getters, and one-liners in header files and
+  everything else that's not a template in source files, including
+  constructors.
+
+* Make methods `const noexcept` or `const` as much as possible.
+
+* Make constructors `explicit` unless you really need an implicit
+  constructor (which is rare), including default constructors:
++
+[source,cpp]
+----
+explicit Meow();
+----
+
+* Use `std::unique_ptr` to manage memory when possible.
++
+However, use references (`+*my_unique_ptr+`) and raw pointers
+(`+my_unique_ptr.get()+`) when not transferring ownership.
+
+* Use `nullptr`, not `NULL` nor 0.
+
+* Return by value (rvalue) instead of by output parameter (non-const
+  lvalue reference), even complex objects, unless you can prove that the
+  performance is improved when returning by parameter.
+
+* For a function parameter or a return value of which the type needs to
+  be a reference or pointer, use:
++
+If the value is mandatory:::
+    A reference.
+If the value is optional:::
+    A raw pointer.
+
+* Don't use `+std::move()+` when you already have an rvalue, which
+  means:
+** Don't write `+return std::move(...);+` as this can interfere with
+   RVO.
+** Don't use `+std::move()+` with a function call
+   (`+std::move(func())+`).
+
+* For each possible move/copy constructor or assignment operator, do one
+  of:
+** Write a custom one.
+** Mark it as defaulted (`default`)
+** Mark it as deleted (`delete`).
+
+* Use scoped enumerations (`+enum class+`).
+
+* Mark classes known to be final with the `final` keyword.
+
+* Use type aliases (`using`), not type definitions (`typedef`).
+
+* In a `.cpp` file, use anonymous namespaces for local symbols instead
+  of `static` or `inline`.
+
+* Prefer a function in an anonymous namespace in a `.cpp` file over a
+  private static method if it doesn't need private access to an object.
+
+* Don't pollute the global namespace:
+** Don't use `using namespace xyz` anywhere.
+** Use only namespace aliases in source files (`.cpp`), trying to
+   use them in the smallest possible scope (function, or even smaller).
+
+* Return a structure with named members instead of a generic container
+  such as `std::pair` or `std::tuple`.
+
+* When a class inherits a base class with virtual methods, use the
+  `override` keyword to mark overridden virtual methods, and do not use
+  the `virtual` keyword again.
+
+* Define overloaded operators only if their meaning is obvious,
+  unsurprising, and consistent with the corresponding built-in
+  operators.
++
+For example, use `+|+` as a bitwise- or logical-or, not as a shell-style
+pipe.
+
+* Use RAII wrappers when managing system resources or interacting with
+  C{nbsp}libraries.
++
+In other words, don't rely on ``goto``s and error labels to clean up as
+you would do in{nbsp}C.
++
+Use the RAII, Luke.
+
+* Throw an exception when there's an unexpected, exceptional condition,
+  https://isocpp.org/wiki/faq/exceptions#ctors-can-throw[including from
+  a constructor], instead of returning a status code.
+
+* Accept a by-value parameter and move it (when it's moveable) when you
+  intend to copy it anyway.
++
+You can do this with most STL containers.
++
+Example:
++
+[source,cpp]
+----
+void Obj::doSomething(std::string str)
+{
+    _mName = std::move(str);
+    /* ... */
+}
+----
+
+.`baby.hpp`
+====
+This example shows a {cpp} header which follows the {bt2} {cpp} coding
+convention.
+
+[source,cpp]
+----
+/*
+ * SPDX-FileCopyrightText: 2020 Harry Burnett <hburnett@reese.choco>
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_BABY_HPP
+#define BABELTRACE_BABY_HPP
+
+#include <string>
+#include <unordered_set>
+#include <utility>
+
+namespace life {
+
+class Toy;
+
+/*
+ * A baby is a little human.
+ */
+class Baby : public Human
+{
+    friend class Parent;
+
+public:
+    using Toys = std::unordered_set<Toy>;
+
+    enum class Gender
+    {
+        Male,
+        Female,
+        Other,
+    };
+
+    explicit Baby() = default;
+    explicit Baby(const Toys& toys);
+    Baby(const Baby&) = delete;
+    Baby(Baby&&) = delete;
+
+protected:
+    explicit Baby(Gender initialGender = Gender::OTHER);
+
+public:
+    ~Baby();
+    Baby& operator=(const Baby&) = delete;
+    Baby& operator=(Baby&&) = delete;
+
+    /*
+     * Eats `weight` grams of food.
+     */
+    void eat(unsigned long weight);
+
+    /*
+     * Sleeps for `duration` seconds.
+     */
+    void sleep(double duration);
+
+    /*
+     * Sets this baby's name to `name`.
+     */
+    void name(std::string name)
+    {
+        _mName = std::move(name);
+    }
+
+    /*
+     * This baby's name.
+     */
+    const std::string& name() const noexcept
+    {
+        return _mName;
+    }
+
+protected:
+    void _addTeeth(unsigned long index);
+    void _grow(double size) override;
+
+private:
+    std::string _mName {"Paul"};
+    Toys _mToys;
+};
+
+} /* namespace life */
+
+#endif /* BABELTRACE_BABY_HPP */
+----
+====
+
+== Python Usage
+
+=== Formatting
+
+All Python code must be formatted using the version of
+https://github.com/psf/black[Black] specified in `dev-requirements.txt`.
+
+All Python imports must be sorted using the version of
+https://pycqa.github.io/isort/[isort] indicated in `dev-requirements.txt`.
This page took 0.031793 seconds and 4 git commands to generate.