Take a look at existing code to see how the code style looks like. Some noteworthy things:
- always use tabs for indentation
- split function calls / function definitions into multiple lines if they get too long (see the code for examples)
- no one line ifs/fors/whiles ..., every one of those must use two curly braces
These are guidelines on how to structure APIs, this applies not only to the public API, but also to internal APIs between components.
Function parameters:
- output first, followed by input
- public key first, then private key
- optional parameters at the end (optional outputs after regular inputs)
- inputs/outputs that aren't allocated by the function get passed as Molch::span
Naming conventions:
- Functions:
molch_end_conversationinstead ofmolch_conversation_end(verb first)- but start with the 'class' that the function belongs to (
molchin the example above)
- make as much
constas possible, including pointers (e.g.const buffer_t * const buffer) - don't rely on undefined behavior
- declare variables as locally as possible, not at the beginning of a function but only once they are needed
- use
nullptrfor null pointers and explicitly checkpointer == nullptrin conditions (this makes code much more readable and makes the programmer's intent clearer) - AAA (Almost Always Auto): Use the
autokeyword - Use initializer lists where possible
- Use RAII (Resource Acquisition Is Initialization) everywhere!
- Always pass by reference if possible
- Use
gsl::bytefor binary data - Use
byte_to_ucharanduchar_to_byteto convert betweenunsigned char*andgsl::byte* - Use
gsl::narrowfor integer conversions. If you know it cannot fail, you can usegsl::narrow_cast(no runtime overhead).
- document every new function with doxygen doc comments. Functions that are also in the header are only documented in the header file.
- use a layer based approach (function calls / access to data structures is only done top down, not the other way round), the functions that are called mustn't know by whom they are called etc.
- make sure to always overwrite memory locations that held confidential data with zeroes afterwards using sodium_memzero
Bufferdoes this automatically, other things to help:SodiumAllocator/SodiumDeleter,autozero
- if possible, always work with
Molch::span - write tests for everything you do
- if you're modifying existing files, just add your test to the appropriate file in the
testdirectory - if you're creating new files, add a new test file in the
testdirectory and add it totest/CMakeLists.txt
- if you're modifying existing files, just add your test to the appropriate file in the
- add
__attribute__((warn_unused_result))to functions that return error codes or pointers to heap allocated memory - Follow the CPP Core Guidelines (except use
size_tfor sizes, not a signed integer type)
- make small, concise commits, that only do one thing
- write explanatory commit messages
- every commit has to compile and pass the tests