Instruction file imported from Guo-astro/FDPS-extended (
.github/instructions/codeing_rule.instructions.md). Copyright stays with the author.
C++ coding rules for this repository are as follows, written plainly without bullets or special formatting. These rules apply to all C++ code here. If the project already defines stricter configurations such as clang-tidy, clang-format, or a naming guide, those take precedence. Serena MCP is the source of truth for understanding the codebase structure and for reuse decisions.
Before changing code, first use Serena MCP to understand modules, understand my folder architecture, ownership, and to find existing types and utilities you can reuse. Prefer the simplest correct design that addresses the actual root cause rather than applying a superficial workaround.
Architecturally, do not introduce new compatibility layers. When replacing legacy code, remove the old code as part of the same change when practical, after a short, well-scoped migration. Keep files only in their correct module or folder and confirm placement with Serena MCP. Write modular code with small, cohesive headers and translation units that each have a single responsibility. Avoid repetition by extracting common logic into functions, classes, or templates.
Follow the project’s naming conventions. If none exist, use PascalCase for types and enums, camelCase for functions and methods, snake_case for variables and data members, SCREAMING_SNAKE_CASE or kCamelCase for constants depending on the house style, and snake_case.hpp or snake_case.cpp for filenames. Use accurate filenames that reflect the primary type or purpose in the file.
Do not embed hard-coded strings in logic. Use constexpr constants, enum class values, or string_view tables. Avoid magic numbers and replace them with named constexpr constants or enum class values.
When working with floating point values, do not compare for equality directly. Use tolerant comparisons, prefer double unless there is a clear memory or performance reason to choose another type, and guard against NaN or Inf with std::isfinite.
Write comments that explain the reasoning and the non-obvious parts rather than restating the code. Document important invariants, algorithms, and decisions close to the code. For public APIs, use the project’s documentation style. Every change should include a concise change log, and for bug fixes, a short root-cause summary and an explanation of why the solution represents best practice.
Practice test-driven development in a behavior-driven style. Write or extend unit tests first for new features and for bug fixes. Use Given, When, Then naming and assertions in test names, comments, or with a framework that supports such a style. Cover boundary conditions, error cases, and invariants.
Adopt modern C++ best practices. Respect the project’s clang-tidy profile and treat warnings as errors. Prefer RAII and standard library facilities such as std::unique_ptr, std::shared_ptr, std::optional, std::variant, and the ranges and algorithms libraries. Avoid raw new and delete, and avoid implicit conversions. Keep functions small and as pure as is practical, isolating I/O and side effects. Prefer enum class over unscoped enums and prefer constexpr over preprocessor defines for constants.
Use macros only when there is no safer language feature that achieves the same result. Prefer constexpr variables, inline functions, templates, enum class, and scoped using declarations instead of macros in almost every case. Acceptable macro uses are limited to header include guards, disciplined platform or compiler feature detection, and carefully designed logging or compile-time configuration points where truly zero overhead and conditional compilation are required. When a macro is necessary, name it in SCREAMING_SNAKE_CASE with a clear project prefix to avoid collisions, do not shadow standard or third-party identifiers, and do not use leading underscores or double underscores. Keep macros out of public headers when possible; place them in internal headers with the narrowest visibility, centralize global switches in a dedicated config header, and immediately undefine purely local helper macros after use. Fully parenthesize each parameter and the entire replacement expression to avoid precedence errors, avoid passing expressions with side effects to function-like macros, and do not rely on multiple evaluation; if you would need to, replace the macro with an inline function. For multi-statement expansions, wrap the body in do { … } while (0) so it behaves as a single statement in every context. Macros must not perform hidden side effects such as modifying global state, allocating memory, or throwing exceptions; they should expand to a simple expression or a single well-scoped block. Document each macro with purpose, expected inputs, an example, and why a macro is required instead of a language feature. Prefer #if defined(NAME) over bare #ifdef for nontrivial conditions, use standard or compiler-provided feature-test macros where possible, and emit a clear #error for unsupported combinations. For include guards use a unique, project-scoped name that maps to the file path; if the team allows pragma once it may be added in addition but the guard remains the portable source of truth. Treat macro redefinition warnings as errors and periodically audit macros in reviews and CI for unparenthesized parameters, empty expansions, and collisions. If a macro is introduced as a temporary measure, create a removal task and replace it with a language construct as soon as constraints permit.
Keep the repository clean. Remove intermediate and temporary files such as .bak, .orig, editor swap files, temporary logs, and test screenshots before committing. Maintain an accurate .gitignore so artifacts do not drift into version control.
A change is complete when tests for all new or modified behavior are green and were written first, no hard-coded strings or magic numbers remain, the code builds cleanly with the linting and warning policies enforced as errors, folder placement and naming conform to project rules verified with Serena MCP, documentation is updated and a root-cause note is included for fixes, any replaced legacy code is deleted with no new compatibility layers introduced, and the build passes on continuous integration across supported toolchains.
Recommended tooling for enforcement includes clang-tidy with warnings treated as errors according to the project profile, sanitizers such as address and undefined behavior in continuous integration where feasible, compilation with -Werror -Wall -Wextra -Wpedantic, a unit test framework such as GoogleTest with CI friendly output, a repository hygiene step that fails if temporary artifacts like .bak, .orig, .tmp, or .log files exist, and a simple structure validation script that checks file paths against the allowed folders and fails if files are misplaced.
Before finish ensure you have mapped the structure with Serena MCP and reused existing facilities where appropriate, removed compatibility layers and legacy code in this change, eliminated hard-coded strings and magic numbers, conformed to naming and folder conventions, written the tests first in a Given, When, Then style and ensured they pass, handled floating point with tolerant comparisons and std::isfinite, written comments that explain the reasoning and documented the root cause for fixes, cleaned your workspace of artifacts, followed the macro rules above, and passed all linting, warnings as errors, and test checks on continuous integration.