NEVER include using namespace
statements in header files.
NEVER include a using statement for the standard namespace (std
). Instead, always qualify all types from it.
USE a constexpr expression instead of a MACRO whenever possible.
USE pragma once
instead of header guards.
USE enum class
instead of enum
whenever possible.
ALWAYS declare variables as close to first usage as possible - this isn't C!
ALWAYS pass non-trivial parameters by reference.
PREFER a composite return value (e.g. pair
, POD struct
) to multiple out parameters.
PREFER auto
whenever possible, but use as many type modifiers (const
, volatile
, &
, *
) as possible.
AVOID volatile unless there is a very strong justification (there usually isn't).
ALWAYS use using
statements instead of typedef
for aliases.
USE function qualifiers (override
, final
, const
) liberally.
PREFER an enumeration to multiple booleans.
USE anonymous namespaces liberally in cpp files and export the minimum number of names from each compilation object.
NEVER use static free functions.
USE size_t
whenever dealing with data sizes.
USE types defined in stdint.h (uint8_t
, uint16_t
, uint32_t
, etc.)
AVOID using signed types unless it's really necessary and reasonable.
AVOID using floating point arithmetic, especially in any part of consensus.
If a cpp/h file contains a single class, the file should be named after the class and be UpperCamelCase. If a cpp/h file contains utility functions, the file should be given a descriptive name and be UpperCamelCase.
We expect parallel source and test directory hierarchies. For example,
root
- parser # package name, directory containing source code
Parser.h/cpp # contains class Parser
- ast
- Ast.h/cpp # contains various exports
- tests # directory containing tests for source code
- ParserTests.cpp # unit tests for parser/Parser.h/cpp
- ast
- AstTests.cpp # unit tests for parser/ast/Ast.h/cpp
Static and free functions should be UpperCamelCase
Member function names should be lowerCamelCase
Constants (global or local) should be Upper_Camel_Case.
#defines should be TITLE_CASE
Local variables and function parameters should be lowerCamelCase
Struct members should be UpperCamelCase
Prefix class instance members with m_
Prefix class static members with s_
Prefix globals with g_
Prefix all pointers (both smart and raw) with p
Never prefix anything with a single underscore (_
).
If you pass size of an array somewhere, always give the size variable a name, that suggests what it actually is:
So if you actually expect number of elements, use name with Count
postfix [e.g. nodeCount
]
If you want number of bytes use name like size_t nameSize
Always use "/" in includes and NEVER "\", (C standard WG14/N1256 point 6.4.7, C++ standard ISO/IEC 14882:2003 point 2.8, C++ standard ISO/IEC 14882:2011 (from working draft N3225) point 2.9)
Try to include the minimal number of files required for a successful build. Corollary: don't include anything you don't need.
Order includes from most specific to most general.
Recommended class order:
Private constants (as they are usually used early)
Public constants
Methods
Constructors
Instance methods
Static methods
Fields
Public members (should probably be used only for POD types)
Protected members
Private members
Use an access modifier (public:
, private:
) for each section even if the modifier is redundant.
Blockchain not BlockChain
Filename not FileName
Filesystem not FileSystem
NotEmpty not NonEmpty
Nonzero not NonZero or Notzero or NotZero
Roundtrip not RoundTrip
SubCache not Subcache
ThreadPool not Threadpool
Timestamp not TimeStamp
Configuration
for class names
config
for variable names
single indent for block opening
for (auto&& pEntity : entities) {
singleEntityVector[0] = pEntity;
auto result = dispatcher.dispatch(m_config.ValidationPolicy, singleEntityVector);
m_config.pObserver->notify(*pEntity, observerContext);
}
continuations use double indent
CATAPULT_LOG(debug) << "comparing chain scores: " << localScore << " (local) vs "
<< remoteScore << " (remote)";
return pState
&& pState->ImportanceInfo.Importance > Importance(0)
&& pState->Balances.get(Xem_Id) >= minHarvestingBalance;
initializer list, and ctors/function/method arguments, have double indent
// mind the double indent for method arguments
thread::future<std::unique_ptr<model::Block>> BlockAt(
Height height,
const io::BlockStorageView& storage) {
if (Height(0) == height || storage.chainHeight() < height) {
auto exception = CreateHeightException("unable to get block at height", height);
return thread::make_exceptional_future<std::unique_ptr<model::Block>>(exception);
}
return thread::make_ready_future(storage.loadBlock(height));
}
empty body, short
Foo() : m_value(0)
{}
empty body, long
// two indents
Foo(very arguments, much wow)
: m_value(0)
, m_xman(professor)
{}
body, short
Foo() : m_value(0) {
// body
}
body, long
// two indents
Foo(very arguments, much wow)
: m_value(0)
, m_xman(professor) {
// body
}
Do not use such a construct when for
doesn't have a body
for (a; b; c);
Instead use
for (a; b; c)
{}
This leaves clear intention of what you had in mind.