Polygon Mesh Processing Library
Loading...
Searching...
No Matches
Coding Style

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.

Naming

Types

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.

class SurfaceMesh { ... };
struct Flags { ... };
enum class TextureMode { ColdWarm, Checkerboard, MatCap };

Functions

Function names are written using snake_case. All characters are lowercase. Separate words by underscores.

class MeshViewer
{
bool load_mesh(const char* filename);
};

Variables

Variable names use snake_case notation. All characters are lowercase. Separate words with underscores. Class member variables have an underscore _ suffix.

int global_var;
class ExampleClass
{
protected:
double member_variable_;
static double static_member_;
};

Exception: Public members of a struct holding just a group of variables may omit the underscore suffix:

struct NearestNeighbor
{
Scalar dist;
SurfaceMesh::Face face;
Point nearest;
};

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:

Eigen::SparseMatrix<double> A(n, n);
Eigen::MatrixXd B(n, 3);

File Names

File names are all lowercase. Words are separated with underscores. Implementation files end with .cpp and header files end with .h.

Formatting

Blocks

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.

if (foo == bar)
{
std::cout << "baz" << std::endl;
}
else
{
std::cout << "barbaz" << std::endl;
}

Line Length

Lines should not exceed more than 80 characters. There should only be one statement per line.

Indentation

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.

Miscellaneous

This section describes some basic programming conventions developers should adhere to.

Declaration Order

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:

  1. typedefs and enums
  2. constants
  3. constructors and destructor
  4. operators
  5. methods
  6. static methods
  7. data members
  8. static data members

Comments

Use C++-style comments, i.e., // my comment.

Doxygen Comments

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?

Include Guards

Use the

#pragma once

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.

Header Include Order

Use the following order to include header files:

  1. Related header
  2. C standard library headers
  3. C++ standard library headers
  4. Other library headers
  5. Project library headers

Separate each group by a blank line. Optional: Sort headers alphabetically within a group.

Include Style

Use quotes to include other project headers. Use the full relative path from the project src directory. Example:

#include "pmp/algorithms/remeshing.h"

Namespace

Use the pmp namespace in order to avoid conflicts. In source files, do not add an additional level of indentation due to the namespace:

namespace pmp {
class ExampleClass
{
...
};
}
The pmp-library namespace.
Definition: barycentric_coordinates.h:8

Boolean Prefixes

Use meaningful prefixes for bool variables or functions returning booleans, e.g., has_colors() for a function or is_done for a variable.

Naming Consistency

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, ...).

Type Consistency

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.

Structs vs. Classes

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.

Scoping

Localize variable scope and avoid declaring all variables at the beginning of a function or code block.

Prefer C++ over C

Give preference to C++ and STL constructs over C-style ones. Example: Use std::numeric_limits<float>::max() instead of FLT_MAX.

Using clang-format

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:

make clang-format

This requires that the clang-format executable is found during CMake configuration. The exact path to the executable can be specified using

cmake -DCLANG_FORMAT_EXE=<path/to/executable> ..

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:

// clang-format off
Mat4<Scalar> m;
m(0, 0) = x[0]; m(0, 1) = x[1]; m(0, 2) = x[2]; m(0, 3) = -dot(x, eye);
m(1, 0) = y[0]; m(1, 1) = y[1]; m(1, 2) = y[2]; m(1, 3) = -dot(y, eye);
m(2, 0) = z[0]; m(2, 1) = z[1]; m(2, 2) = z[2]; m(2, 3) = -dot(z, eye);
m(3, 0) = 0.0; m(3, 1) = 0.0; m(3, 2) = 0.0; m(3, 3) = 1.0;
// clang-format on

Commit Messages

Please write meaningful commit messages. See this post for the why and how.

The basic rules are:

  1. Separate subject from body with a blank line
  2. Limit the subject line to 50 characters
  3. Capitalize the subject line
  4. Do not end the subject line with a period
  5. Use the imperative mood in the subject line
  6. Wrap the body at 72 characters
  7. Use the body to explain what and why vs. how

This is what an example might look like:

Summarize changes in around 50 characters or less
More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. Explain the problem this commit is solving. Focus on why you are making this change as opposed to how. Are there any side effects or counter-intuitive consequences?
Reference issues at the bottom, sign off on last line:
Resolves: #123
See also: #456, #789
Sign-off-by: Jane Miller <jane.miller@example.com>

Further Reading

Here are some additional resources regarding C++ coding standards and best practices: