*********************** Erbsland C++ Code Style *********************** This document defines the portable code-style baseline for Erbsland C++ libraries and applications. Project-specific guidelines may refine or override semantic rules for their domain. The project's ``.clang-format`` file is authoritative for mechanical formatting. In this document, **must** marks a requirement, **should** marks the expected default unless there is a concrete reason to deviate, and **may** marks an optional choice. Formatting ========== Format every changed C++ file. Accept ``.clang-format`` decisions for indentation, line length, braces, wrapping, spacing, and includes. Formatting that requires manual attention: * Use empty lines to separate logical blocks. * Do not add empty lines between adjacent documented declarations or inline definitions in a header. * Use one empty line around namespace-scope class, struct, enum, and function definitions. * Run the project's validation command after making changes, if one exists. Naming ====== * Types and public type aliases use ``PascalCase``; methods, free functions, local variables, and parameters use ``camelCase``; member variables use ``_camelCase``. * Namespace-scope and static constants use ``cCamelCase``. Enum-like static constants may use ``PascalCase``, as in ``Color::Red``. * A single straightforward template parameter may use ``T``; multiple or descriptive parameters use ``tCamelCase``. * Namespaces use lowercase nested names, such as ``erbsland::unittest``. * Preprocessor macros use ``UPPER_CASE`` and an ``ERBSLAND__`` prefix in Erbsland Core libraries and applications. Do not use macros for constants. * Treat initialisms as words in identifiers, such as ``HttpServer`` and ``parseUtf8``. Keep the documented spelling of domain-specific abbreviations. Files and Includes ================== * Begin each C++ file with the project's two-line copyright block. Put ``#pragma once`` directly after it in headers. * Use ``.hpp`` for headers, ``.cpp`` for implementations, and ``.tpp`` for extracted templates. * Each ``hpp/cpp`` module should have one primary class, struct, enum, alias, or logical method collection. Closely related implementation helpers may share a module. * Match the primary type and filename, and mirror namespaces in the source directory structure. Directories may subdivide a large namespace without adding another namespace. * Put private implementation details in an ``impl`` directory and matching ``impl`` namespace. * Directly include every declaration a file uses; do not rely on unrelated transitive includes. A ``cpp`` file includes its corresponding header first. * Handwritten C++ source files must not exceed 500 physical lines. Split larger implementations by logical responsibility. Name parts ``Class_part.cpp``, ``Class_part.hpp``, or ``Class_part.tpp``. Include ``tpp`` parts at the bottom of the owning header, without an include back to that header. * Do not edit generated files directly. Modify their source or generator and regenerate them. CMake ===== * Use one ``CMakeLists.txt`` in each directory that contains source files. * Add only local files with one flat ``target_sources( PRIVATE ...)`` block. Add nested directories with ``add_subdirectory(...)`` before ``target_sources``. * Sort files and subdirectories alphabetically. Comments and API Documentation ============================== Comment Format -------------- * Use ``///`` and Doxygen ``@`` commands for API documentation, without empty comment lines. * Use ``//`` for short implementation notes. Use ``/* ... */`` only when an inline annotation or generated layout makes it clearer than a line comment. * ``@seedoc{/path}`` links to a documentation page, and ``@seeref{id}`` links to a reference target. * ``@wip`` marks work in progress; ask the project owner before modifying the marked API. Required Documentation ---------------------- * In public and internal APIs, document every class, struct, enum, public type alias, public constant, namespace-scope function, and public method. * Start with one brief line and document every parameter, non-void return value, thrown exception, and relevant edge or error case. * Move extensive explanations to linked reference or topic documentation. * Give every data member and enum member a brief trailing ``///<`` description. * Explicitly defaulted or deleted special members don't need documentation, they must be grouped under ``// defaults`` or ``// defaults/deletions`` or a similar block. * A trivial getter or setter needs only a one-line description without ``@param`` or ``@return``. * An override inherits the API documentation of its base declaration and must not duplicate that documentation. Group overrides under ``public: // implements Base`` or ``protected: // implements Base`` and document only relevant behavioral differences at the derived-class level. Cryptographic Implementations ----------------------------- Cryptographic code must be written for transparent security review as well as functional correctness. * Keep the implementation in the same logical order as the defining specification wherever practical. Prefer direct, readable transformations over compact or clever formulations. * API documentation for an algorithm implementation must name the governing specification and the relevant section. * Add inline comments before each substantive algorithm step that identify the corresponding specification section and relate the specification's notation or formula to the variables and operations in the code. * Document security-relevant bounds, representation choices, precomputations, and deviations from optional parts of the specification where they are enforced. * Keep secret-state lifetime and erasure behavior visible at the point where secret intermediates are created, transferred, or released. Test Status ----------- End every documented class, struct, and namespace-scope function API block with exactly one test-status marker. Do not mark constructors, methods, operators, or other members. Only use these marker in our primary code base in the ``src`` directory. * ``@tested{ExampleTest OtherTest}`` lists one or more test-suite class names separated by spaces. Names must end in ``Test``; paths and method selectors are invalid. * ``@notest{reason}`` explains in one line why a test is not applicable. * ``@needtest{reason}`` identifies missing coverage in one line. Class Organization ================== Group a class with repeated access specifiers: one empty line before each section, none between its declarations, and an optional lowercase ``//`` label. Simple value structs and dependency constraints may require a smaller or different layout. The usual section order is: 1. Private friends, nested types, enums, and aliases in dependency order. 2. Public types in dependency order. 3. Default and other constructors, destructor, copy and move constructors, then copy and move assignment. Put explicitly defaulted or deleted members in a final defaults group. 4. Main public operations. 5. Overrides, using one ``public: // implements Base`` section per base. 6. Operators: comparison, arithmetic, logical, then other operators. 7. Accessors: condition tests first, then each attribute's accessors together. 8. Other public tools, grouped only when this improves navigation. 9. Conversions: ``to...`` methods followed by static ``from...`` and other factories. 10. Private and protected methods. 11. Data members, grouped by access. Modern C++ ========== * Use portable C++20 features. Prefer concepts, structured bindings, designated initialization, and range-based loops when clearer. * Use trailing return types for non-void functions where the syntax permits, such as ``auto create() -> std::string``. Use ``void function()`` for ordinary void functions and explicit ``-> void`` on non-generic lambdas. Use concrete return and parameter types for non-generic functions and lambdas. * Use ``auto`` for values when the type is apparent or clearer; use ``const`` for immutable values and ``constexpr`` when usable at compile time. * Add ``[[nodiscard]]`` when silently discarding a result is likely to be a mistake. Add ``noexcept`` only when the operation is guaranteed not to propagate an exception. * Do not use ``static_cast(...)`` merely to silence ``[[nodiscard]]``. Select an operation whose contract matches the intended use, handle the result, or remove ``[[nodiscard]]`` when discarding the result is genuinely a normal and safe use of that API. * Mark intentionally unused named parameters ``[[maybe_unused]]``; omit an unused private overload-disambiguation tag's name. * Mark overriding functions ``override`` and classes deliberately closed to extension ``final``. * Express ownership explicitly. Use values or references by default, ``std::unique_ptr`` for unique ownership, ``std::shared_ptr`` only for shared ownership, raw pointers for deliberate non-owning or native boundaries, and ``std::optional`` for an absent value. * Expose raw pointers through public APIs only at unavoidable interoperability boundaries. Use an explicitly named ``Unsafe...`` alias or wrapper and document ownership, lifetime, nullability, and mutability. * Use lazy initialization for immutable or expensive data whose construction should be deferred. Erbsland Core Integration ========================= * Prefer ``String`` for read-only strings, ``""_el`` for literals, and ``StringFormat`` for formatting. * Prefer ``StringEditor`` as a local mutable working value for explicit in-place editing or small construction tasks. Do not use it as the default parameter or read-only storage type. * For joining fixed string segments, use ``String::fromJoined()``; for a dynamic collection, prepare and join a ``StringList``. Use ``AnyStringBuilder`` for width-independent construction and direct formatted-value appends. * Prefer regular UTF-8 types; use U8, U16, or U32 types when an API boundary or algorithm requires them. * Prefer Erbsland Core types and algorithms before ``std::`` types and algorithms. * In portable unit tests, do not construct UTF-8 text with ``\x??`` escapes because their interpretation differs between compilers. When using Erbsland Unit Test, use ``th::stdStringFromHex()`` when raw bytes are required.