Please adhere to the following code style and conventions in your pull requests: Feel free to fix code that doesn't adhere to this guide (yet).
- Use clang-format with the .clang-format style in the repository before you commit.
There is a script "apply-clang-format.sh" which you can use to fix all files in the repository.
If you need a section untouched by clang-format you can use
// clang-format off some() ("fragile", DSL_LIKE) (code) / (that - should - not - be - touched); // clang-format on
- Lean towards Python PEP8 naming conventions:
- classes are capitalized
CamelCase
, - member functions, free functions and variables are lowercase
snake_case
, - constants are uppercase
SNAKE_CASE
.
- classes are capitalized
- Prefix member variables with an
m_
.
Member functions should not be prefixed. - Prefix global variables (if you need them) with a
g_
. - Use JavaDoc style comments for inline documentation.
- Use
#pragma once
to guard headers/includes. - Always use braces around the block after control flow statements (
if
,else
,loops). - Declare/define only one variable per line.
- Write all code in a namespace, never pollute the global namespace (e.g. with
using namespace
in a header). - Do not use the global random number generators from the C/C++ libraries.
Use a local deterministic PRNG likestd::mt19937
instead or ask the caller for a source of randomness. - Prefer C++ style casts (
static_cast
,dynamic_cast
,const_cast
,reinterpret_cast
) over C-style casts. - Never write new.
Use C++14make_unique
/make_shared
or at least immediately catch the resulting pointer in aunique_ptr
orshared_ptr
. - Include what you need - Headers only include what is needed for the interface of the class.
Implementations include what is needed for the implementation. Headers SHOULD NOT include stuff that is only needed for the implementation. If you want to reduce includes in headers even further, consider using the PIMPL pattern. - Make helper functions static or put them into an anonymous namespace so that users and the compiler/linker know they are local to the compilation unit.
- Write tests.
- All code goes into or below the
::tin-terrain
namespace. - The use of sub-namespaces below
::tin-terrain
is discouraged. - Use the
TNTN_ASSERT()
macro from"tntn/tntn_assert.h"
instead ofassert()
so that the behaviour of asserts can be changed when needed. - Use the
println(...)
andprint(...)
functions from"tntn/println.h"
to write intentional output to stdout. Intentional output could be processed by a script and creates a contract. - Use
TNTN_LOG_<level>
macros from"tntn/logging.h"
to output diagnostic message on the commandline.
TNTN_LOG_ERROR
andTNTN_LOG_WARN
are message that require special attention from the user.TNTN_LOG_INFO
are messages that a normal user should see on the console when running a commandline tool.TNTN_LOG_DEBUG
are messages that only developers should see.TNTN_LOG_TRACE
are messages that are only available in Debug builds and should only be relevant when you work on the specific module.
- Use
File
andFileLike
classes to read and write files (instead of iostreams or stdio).
- Write tests.
- All test code goes into the
::tin-terrain::unittests
namespace. - The test source file is named after the file where code under test lives.
E.g. when you add a feature or fix something inSomeFile.h/.cpp
, the tests go toSomeFile_tests.cpp
. - Never write to the real filesystem in tests, use
MemoryFile
instead. - Try to avoid reading data from the real filesystem in tests. If you really need to read data for tests
(e.g. reference data), before you use the real filesystem, consider:
- generating synthetic test data on the fly instead of using real data
- the copyright/database rights of assets/resources before you include them in the code repository
- to include small resources statically in the code by dumping the data into C++ source,
e.g. with xxd:
xxd -i foo.bin > foo.cpp
- Use
.h
for header files,.cpp
for implementations. - A header file should declare one important/major class.
Associated small helper classes can be put into the same header. - Header files that contain mostly classes should be named after the important/major class inside.
E.g. if a header contains theclass Foo
andclass FooHelper
then the header should be namedFoo.h
. If a header contains multiple equally important classes (not good, but might be appropriate because they belong together), then the file should be also named capitalized CamelCase like classes but with a descriptive name. E.g. a header that containsclass FooReader
andclass FooWriter
should be namedFoo.h
. - Header files that are collections of things or contain mostly free functions should be named lowercase snake case.
Choose a name that describes the grouping of the contents. E.g. if a header contains the functionsconcatenate_strings(...)
andconcatenate_vector(...)
, a good choice might beconcatenation.h
- Implementations for headers go into a
.cpp
with the same name.
- Development should happen on feature branches. Never commit to master directly.
- Branch names should be
kabab-cased.author-nickname
(http://wiki.c2.com/?KebabCase). - Submit pull request to get stuff merged to master.
- Commit messages should contain meaningful one-line title and optional description after the first line.
- Never merge master to feature branches, rebase your feature branch on top of master instead.
If you want to make sure to run clang-format before every commit you do,
you can use the apply-clang-format script as a pre-commit hook in git.
Paste this into .git/hooks/pre-commit
:
#!/bin/sh
./apply-clang-format.sh