Browse Source

Coding style guide is now shared with Corrade.

vectorfields
Vladimír Vondruš 14 years ago
parent
commit
f3c05e9854
  1. 393
      doc/coding-style.dox

393
doc/coding-style.dox

@ -9,377 +9,32 @@ Please note that if you have a good excuse to either break the rules or modify
them, feel free to do it (and update this guide accordingly, if appropriate). them, feel free to do it (and update this guide accordingly, if appropriate).
Nothing is worse than rule that hurts productivity instead of improving it. Nothing is worse than rule that hurts productivity instead of improving it.
You can also take inspiration from other thorougly written coding style This guide builds upon Corrade's coding style guide and extends it where
guidelines of large projects: needed. You are encouraged to read it first:
- LLVM: http://llvm.org/docs/CodingStandards.html - @ref corrade-coding-style
- Qt: http://qt-project.org/wiki/Qt_Coding_Style
@section cmake CMake code
All cmake functions and macros (e.g. `add_executable()`, `set()`) are
lowercase, keywords (e.g. `FILES`, `DESTINATION`) are uppercase. Variables are
mostly uppercase with underscores between words, except for variables with
direct relation to any named target - then they have the target name as prefix
with no case change, followed with underscore, the rest of variable name is
uppercase, e.g. variable holding all sources for target `MagnuMeshTools` will
be named `MagnumMeshTools_SRCS`.
Multi-line calls (i.e. `set()`) have trailing parenthesis on the same line as
last parameter, *not* on separate line:
@code
set(Magnum_SRCS
Object.cpp
Camera.cpp
Light.cpp)
@endcode
@section cpp C++ code @section cpp C++ code
@subsection cpp-files File naming and directory structure
All C++ header and source files are named after the class they contain with no
case change. Thus there should be only one class per file, but if the classes
are closely related and small enough, you can make an exception (see Query.h
or TypeTraits.h for example).
Supporting headers (not relevant to end user), such as various `configure.h`,
`visibility.h` etc., which are used only internally and don't contain any
code, should have first letter of the name lowercased to distinguish them from
API headers.
Code in the root Magnum namespace is in `src/` directory, each subnamespace is
in its own subdirectory. Unit tests are in `Test` subnamespace (and
subdirectory). Implementation details (helper classes etc.) which shouldn't be
visible to end users should be in `Implementation` subnamespace in the same
file as the class/function for which the implementation is. See @ref documentation
section below for guide how to hide it also from Doxygen documentation.
@subsection cpp-headers Headers @subsection cpp-headers Headers
Headers have an strict structure. Include guards are basically include path Headers shouldn't have `using` declarations inside them (unless there is good
with slashes replaced with underscores to make refactoring as easy as possible. excuse, see Magnum.h).
Directly after them is license block, blank line, then file documentation,
blank line and after that the contents of the header. Include guard ending is
only `endif`, without any additional comments.
It's probably common practice, but repeating won't hurt: headers shouldn't
have `using` declarations inside them (unless there is good excuse, see
Magnum.h).
@subsection cpp-sources Source files
Source file have similar structure as headers - first license block, then
blank line, then the includes, then contents of the file.
Unlike headers, it's good to use `using` declaration in source files as much
as needed to make the code less verbose (unless the name is used only once).
@subsection cpp-format Code format @subsection cpp-format Code format
@subsubsection cpp-naming Naming @subsubsection cpp-naming Naming
Namespaces, classes and structs, enums, type template names and static When writing wrappers for OpenGL functions and defines, try to match the
constants should be named with `CamelCase`, i.e. first letter of the name and original name as closely as possible, although expanding abbrevations (and
each successive word uppercase, other lowercase. E.g. `%CubeMapTextureArray`. removing redundant prefixes) is encouraged.
Classes with pure virtual methods or base classes which are not meant to be
used directly should be prefixed with `Abstract`. If the class is not meant
to be instanced directly and doesn't have any pure virtual methods, consider
using pure virtual destructor (see AbstractTexture source for example).
Functions, function parameters, non-type template names and variables should
be named with `camelCase`, i.e. first letter of the name lowercase, each
successive word starting with uppercase. E.g. `generateFlatNormals()`.
Preprocessor macros should be written in uppercase with underscores between
words, e.g. `MAGNUM_EXPORTING`.
Redundant information and abbrevations in names are not recommended (use
`determinant`, `inverse` and `attribute` instead of `det`, `inv` and `attr`).
Hungarian notation, `I` and `E` prefixes for interfaces and enums are
forbidden and cruelly punished, if found. Acronyms should be written with
first letter uppercase only to avoid visual collision with preprocessor macros
(`Http`, `Collada` and `Bptc` instead of `HTTP`, `COLLADA` and `BPTC`). When
writing wrappers for OpenGL functions and defines, try to match the original
name as closely as possible, although expanding abbrevations (and removing
redundant prefixes) is encouraged.
Private variables clashing with (mostly getter) function names can have
one underscore before them, don't use two underscores, as they are reserved
for internal usage by the C++ standard. Underscores before the name shouldn't
be used in public API or function parameters, as it looks ugly in the
documentation.
@subsubsection cpp-namespace Namespace declarations
Namespace declaration is on one line, separated with blank lines on both
sides. The code inside the declaration is not indented to save horizontal
space.
@code
namespace Magnum { namespace Math { namespace Geometry {
// ...
}}}
@endcode
The only exception is with forward declarations: use indentation where it
improves readability, e.g.:
@code
namespace Corrade { namespace PluginManager {
class AbstractPluginManager;
}}
namespace Magnum {
namespace Math {
class Matrix4;
namespace Geometry {
class Distance;
}
}
// the actual code...
}
@endcode
@subsubsection cpp-classes Class and structure declarations
Class and structure protection levels are ordered as following: first friend
declarations, then deleted copy/move constructors and assignment operators,
then public members, then protected members and finally private members, so
class public interface is easy to spot at the top of the file.
Members are ordered as following: first classes and enums, then static
functions, then non-static functions, then static variables, then non-static
variables. Again, classes and methods are more important for user than
variables, static members are more important than non-static.
@subsubsection cpp-style Blocks, whitespace and indentation
The goal is to preserve readability with minimal amount of wasted vertical
and horizontal space.
Each file must have one blank line at the end (Git will warn you in the
diff if it's not the case), indentation is done exclusively with spaces (4
spaces). Trailing whitespaces are not permitted (and you should set up your
Git installation to warn about that).
The code should be wrapped around 80th column, exceptions for long single-line
statements are allowed unless it hurts readability.
Indented is everything except namespace declarations (as specified above) -
blocks, class protection levels, `case` statements. Overlong line breaks are
indented also with 4 spaces or better where it makes more sense (e.g. for
aligning similar code), multiline comments are indented with three spaces for
the comment text block to be aligned.
Whitespace is **not allowed** inside parentheses and between function name or
branch/loop statement and left parenthesis (or between constructed variable
name and left brace) and before semicolon. It **must be** around block braces
if the block is not empty. It **must not** be space before, but after the
comma.
@code
if ( statement ){foo (a ,b) ;} // awful!
if(statement) { foo(a, b); } // good
@endcode
Whitespace should be around operators with low precedence (namely `+`, `-`,
`<<`, `>>` but not on unary `-`), around all boolean and comparison operators,
around `=` and related operators and around ternary operator. Whitespace is
should be around `/`, `*`, `%` to indicate they have precedence before
addition and substraction. Whitespace can or need not to be around binary
operators, whichever looks better in particular content.
Block opening braces start on the same line as corresponding statement (class/
function declaration, branch and loop statement), `else` and `else if`
statements have both braces on the same line too:
@code
if(expression) {
// ...
} else if(another || expression) {
// ...
} else {
// ...
}
@endcode
If the block is only one statement and short enough, it can be on the same line:
@code
void setClearDepth(GLfloat depth) { clearDepth = depth; }
@endcode
@code
if(!initialized) return false;
@endcode
@subsubsection cpp-switches Switch statements
Switch statements are usually very verbose and thus they are often subject of
various shortening and whitespace tricks. The goal is to make them as readable
as possible without wasting too much vertical space, for example:
@code
switch(type) {
case Byte: size = 8; break;
case Short: size = 16; break;
case Int: size = 32; break;
case Long: size = 64; break;
case LongLong: size = 128; break;
default: size = 0;
}
@endcode
@subsubsection cpp-keywords Class member and function keywords
Use keywords in this order: `template virtual inline constexpr static`. Only
base virtual functions should have `virtual` keyword, not the
reimplementations.
@subsubsection cpp-includes Includes
Includes should be organized into separate groups separated with blank line -
first header belonging to the particular source file (if the file is source
file), then system includes, then includes from the engine itself and then
internal includes used only in the particular file (e.g. `configure.h`).
Includes from system libraries and dependencies are in angle brackets,
includes from engine itself are in quotes. Includes should be sorted by
"level" (e.g. C includes (`&lt;cstdlib&gt;`) before C++ includes
(`&lt;string&gt;`) and those before dependencies (`&lt;GL/gl.h&gt;`)), then by
path name.
@subsubsection cpp-macros Preprocessor macros
Preprocessor macros should have the same indentation as surrounding code. If
the macro is long or contains code which should be spanned or multiple lines,
it should be wrapped on multiple lines, each successive line indented and the
line wrapping indicator `\` should be aligned around 80th column, preferably
on some tab-stop.
@subsection cpp-constexpr Constant expressions and constants
Use `constexpr` keyword as much as possible, mainly for getters and static
pure functions, e.g. Matrix4::translation(). If the function is not a single
return-statement, try hard to make it so.
Traits class members and class constants which are not meant to be referenced
or pointed to should be defined as inline (constexpr) function, because
declaring them as static const variable will result in another (probably
unwanted) symbol.
@subsection cpp-assert Assertions
Use asserts as much as possible. %Corrade utility library has convenient
`CORRADE_ASSERT()` macro, which does everything needed - checks the statement,
prints given message to error output and exits immediately or returns default
value:
@code
T operator[](size_t pos) const {
CORRADE_ASSERT(pos < size(), "Index out of range", T())
return data[pos];
}
@endcode
@subsection cpp-forbidden Forbidden C/C++ features
Don't use C-style casts, use C++-style `static_cast` and `reinterpret_cast`
instead. For numeric types (e.g. casting from int to float) you can use
"constructor cast":
@code
int a = 22;
int b = 7;
float pi = ((float) a)/b; // bad!
float pi = static_cast<float>(a)/b; // good
float pi = float(a)/b; // even better here
@endcode
Don't use RTTI (`dynamic_cast` and `std::typeinfo`) and exceptions. They
violate C++ principle of "don't pay for what you don't use" and thus they are
disabled in the code (GCC/Clang option `-fno-rtti -fno-exceptions`).
@section comments Comments
All comments should be in C-style (i.e. slash and asterisk, not two slashes).
There should always be space after leading asterisk and before trailing
asterisk, this is also the case for C++-style comments, if are used somewhere
(mostly in the documentation, because nesting of C-style comments is
impossible).
Multi-line comments should be done in a way which preserves block align (so
when first line starts with slash, asterisk and space, the second line should
be indented with three spaces to align the text).
@section documentation Doxygen documentation @section documentation Doxygen documentation
Doxygen documentation uses C-style comments with two asterisks, each
successive line should start with asterisk and space. However, documentation
block starting at beginning of the line (with no indentation) and spanning
more lines shouldn't have leading asterisks and use whole 80 column width to
avoid wasted space.
Doxygen commands are prefixed with `@`.
If the documentation comment is short enough, it can be on one line. If not,
the first line should contain only the slash and two asterisks. However, there
are exceptions for commands that can be on the first line of the multiline
documentation block - namely @c \@page, @c \@name, @c \@file, @c \@namespace
and other commands for "out-of-place" documentation.
Doxygen documentation is mainly in header files, additional documentation
pages which doesn't belong to any particular class (e.g. namespaces,
overview...) is in `doc/` directory. In source file should be only @c \@todo
items related to particular lines of code. Documentation pages and additional
documentation files should be named in lowercase with dashes between words.
Additional documentation files use `*.dox` extension.
File documentation block is after license block, it explains only in
@c \@brief what content given header contains.
Namespace documentation is only in file `namespaces.dox` inside `doc/`
directory.
Class and function documentation block nearly always starts with an @c \@brief
description (the only exception is enum value documentation). After that is
documentation of template parameters, function parameters and return value.
These are documented only if it's not obvious from the description or
function/parameter name (i.e. it's not needed for setters).
Trivial function overloads (e.g. const overloads) are marked only with
@c \@overload keyword and are always *after* the original documented function.
If the documentation is short enough, it can be placed after the documented
element only if it doesn't exceed 80 character limit too much (e.g. enum value
documentation).
For hiding implementation details from documentation or for working around
Doxygen parsing issues (and false positive warnings), preprocessor define
`DOXYGEN_GENERATING_OUTPUT` can be used. It is defined only when doxygen
generates the documentation. If that works around some Doxygen parsing bug,
don't forget to mark it with @c \@todoc (see below).
@subsection documentation-commands Special documentation commands @subsection documentation-commands Special documentation commands
@subsubsection documentation-commands-todoc Documentation-related TODOs Additionally to @c \@todoc and @c \@debugoperator (same as in Corrade), these
are defined:
TODOs about documentation (or about Doxygen workarounds) should be written
with @c \@todoc instead of @c \@todo. They will appear on @ref todoc
"separate page".
@subsubsection documentation-commands-debugoperator Debugging operators
Operators for printing types on Corrade's debug output should be marked with
@c \@debugoperator, e.g.:
@code
// @debugoperator{Matrix4}
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4<T>& value) {
// ...
}
@endcode
They will appear as related functions within documentation of class specified
as the parameter.
@subsubsection documentation-commands-collisionoperator Physics collision operators @subsubsection documentation-commands-collisionoperator Physics collision operators
@ -425,33 +80,5 @@ noted in the description.
All classes and functions using those commands are cross-referenced in page All classes and functions using those commands are cross-referenced in page
@ref required-extensions. @ref required-extensions.
@section git Git commit messages, branch and tag format
It is encouraged to follow best practices of git commit messages as explained
here: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
In short, each commit message should be in this format, each line at most 72
characters long:
~~~~
Capitalized short summary
More detailed explanation text, if necessary, wrapped on multiple lines.
- Bullet points, indented with one space before (if there is preceeding
paragraph) and one space after the bullet, indented to have the text
aligned. Colons are allowed too, but not mixed.
- Bullet points are separated from surrounding text with blank lines.
It is good to use *emphasise*, _underline_ or `code` as in Markdown, if
necessary, but they shouldn't be overused.
Multi-line code examples are indented with four spaces, as in Markdown
syntax.
~~~~
Branches and tags should be named with lowercase names with words separated
with colons (`-`), e.g. `physics-performance-tweaks`. Version tags start with
`v`, followed by version number, e.g. `v1.0.3`.
*/ */
} }

Loading…
Cancel
Save