This is for working on libfn to use the library see the README Development environment Building and testing requires a C 20 toolchain The namespace polyfills C 23 26 standard library utilities which the layer builds upon The minimum supported compilers are gcc 12 and clang 16 If your host OS lacks these use the devcontainer or Nix environment see nix README md Apple Clang 16 0 or MSVC 2022 or newer are also supported Exceptions to the C 20 baseline C 23 Validation Lane CMake option Requires a compiler with solid C 23 support such as GCC 15 or Clang 21 and is unsupported on MSVC C 26 Validation Lane CMake option Requires a compiler implementing such as GCC 16 and is unsupported on MSVC Standard mode feature reliance By default headers rely strictly on C 20 The C 23 validation lane compiles the same sources under without relying on C 23 features The mode relies on a single C 26 feature feature test macro If the compiler lacks this feature compilation fails with an naming the requirement never relies on post C 20 features in any configuration Building locally By default the CMake build compiles the library unit tests and examples in C 20 mode Subsequent build configuration examples vary this basic command and reuse the same build directory To compile and run a single example directly without CMake C 23 and C 26 On modern compilers GCC 15 or Clang 21 enabling requires compiles unit tests and examples in C 23 mode This enables and to validate that polyfills behave identically to standard and Enabling activates C 26 type ordering via This option does not inject a compiler language standard flag You need to select C 26 separately for example with Explicit choice via Dependency on exported target which propagates Dependency on CMake native target which propagates The CMake variable The environment variable The C 26 mode requires a compiler supporting C 26 such as GCC 16 If installed but not configured as the default select it via the and environment variables before running CMake Ensure both are exported e g on Ubuntu 26 04 Because changes the layout of and alternatives the library uses a distinct ABI namespace to prevent binary compatibility issues Enabling requires and builds tests and examples in C 26 mode no need to enable it separately compatible compiler required Sanitizers Sanitizers are enabled by default on supported platforms when is or left unset Other build types reject them To disable sanitizers in a debug build Supported platforms Linux GCC Clang Enables Address ASan Leak LSan and Undefined Behavior UBSan macOS Apple Clang Enables ASan and UBSan LSan is unsupported Unsupported Environments MSVC macOS with Homebrew GCC due to path resolution issues macOS with Homebrew Clang due to runtime process hangs from library mismatches On the above platforms the build rejects sanitizer flags causing a CMake configuration error Coverage Enabling requires GCC or Clang adds a target to generate a report Requirements gcovr 8 4 The coverage build requires s option You may install it via a Python virtual environment e g or under your directory if your package manager distributes an older version Compiler Compatibility The underlying coverage tool is detected automatically GCC Uses Clang Uses Apple Clang Uses via Documentation Enabling requires adds the target to generate the API reference in the build directory s folder The exported tree contains the site root and a versioned copy under derived from with internal links adjusted for their serving paths The live site combines this output with archived versions hosted on libfn website Requirements Doxygen 1 12 0 note newer version 1 17 0 is known to be incompatible 1 91 requires Java OpenJDK 21 or newer Graphviz providing See for the exact reference environment The documentation build fails on outdated docs or broken references verifying that Every documented entity is present on the generated site All documented API signatures match the C headers exactly Unit tests While unit test coverage target is 100% execution of every line and branch is insufficient Crucial guarantees including overload resolution conversions constraints and specifications are compile time properties and must be asserted in unit tests as well Tests must exercise interface dimensions in combination rather than merely executing lines of code Structure Consistent structure exposes these testing dimensions Test Layout Use one per file level entity class specialization or overload set and a top level for each member function Hierarchy Nest sections to test combinations value category first followed by type properties with constraint checks last A test s placement in the section hierarchy must define its purpose avoid catch all sections Test Dimensions Test across relevant dimensions including the four cv ref value categories and type traits such as triviality throwing behavior or support for default copy move construction and assignment Conciseness Keep section names short Use plain instead of BDD macros Scope Declare subject type aliases and reusable probe lambdas once at scope to avoid redundant declarations in nested sections Templates Use only when the exact same test battery applies to multiple types Alias template arguments containing commas to avoid macro expansion errors Assertion Counts Verify that restructuring tests does not alter Catch2 assertion or test counts adds one assertion per leaf section whereas parent section assertions execute once per nested leaf Assertions Match the assertion to the tested property Compiler Decided Facts Use without a runtime twin for properties decided purely by the compiler such as specifications overload viability concept satisfaction result types or constructor triviality Do not use runtime checks like on compile time constants e g Program Behavior Test dynamic behaviorcomputed values side effects or state changesusing at runtime and a corresponding twin in constant evaluation Runtime tests provide sanitizer coverage while twins verify compatibility and let the compiler diagnose undefined behavior Exceptions Test throwing paths at runtime with and assert the state of any observable operands after the exception Always pair throwing path tests with a non throwing case at runtime and in constant evaluation to ensure the code paths run to completion To isolate throwing paths in move relocation machinery use a local fixture configured to throw on its n th operation Empty Sections End sections containing only compile time assertions with to satisfy Catch2 s warnings and mark compile only branches clearly Compile time probes Conditional Specifications Pair negative assertions with their positive converses e g pair with a witness for which it is This proves that the specification is conditional rather than unconditionally false Apply the same positive control discipline to negative constraint or viability probes Substitution Contexts Ensure expressions in negative viability probes are dependent on a template parameter A expression over concrete types is not a substitution context meaning an invalid requirement triggers a hard error rather than a SFINAE failure Enclose the dependent probe in a generic lambda or a type keyed concept to yield on invalid substitution Exception Fixtures Select exception proving fixtures carefully The library s implements a separate constructor for each value category and its non const lvalue copy constructor is always A configured to throw is therefore not throwing for every value category which can hide incorrect specifications Use a simple local type if the test requires every relevant constructor to be potentially throwing Client code Code written against the library such as examples documentation snippets and reproducers serves as user guidance Graded Error Types Except for the most trivial cases do not spell a multi alternative or manually The canonical alternative order is internal and compiler dependent Use and and use to verify the deduced type Constexpr Twins Pair dynamic code with a corresponding twin that replays the same operations Because undefined behavior is ill formed in constant expressions the compiler will diagnose issues that runtime execution might silently miss Monadic Composition Prefer monadic composition over unchecked access is the library s only throwing path Do not promote an anti pattern by using it where or or can safely propagate values Requires Probes Do not rely on bare probes of calls Several compile time rejections such as mismatched branch types in or grade mismatches in are enforced via internal s which causes the probe to evaluate to while the instantiation fails with a hard compiler error Verify the call by compiling it and use dependent viability probes Type Ordering Outside of the internal type ordering does not support unnamed types or types without linkage and is not portable between GCC and Clang In portable code do not use lambdas or local types as alternatives and do not mix GCC with Clang both using in a single binary ABI & Versions Link exactly one version per binary Because the library is header only mixing different versions including distinct patch releases may cause ODR violation in your program The authors will strive to ensure that each potentially incompatible version uses a unique namespace to prevent ODR violations but validating dependency consistency remains the user s responsibility Builds with and without use different namespaces and are link incompatible by design Reproducers Standalone bug reproducers must be entirely free of undefined behavior Validate reproducers against UBSan and ASan requiring an empty standard error output rather than merely relying on a zero exit code The library currently contains workarounds for a known Clang miscompile error Header layering The directory is structured into four header trees strictly restricted to downward only dependencies May include and May include but must never include The C 23 26 polyfill standalone except for the version header below The root version header with zero dependencies and Macros scoping headers with zero dependencies To share an level facility with hoist it move the implementation into as detail headers are internal and lack Doxygen comments and expose it in as a thin wrapper re exporting following the pattern of Versioning The file in the repository root is the sole source of truth for the library version The pre commit hook automatically propagates this version to and The version header defines the macro the inline namespace wrapping and its mode less sibling wrapping Do not modify these version literals manually edit and let the hook synchronize them Inline namespaces are derived dynamically Minor Releases 0 y with y 1 Share the namespace patch releases are intended to be ABI compatible Prereleases SemVer prerelease tags append directly e g becomes and becomes Tagged on Each candidate has a unique namespace ensuring safe link incompatibility hard linker errors if mixed Un tagged on Different commits share the same namespace creating a silent ABI breaking hazard if mixed C 26 Twin Selected via keeping the suffix last The namespace is mode less its data layouts do not depend on the C 26 type ordering or language features It remains wrapped in the base version without the suffix to ensure link compatibility across compilation modes The pre commit hook enforces this layering by verifying that every block uses and every block uses Releasing A release is defined by a GPG signed tag on a commit fast forwarded onto the branch This branch is the source for documentation deploys and single header publishing Summarize immediately before a release or release candidate collapse the dated entries into a compact dateless summary of changes The summary must reference the commit SHA of the last detailed list the commit immediately preceding the first release candidate so the full historic log remains accessible The procedure Version cadence increments sequentially based on the active phase Release Candidate transitions to the release or a subsequent candidate Development Immediately after tagging the version on bumps to Breaking Cycles If a cycle introduces breaking changes the version bumps to The immediate bump to renames the inline ABI namespace e g to preventing builds of unreleased code from linking with the official release Key step rationales Fast Forward & Tag Location The branch requires linear history Fast forwarding onto the candidate commit ensures that the tag sits on a commit reachable from both and This ensures resolves properly across all pull requests and branches Tag Before Push The documentation build derives the single header banner from The tag must exist on the commit before pushing otherwise the generated artifact will use an incorrect name or fallback description The workflow refuses a release deploy from an untagged commit Atomic Push Using updates both the branch reference and the tag in a single transaction This prevents GitHub Actions workflows from triggering on a branch update before the corresponding tag is visible GitHub Release Creating the Release object triggers the workflow s job which generates and attaches to the release The flag automatically populates the PR log Provenance The job attests the single header asset before upload binding its cryptographic digest to this repository the tagged commit and the workflow run enforcing SLSA build provenance signed via Sigstore Running confirms that a downloaded copy is the authentic artifact built by this repository The release push triggers the workflow which rebuilds the site archives the tree in libfn website and deploys A release is complete when the live banner on libfn org reads lists the GitHub Release attaches and the bump to the next version is merged on Repository prerequisites The release workflow depends on three external repository configurations GitHub Pages The environment must permit deployments from the branch Branch Protection The branch must enforce linear history but must not require a pull request or require deployments to succeed which would create a deadlock blocking the push Credentials The repository secret used to archive documentation in libfn website must be a valid unexpired personal access token Pre commit This repository uses pre commit to enforce formatting of the C source code and perform other checks The details can be seen in To install git commit hooks which will run checks on the repository as you commit changes configure a Python virtual environment e g with or under your install the requirements from run in your local repository You can run all checks manually as follows If a hook modifies files e g clang format or the version sync above the commit is aborted re stage the changes and commit again Running CI on a fork The and workflows are fork aware targeting upstream only when executed from and otherwise routing reports to your fork s accounts To configure these in your fork set the following parameters under Settings Secrets and variables Actions Codecov Operates tokenless with zero configuration Because tokenless uploads are rate limited set the secret to avoid rate limiting on busy forks SonarCloud Requires the secret as well as the and repository variables Without the token SonarCloud scans are skipped the build succeeds but no report is uploaded If the token is set but variables are missing the build fails fast to point to the misconfiguration GitHub Actions workflow pitfalls Follow these conventions for files under Checkout Refs Avoid setting on without explicit justification The action defaults to on and events making explicit refs redundant Action Pinning Pin all actions to a commit SHA rather than a tag e g to secure the supply chain Dependabot maintains these pins and enforces them at commit time Job Isolation Isolate separate concerns into distinct jobs using GitHub build matrices Do not combine multiple install build and test sequences into a single job that requires manual step by step cleanup Use matrix exclusions or conditional gates where necessary Monolithic Build Slots If a test suite requires compiling all combinations assign a dedicated slot in the build matrix e g with and gate other steps with Avoid inline clean and rebuild patterns within a single job runner Multi Line Commands Use the literal block form and line continuations for multi line shell commands This ensures scripts are easily copy pasteable from diffs directly to local terminals Shell linting Install locally runs via pre commit on every inline shell block if it is available in your missing linters are silently skipped Draft Pull Requests Skip expensive actions on draft pull requests by adding the condition to each job and explicitly include in the trigger Cheap checks pre commit license validation and documentation builds should still run on drafts Skipped jobs resolve as rather than preventing downstream scan triggers from executing prematurely libfn pfn expected optional invoke_r unreachable fn VALIDATE_CXX23 VALIDATE_CXX26 std type_order libfn std c 23 LIBFN_CXX26 std type_order __cpp_lib_type_order #error pfn mkdir build && cd build cmake cmake build ctest output on failure cmake g std c 20 Iinclude examples polygon main cpp o tmp polygon VALIDATE_CXX23 ON LIBFN_TESTS ON tests pfn expected_validation cpp tests pfn optional_validation cpp pfn std expected std optional cmake DVALIDATE_CXX23 ON LIBFN_CXX26 ON std type_order target_compile_features <your target> PRIVATE cxx_std_26 libfn fn_cxx26 cxx_std_26 include_fn_cxx26 cxx_std_26 CMAKE_CXX_STANDARD 26 CXXFLAGS std c 26 CC CXX export CC usr bin gcc 16 export CXX usr bin g 16 LIBFN_CXX26 ON copack choice VALIDATE_CXX26 ON LIBFN_TESTS ON LIBFN_CXX26 ON cmake DLIBFN_CXX26 ON DVALIDATE_CXX26 ON CMAKE_BUILD_TYPE Debug cmake DLIBFN_SANITIZERS OFF DCMAKE_BUILD_TYPE Debug libasan LIBFN_COVERAGE ON LIBFN_TESTS ON coverage coverage xml cmake DLIBFN_COVERAGE ON cmake build ctest L tests_ * cmake build target coverage gcovr merge lines pip uv $HOME gcov llvm cov gcov llvm cov xcrun f LIBFN_DOCS ON LIBFN_TESTS ON export_docs docs cmake DLIBFN_DOCS ON cmake build target export_docs v<version> VERSION znai dot ci docs Dockerfile noexcept TEST_CASE SECTION & const & && const && SECTION GIVEN WHEN THEN TEST_CASE TEMPLATE_TEST_CASE SUCCEED static_assert noexcept CHECK noexcept f CHECK static_assert static_assert constexpr CHECK_THROWS_AS SUCCEED static_assert not noexcept expr noexcept requires false helper_t noexcept helper_t noexcept copack< > choice< > copack_for< > choice_for< > static_assert static_assert value and_then transform apply requires libfn apply and_then static_assert true LIBFN_CXX26 copack libfn libfn LIBFN_CXX26 include fn fn detail pfn fn detail pfn fn pfn libfn_version hpp fn detail macro_begin hpp fn detail macro_end hpp fn fn detail fn detail X hpp fn detail _name fn X hpp fn name fn functional hpp VERSION scripts sync_versions py ports libfn vcpkg json MODULE bazel include libfn_version hpp LIBFN_VERSION fn LIBFN_VERSION_BASE pfn VERSION v0_<y> dev _dev rc1 _rc1 release rcN main dev LIBFN_CXX26 _cxx26 pfn LIBFN_VERSION_BASE _cxx26 scripts check_namespace_wrap py namespace fn inline namespace LIBFN_VERSION namespace pfn inline namespace LIBFN_VERSION_BASE main release CHANGELOG md # 1 Verify that the candidate commit is green across the build matrix gh api repos libfn functional commits <main sha> check runs jq check_runs | select conclusion success | name conclusion # 2 Fast forward the release branch onto the candidate and tag it git checkout release git merge ff only <main sha> git tag s v<version> m libfn <version> <main sha> # 3 Push the branch and the tag atomically git push atomic origin release release refs tags v<version> # 4 Once the documentation deploy is green create the GitHub Release gh release create v<version> verify tag generate notes draft # 5 Review release notes press Publish release # 6 Bump VERSION on main branch to open the next cycle via a PR VERSION x y z rcN x y z x y z rc N 1 x y z main x y z 1 dev dev x y 1 0 dev dev v0_1 v0_1_dev main release main release git describe git describe docs git push atomic single header publish libfn v<version> hpp generate notes publish gh attestation verify libfn v<version> hpp repo libfn functional docs Revision v<version> versions html v<version> libfn v<version> hpp VERSION main github pages release release WEBSITE_PUSH_TOKEN pre commit config yaml pip uv $HOME ci pre commit requirements txt pre commit install # Set up a virtual environment to install pre commit python3 m venv venv source venv bin activate pip install r ci pre commit requirements txt # Install the pre commit hooks locally pre commit install # Source the virtual environment to access pre commit source venv bin activate # Run pre commit on local files pre commit run all files codecov sonarcloud libfn libfn functional CODECOV_TOKEN SONAR_TOKEN SONAR_ORGANIZATION SONAR_PROJECT_KEY github workflows ref actions checkout github sha push pull_request workflow_dispatch uses actions checkout@11bd71901b # v4 2 2 zizmor if matrix name X matrix include mode all if matrix mode all run | shellcheck actionlint shellcheck PATH if github event pull_request draft true ready_for_review pull_request types skipped success