This section describes the coding standards we use. They are important to establish a minimum level of consistency through the code base as well as to facilitate code comprehension for developers and users. If you would like to contribute to PMP, please make sure your code adheres to the conventions outlined below.
The names of user-defined types such as classes, structs, and enums use CamelCase
notation. The names of persons such as Cholesky or Delaunay are properly capitalized as well.
Function names are written using snake_case
. All characters are lowercase. Separate words by underscores.
Variable names use snake_case
notation. All characters are lowercase. Separate words with underscores. Class member variables have an underscore _
suffix.
Exception: Public members of a struct
holding just a group of variables may omit the underscore suffix:
Exception: For the sake of similarity with common mathematical notation, we sometimes use uppercase letters, e.g., to denote matrices when solving a linear system:
File names are all lowercase. Words are separated with underscores. Implementation files end with .cpp
and header files end with .h
.
The expressions following an if, else, while, do ... while
or for
statement should always be enclosed in braces. The braces enclosing a block should be placed in the same column, on separate lines.
Lines should not exceed more than 80 characters. There should only be one statement per line.
Use spaces instead of tabs. Indent the code by four spaces for each level of indentation. Avoid trailing whitespace at the end of a line as well as on empty lines.
This section describes some basic programming conventions developers should adhere to.
Group the sections of a class in the following order: public, protected, private.
Use one section for each type of access specifier.
Omit empty sections.
Within a section use the following order:
Use C++-style comments, i.e., // my comment.
We use Doxygen to generate our API documentation. All public types and interfaces should be properly documented. This usually includes a brief one-sentence description and a more detailed description of what the function does. We use //!
for Doxygen comments. The following is an example what a full documentation comment could look like:
//! \brief Does foo. //! \details Does foo and nothing else. If \p use_bar argument is true uses the //! bar method instead of foo. //! \param[in] use_bar toggle to switch method //! \param[out] results filled with results from foo //! \return true on success.
Use \p
to reference (member) function parameters.
It is good practice to document pre- and post-conditions for performing an operation. Those can be documented using the \pre
and \post
Doxygen special commands.
It is good practice to document exceptions thrown by your function using the \throw
markup command.
Use Doxygen comments only in the header file. Do not repeat the same information in the implementation file. Instead, provide specific details on the implementation at hand, i.e., how was the functionality implemented, and why was it implemented in this manner?
Use the
compiler directive at the beginning of each header file in order to protect against multiple inclusion. Although this is not officially part of the language this feature is supported by all major compilers and is much more convenient than conventional header guards.
Use the following order to include header files:
Separate each group by a blank line. Optional: Sort headers alphabetically within a group.
Use quotes to include other project headers. Use the full relative path from the project src
directory. Example:
Use the pmp
namespace in order to avoid conflicts. In source files, do not add an additional level of indentation due to the namespace:
Use meaningful prefixes for bool
variables or functions returning booleans, e.g., has_colors()
for a function or is_done
for a variable.
Consistently name dynamic properties, e.g., v:scalar
for vertex scalars or f:normal
for face normals. Similarly, consistently name iterators and circulators by their entity type (Vertex
, Halfedge
, ...).
Try to avoid conversion issues by using consistent types, e.g., use std::size_t
when storing values from STL functions such as the size()
member function of a std::vector
. Use the C++11 auto
keyword to let the compiler determine the proper types.
Use plain structs for data objects providing nothing but a collection of other data types, e.g., a collection of parameters passed to a functions. Such a struct should not contain any further functionality than what is required for construction, destruction, or initialization. In contrast to class member variables, struct members do not have a underscore _
suffix.
Localize variable scope and avoid declaring all variables at the beginning of a function or code block.
Give preference to C++ and STL constructs over C-style ones. Example: Use std::numeric_limits<float>::max()
instead of FLT_MAX
.
Please use the clang-format tool and the corresponding .clang-format
configuration file from the repository to properly format your code. We also provide a convenience CMake target to run clang-format on all source files:
This requires that the clang-format
executable is found during CMake configuration. The exact path to the executable can be specified using
In case you want to preserve the special formatting of a particular code block such as a matrix initialization add the // clang-format off
and // clang-format on
directives around this block:
Please write meaningful commit messages. See this post for the why and how.
The basic rules are:
This is what an example might look like:
Here are some additional resources regarding C++ coding standards and best practices: