Leonardus
Loading...
Searching...
No Matches
CODING

Notes on more general aspects of programming that could also be applied in
other C++ projects.

  • Naming and Structure Conventions
  • Order of Class Members
  • C++ Notes
  • Design by Contract
  • Class Invariants
  • Static Code Analysis
  • Task Tags
  • Doxygen

The more project specific notes can be found in ARCHITECTURE.

Naming and Structure Conventions

The first character of a class name is an uppercase letter.

Class attributes end with an underscore.

Parameters are consistently prefixed with p_.

Functions within anonymous namespaces are consistently prefixed with s_.

namespaces have lower case names.

Test cases names are prefixed with B_.

Test suite names are prefixed with Suite.

using namespace xyz; is not used at all.

An indentation consists of 2 spaces.

A maximum of 4 levels of indentation should be maintained (This is called a never nesting approach).

We use the dollar sign character as part of identifiers.

For operators and functions where an "in place" variant and an "non in place"
varaint make sense, we idicate die "in place" varaiant with a suffix ¹ or a
suffix __1.

The test coverage is determined using gcov. The latter requires
a clean separation of code lines for each statement to be measured.

Order of Class Members

++
class AClass {
private:
protected:
public:
// starting with ctors and dtors
public: /* accessor */
// setters and getters
public: /* virtual */
// virtual member functions
public: /* other */
// other member functions
};

C++ Notes

The minumum C++ standard in use is C++ 20 with GNU extensions.

Remarkable C++ features in use:

  • templates
  • lambdas and function pointers
  • multiple inheritance
  • virtual dtors
  • anonymous namespaces
  • 128 bit integer and 128 bit floating point data types
  • initialization of static inline int attributes within
    the class definition
  • static class members and static member functions
  • curiously recurring template pattern
  • explicit ctors
  • [[nodiscard]] and [[noreturn]] attributes
  • auto type deduction and decltype()
  • shared pointers
  • iterators for STL classes
  • std::initializer_list<>
  • dollar signs in identifiers
  • constexpr and regular usage of const qualifiers
  • delegating ctors
  • in-class initialization
  • deleted und defaulted methods
  • std::source_location
  • STL algorithms
  • regex library
  • raw literal strings
  • [[gnu::constructor]] and [[gnu::destructor]]

C++ features that we intentionally avoid:

  • exception handling

Patterns and architecture:

  • singleton pattern (class Interpreter)
  • adapter pattern for functions and classes (stoint128(); class SOK)
  • pipes ( interpreter pass 1 | interpreter pass 2 )
  • composite pattern (class SO hierarchy)
  • ? proxy (without interface: class Counter)
  • polymorphic containers (class SOA)
  • null objects (class SOL)
  • bridge pattern / opaque pointers (class PimplTime)
  • rudimentary design by contract with prerequisites, postrequisites and class invariants
  • single source of truth
  • explicit attributes for pure functions and whole libraries

Design by Contract

Invariants, pre- and postconditions are documented inline with Doxygen.

Certain contracts can be and are fullfilled by strong typing:

  • size_t ensures a non-negative integer
  • enum AngularUnit
  • enums opError and inError
  • enum class OTCode
  • etc.

The const qualifier is in use for call parameters to document and enforce this const contract.

Class Invariants

Classes with invariants have to inherit protected from class DbC
from dbc.h.

A protected bool invariant() noexcept const implements all invariant-checks
listed in the Doxygen @invariant class documentation.

If a class has a parent class with an invariant(), then it must call
this Parent::invariant().

#ifndef DBC_IS_VOID guards the invariant checker and auxiliary code
to exclude them in BUILD_TYPE PRODUCTION or PERFORM.

DBC_INV_CTOR(classname); will be used

  • at the end of ctors
  • at the beginning of dtors

DBC_INV; will be used

  • in non-constant public functions
  • not in static functions
  • not for single parameter setters

DBC_INV_RAII(classname) can used to force the call to invariant()
at function return.

It does the checks, but not in BUILD_TYPE PRODUCTION or PERFORM.

Following global invariants are documented:

  • No instantiation of the class
  • Singleton

These invariants are forced by:

  • non-public ctors
  • pure virtual functions
  • creation of the singleton instance in a static get() function

Preconditions

The preconditions are listed in the Doxygen @pre member function
documentation. DBC_PRE ist used for the implementation of the
precondition-checks.

Postconditions

The postconditions are listed in the Doxygen @post
member function documentation.
DBC_POST ist used for the implementation of the postcondition-checks.

Static Code Analysis

and code statistics

cppcheck

cppcheck ist used as integrated code tool in KDevelop and as target within
the makefile.

Some false positves are suppresed. E.g.:

// cppcheck-suppress stlcstrParam

clang-tidy

clang-tidy ist controlled by the makefile.
The output is send to tmp/statcode1.txt
Integration into Viusal Studio Code is TBD.

Clazy

Integrates with KDevelop. detailed config TBD.
makefile integration TBD.

Count Lines Of Code

the tool cloc is integrated in the makefile. It generates CLOC,
which is part of the documentation.

shellcheck

shellcheck is a Unix shell lint. It is integrated with the component
mechanism in the GitLab pipeline.
Some checks by shellcheck are disabled generally within the GitLab
YAML configuration.
SC2086 is disabled with a comment convention within the shell scripts
with # shellcheck disable=SC2086#.

markdownlint-cli2

markdownlint-cli2 is a Markdown lint. It is integrated with the
component mechanism in the GitLab pipeline. The check is configured
to always succeed.

KDevelop Editor

Has build-in analysis for the editor.
KDevelop requires a compile_commands.json file to run clang-tidy
and Clazy.
bear generates this file, with an integration in the makefile.

Visual Studio Code Editor

Has build-in analysis for the editor.

GitLab SAST

GitLab SAST is a GitLab-maintained pipeline feature for automatic security tests.

Dynamic Code Analysis

gprof

gprof is used by the Tools/ptest.sh performance test harnish.

gprof can be found in the package binutils for Ubuntu/Debian based OS.

For more details see TESTS.

Code Coverage

Code coverage analysis is integrated in the build process in the makefile.

For more details see TESTS.

Task Tags

The task tags information is extracted using the Tools/tasktags.sh script.
This script is directly integrated into the makefile, making it part of
the automated build process. Editors and IDEs support this kind of tagging
by highligthing the texts.

We utilize three distinct tags to categorize different types of tasks.
However, specific configuration might be required depending on the editor
or IDE used.

FIXME:
This is a known bug in the software. This bug should be fixed in the
next software release.

TODO:
A task that still needs to be completed. This task should be finished
before the next major software release.

IDEA:
This is an idea for a potential improvement to the software. Implementing
this idea is planned, but the exact timing is not yet determined.

The current list of task tags can be found under TASKTAGS

Doxygen

For detailed configuration, see the Doxyfile in the project root.

Commenting is done in Doxygen Javadoc style. This allows for loose
integration into KDevelop and Visual Studio Code, which parse these comments
natively.

JAVADOC_AUTOBRIEF is enabled in Doxyfile to eliminate explicit
@brief tags.

The Doxygen output is located in the ./public/doxygen and ./man
directories.

The launch of Doxygen is integrated as a target within the makefile.

The Doxygen HTML output is published as GitLab pages. The process is
automated using GitLab's CI/CD features.

The man page output is used to extract console printable help texts for the
LeoScript operators.

We use the style /** to start comments.

Functions are documented at their point of declaration.

Inline LaTeX formulas are used to pimp up the output.

The order of tags for member functions is:

  1. @pre
  2. @post
  3. @param
  4. @return
  5. @see
  6. @note

The @return tag follows the format for one line
@return type ... Description as sentence.,
e.g.:
@return int ... The number of processed items, or -1 on error.
or for multiple lines e.g.:
@return std::tuple<__int128, __int128, __int128> ...
@return - The gcd of p_a and p_b (first element).
@return - The Bézout coefficient s for p_a (second element).
@return - The Bézout coefficient t for p_b (third element).
Multiple @return statements are used to support the VS Code parser.