From 505b764e3005d08453b3c551d3a3d49b1e467fc0 Mon Sep 17 00:00:00 2001 From: Nikolay Malkovsky Date: Tue, 28 Apr 2026 19:02:59 +0300 Subject: [PATCH 1/4] small improvement --- include/pixie/bits.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/pixie/bits.h b/include/pixie/bits.h index 6c2d3ab..33cacae 100644 --- a/include/pixie/bits.h +++ b/include/pixie/bits.h @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -766,6 +765,7 @@ static inline __m128i excess_nibble_pos2_lut() noexcept { -3, -1, -1, 1, -1, 1, 1, 3}; return _mm_load_si128((const __m128i*)lut); } + #endif static inline void excess_positions_512_lut(const uint64_t* s, @@ -789,11 +789,10 @@ static inline void excess_positions_512_lut(const uint64_t* s, int cur = 0; for (int w = 0; w < 8; ++w) { const uint64_t word = s[w]; - const int word_delta = 2 * (int)std::popcount(word) - 64; + const int word_delta = 2 * static_cast(std::popcount(word)) - 64; const int target_local = target_x - cur; if (target_local < -64 || target_local > 64) { - out[w] = 0; cur += word_delta; continue; } @@ -834,8 +833,10 @@ static inline void excess_positions_512_lut(const uint64_t* s, _mm_add_epi8(base, _mm_shuffle_epi8(vpos2, nibbles)), vzero); uint16_t bits2 = static_cast(_mm_movemask_epi8(cmp2)); - __m128i cmp3 = _mm_cmpeq_epi8( - _mm_add_epi8(base, _mm_shuffle_epi8(vdelta, nibbles)), vzero); + // cmp3 checks base + delta == 0, i.e. excl - target_local + delta == 0. + // Since excl + delta == ps (the inclusive prefix sum), this is simply + // ps == target_local. Saves one add and one shuffle. + __m128i cmp3 = _mm_cmpeq_epi8(ps, vtarget_local); uint16_t bits3 = static_cast(_mm_movemask_epi8(cmp3)); out[w] = _pdep_u64(bits0, 0x1111111111111111ULL) | From fdf70ead3b6ab546974d66fdd8085153d414a729 Mon Sep 17 00:00:00 2001 From: Nikolay Malkovsky Date: Thu, 7 May 2026 14:35:18 +0300 Subject: [PATCH 2/4] Optimize excess_positions_512_lut by precomputing t --- include/pixie/bits.h | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/include/pixie/bits.h b/include/pixie/bits.h index 33cacae..5285604 100644 --- a/include/pixie/bits.h +++ b/include/pixie/bits.h @@ -784,7 +784,6 @@ static inline void excess_positions_512_lut(const uint64_t* s, const __m128i vpos1 = excess_nibble_pos1_lut(); const __m128i vpos2 = excess_nibble_pos2_lut(); const __m128i vnibble_mask = _mm_set1_epi8(0x0F); - const __m128i vzero = _mm_setzero_si128(); int cur = 0; for (int w = 0; w < 8; ++w) { @@ -815,30 +814,29 @@ static inline void excess_positions_512_lut(const uint64_t* s, __m128i vtarget_local = _mm_set1_epi8(static_cast(target_local)); // Overflow safety: excl[i] ∈ [-60, 60] (exclusive prefix sum of up to // 15 deltas each in [-4, +4]), target_local ∈ [-64, 64]. - // base = excl - target_local ∈ [-124, 124], fits in int8. - // base + pos_j ∈ [-128, 128]. The boundary value -128 is exactly - // representable in int8 and ≠ 0. The value +128 wraps to -128 in - // int8, which is also ≠ 0, so cmpeq_epi8 produces no false positive. - __m128i base = _mm_sub_epi8(excl, vtarget_local); - - __m128i cmp0 = _mm_cmpeq_epi8( - _mm_add_epi8(base, _mm_shuffle_epi8(vpos0, nibbles)), vzero); + // t = target_local - excl ∈ [-124, 124], fits perfectly in int8. + __m128i t = _mm_sub_epi8(vtarget_local, excl); + + __m128i cmp0 = _mm_cmpeq_epi8(_mm_shuffle_epi8(vpos0, nibbles), t); uint16_t bits0 = static_cast(_mm_movemask_epi8(cmp0)); - __m128i cmp1 = _mm_cmpeq_epi8( - _mm_add_epi8(base, _mm_shuffle_epi8(vpos1, nibbles)), vzero); + __m128i cmp1 = _mm_cmpeq_epi8(_mm_shuffle_epi8(vpos1, nibbles), t); uint16_t bits1 = static_cast(_mm_movemask_epi8(cmp1)); - __m128i cmp2 = _mm_cmpeq_epi8( - _mm_add_epi8(base, _mm_shuffle_epi8(vpos2, nibbles)), vzero); + __m128i cmp2 = _mm_cmpeq_epi8(_mm_shuffle_epi8(vpos2, nibbles), t); uint16_t bits2 = static_cast(_mm_movemask_epi8(cmp2)); - // cmp3 checks base + delta == 0, i.e. excl - target_local + delta == 0. + // cmp3 conceptually checks delta == t, i.e. delta == target_local - excl. // Since excl + delta == ps (the inclusive prefix sum), this is simply // ps == target_local. Saves one add and one shuffle. __m128i cmp3 = _mm_cmpeq_epi8(ps, vtarget_local); uint16_t bits3 = static_cast(_mm_movemask_epi8(cmp3)); + // Note: We use movemask + pdep to interleave bits instead of pure AVX2 + // (e.g. maddubs + packus). While pdep is microcoded/slow on older AMD CPUs + // (Zen 2), it is hardware-accelerated and ~15% faster on modern + // architectures (Zen 3+, Intel) due to fewer vector operations and a + // shorter dependency chain. out[w] = _pdep_u64(bits0, 0x1111111111111111ULL) | _pdep_u64(bits1, 0x2222222222222222ULL) | _pdep_u64(bits2, 0x4444444444444444ULL) | From 5320bf53955bfad037eb552bbb6b2bbb61feee2c Mon Sep 17 00:00:00 2001 From: Nikolay Malkovsky Date: Sat, 9 May 2026 17:31:21 +0300 Subject: [PATCH 3/4] Improved skills --- .kilo/skills/benchmarks/SKILL.md | 35 +- .kilo/skills/cmake/SKILL.md | 23 +- .kilo/skills/setup-cpp-repo/SKILL.md | 137 +++ .../references/project_structure.md | 116 ++ .../scripts/init_cpp_project.py | 1051 +++++++++++++++++ 5 files changed, 1346 insertions(+), 16 deletions(-) create mode 100644 .kilo/skills/setup-cpp-repo/SKILL.md create mode 100644 .kilo/skills/setup-cpp-repo/references/project_structure.md create mode 100644 .kilo/skills/setup-cpp-repo/scripts/init_cpp_project.py diff --git a/.kilo/skills/benchmarks/SKILL.md b/.kilo/skills/benchmarks/SKILL.md index 354db03..0136280 100644 --- a/.kilo/skills/benchmarks/SKILL.md +++ b/.kilo/skills/benchmarks/SKILL.md @@ -9,10 +9,23 @@ You now have expertise in running and interpreting Pixie benchmarks. Follow thes ## Build Directory Convention -Uses the same suffix convention as the cmake skill: +Use a short commit hash suffix for committed revisions: ```bash -BUILD_SUFFIX=local +BUILD_SUFFIX=$(git rev-parse --short HEAD) +``` + +If the worktree has uncommitted changes, append a descriptive suffix so results +cannot be confused with a clean HEAD build: + +```bash +BUILD_SUFFIX=$(git rev-parse --short HEAD)-dirty +``` + +If not a git repository, use + +```bash +BUILD_SUFFIX=agent ``` ## CRITICAL: Never Run Benchmarks from a Debug Build @@ -27,10 +40,10 @@ BUILD_SUFFIX=local If benchmarks affected by the changes are easily tractable build only related targets. -**Pure timing (benchmarks-all, Release):** +**Pure timing (benchmarks, Release):** ```bash -cmake -B build/benchmarks-all_${BUILD_SUFFIX} -DCMAKE_BUILD_TYPE=Release -DPIXIE_BENCHMARKS=ON -cmake --build build/benchmarks-all_${BUILD_SUFFIX} --config Release -j +cmake -B build/benchmarks_${BUILD_SUFFIX} -DCMAKE_BUILD_TYPE=Release -DPIXIE_BENCHMARKS=ON +cmake --build build/benchmarks_${BUILD_SUFFIX} --config Release -j ``` **Hardware counters / verbose report (benchmarks-diagnostic, RelWithDebInfo, Linux only):** @@ -69,10 +82,10 @@ Binary paths vary by generator type: ```bash # Multi-config (MSVC/Xcode) -build/benchmarks-all_${BUILD_SUFFIX}/Release/benchmarks +build/benchmarks_${BUILD_SUFFIX}/Release/benchmarks # Single-config (Ninja/Make) -build/benchmarks-all_${BUILD_SUFFIX}/benchmarks +build/benchmarks_${BUILD_SUFFIX}/benchmarks ``` ### Filter benchmarks with a regex (FILTER parameter) @@ -81,10 +94,10 @@ build/benchmarks-all_${BUILD_SUFFIX}/benchmarks FILTER="BM_Rank" # change to match benchmark names, e.g. "BM_Select", "BM_Louds", "" # Multi-config -build/benchmarks-all_${BUILD_SUFFIX}/Release/benchmarks --benchmark_filter="${FILTER}" +build/benchmarks_${BUILD_SUFFIX}/Release/benchmarks --benchmark_filter="${FILTER}" # Single-config -build/benchmarks-all_${BUILD_SUFFIX}/benchmarks --benchmark_filter="${FILTER}" +build/benchmarks_${BUILD_SUFFIX}/benchmarks --benchmark_filter="${FILTER}" ``` Examples: @@ -110,7 +123,7 @@ build/benchmarks-diagnostic_${BUILD_SUFFIX}/RelWithDebInfo/benchmarks \ ### Save results to file ```bash -build/benchmarks-all_${BUILD_SUFFIX}/Release/benchmarks \ +build/benchmarks_${BUILD_SUFFIX}/Release/benchmarks \ --benchmark_filter="${FILTER}" \ --benchmark_report_aggregates_only=true \ --benchmark_display_aggregates_only=true \ @@ -167,7 +180,7 @@ perf script -F +pid > perf.data.txt ## Best Practices 1. **Never run from a Debug binary**: always use `--config Release` at build time; check path contains `Release/` -2. **Use benchmarks-all for clean timing**: Release optimizations, no debug info, no libpfm overhead +2. **Use benchmarks for clean timing**: Release optimizations, no debug info, no libpfm overhead 3. **Use benchmarks-diagnostic for hardware counters**: RelWithDebInfo + libpfm; Linux only 4. **Use perf for deep profiling**: when counters point to a hotspot but don't explain it 5. **Pin CPU frequency** before timing runs: `sudo cpupower frequency-set -g performance` diff --git a/.kilo/skills/cmake/SKILL.md b/.kilo/skills/cmake/SKILL.md index 5ebfb5d..d3c7096 100644 --- a/.kilo/skills/cmake/SKILL.md +++ b/.kilo/skills/cmake/SKILL.md @@ -9,10 +9,23 @@ You now have expertise in building and configuring CMake projects. Follow these ## Build Directory Convention -Always use a suffix to keep build directories isolated per machine/user: +Use a short commit hash suffix for committed revisions: ```bash -BUILD_SUFFIX=local # change per machine, e.g. "ci", "john", "avx2" +BUILD_SUFFIX=$(git rev-parse --short HEAD) +``` + +If the worktree has uncommitted changes, append a descriptive suffix so generated +artifacts cannot be confused with a clean HEAD build: + +```bash +BUILD_SUFFIX=$(git rev-parse --short HEAD)-dirty +``` + +If not a git repository, use + +```bash +BUILD_SUFFIX=agent ``` Build directories follow the pattern `build/_`. @@ -55,10 +68,10 @@ cmake -B build/coverage_${BUILD_SUFFIX} -DCMAKE_BUILD_TYPE=Debug -DPIXIE_BENCHMA cmake --build build/coverage_${BUILD_SUFFIX} -j ``` -All benchmarks (mirrors `benchmarks-all` preset): +Benchmarks (mirrors `benchmarks` preset): ```bash -cmake -B build/benchmarks-all_${BUILD_SUFFIX} -DCMAKE_BUILD_TYPE=Release -DPIXIE_BENCHMARKS=ON -cmake --build build/benchmarks-all_${BUILD_SUFFIX} -j +cmake -B build/benchmarks_${BUILD_SUFFIX} -DCMAKE_BUILD_TYPE=Release -DPIXIE_BENCHMARKS=ON +cmake --build build/benchmarks_${BUILD_SUFFIX} -j ``` ## Additional Feature Options diff --git a/.kilo/skills/setup-cpp-repo/SKILL.md b/.kilo/skills/setup-cpp-repo/SKILL.md new file mode 100644 index 0000000..808f997 --- /dev/null +++ b/.kilo/skills/setup-cpp-repo/SKILL.md @@ -0,0 +1,137 @@ +--- +name: setup-cpp-repo +description: Scaffold a new C++20 repository with CMake, Google Test, Google Benchmark, CI workflows, Doxygen docs, and Chromium code style. Use when the user asks to create a new C++ project, set up a C++ library, or initialize a C++ repository with modern tooling. +--- + +# setup-cpp-repo + +## Overview + +This skill generates a complete C++20 project scaffold following the conventions of the Pixie succinct data structures library. The generated repository is header-only by default and includes: + +- CMake build system with presets +- Google Test for unit testing +- Google Benchmark for performance benchmarks +- Doxygen documentation with doxygen-awesome-css theme +- GitHub Actions CI workflows (ASan, lint, coverage, docs) +- Chromium C++ code style via `.clang-format` +- `AGENTS.md` for AI coding assistant guidelines + +## When to Use This Skill + +Use this skill when: +- The user wants to create a new C++ library or project from scratch +- The user asks for a "C++ project template" or "C++ repo setup" +- The user needs CMake + Google Test + benchmark scaffolding +- The user wants to follow Pixie-style conventions (header-only, AVX-512 optional, Doxygen docs) + +Do **not** use this skill when: +- Working with an existing codebase (use the `cmake` skill instead) +- The project is not C++ (use a different skill) +- The user only wants a single file or snippet + +## Workflow + +### Step 1: Gather Parameters + +Ask the user for (or infer from context): +- **Project name** (required): Hyphenated lowercase identifier, e.g., `my-lib` +- **Namespace** (optional): C++ namespace. Defaults to project name with hyphens removed, e.g., `mylib` +- **Output directory** (optional): Where to create the project. Defaults to current directory. + +### Step 2: Run the Generator + +Execute the generation script: + +```bash +python3 .kilo/skills/setup-cpp-repo/scripts/init_cpp_project.py \ + --name \ + [--namespace ] \ + [--output-dir ] +``` + +Example: +```bash +python3 .kilo/skills/setup-cpp-repo/scripts/init_cpp_project.py \ + --name succinct-lib --namespace succinct --output-dir . +``` + +### Step 3: Verify the Scaffold + +After generation, the project structure should look like: + +``` +/ +├── CMakeLists.txt +├── CMakePresets.json +├── .clang-format +├── .gitignore +├── README.md +├── AGENTS.md +├── include/ +│ └── / +│ └── .hpp +├── src/ +│ ├── tests/ +│ │ └── unittests.cpp +│ ├── benchmarks/ +│ │ └── benchmarks.cpp +│ └── docs/ +│ ├── Doxyfile.in +│ └── images/ +├── scripts/ +│ └── coverage_report.sh +└── .github/ + └── workflows/ + ├── build-test.yml + ├── linter.yml + ├── coverage.yml + └── doxygen.yml +``` + +### Step 4: Initial Build and Test + +Change into the project directory and run an initial build to verify everything works: + +```bash +cd +cmake --preset release +cmake --build --preset release -j +./build/release/unittests +``` + +If the build and tests pass, the scaffold is ready. + +### Step 5: Hand Off to cmake Skill + +After project creation, use the **`cmake` skill** (`.kilo/skills/cmake/SKILL.md`) for all subsequent build operations. The `cmake` skill documents: +- Build directory conventions with git short-hash suffixes +- How to replicate preset settings with custom build directories +- AddressSanitizer, coverage, and benchmark workflows +- Best practices for out-of-source builds + +## Customization Guide + +### Adding More Test Executables + +Edit `CMakeLists.txt` and add new `add_executable` blocks under the `if(_TESTS)` section, following the pattern of the existing `unittests` target. + +Update `scripts/coverage_report.sh` to run any new test binaries. + +Update `.github/workflows/build-test.yml` to execute new test binaries in CI. + +### Adding More Benchmark Executables + +Edit `CMakeLists.txt` and add new `add_executable` blocks under the `if(_BENCHMARKS)` section, following the pattern of the existing `benchmarks` target. + +### Adding Third-Party Dependencies + +For header-only libraries, prefer `FetchContent` in `CMakeLists.txt`. For compiled libraries, consider vendoring or using a package manager (Conan, vcpkg). + +### Modifying Doxygen Configuration + +Edit `src/docs/Doxyfile.in`. The generated version is intentionally minimal (only non-default settings). Add or override settings as needed. Run `doxygen -g` to see all available options. + +## Reference + +See `references/project_structure.md` for a detailed breakdown of every generated file and its purpose. diff --git a/.kilo/skills/setup-cpp-repo/references/project_structure.md b/.kilo/skills/setup-cpp-repo/references/project_structure.md new file mode 100644 index 0000000..ea80877 --- /dev/null +++ b/.kilo/skills/setup-cpp-repo/references/project_structure.md @@ -0,0 +1,116 @@ +# Generated Project Structure Reference + +This document describes every file and directory generated by `init_cpp_project.py` and its purpose. + +## Root Files + +### `CMakeLists.txt` +Main CMake configuration. Defines: +- C++20 standard requirements +- `MARCH` cache variable (defaults to `native`) +- `DISABLE_AVX512` option for SIMD fallback +- `ENABLE_ADDRESS_SANITIZER` option for ASan builds +- `_COVERAGE` option for gcov instrumentation +- Build options: `_TESTS`, `_BENCHMARKS`, `_DIAGNOSTICS`, `_DOCS` +- FetchContent dependencies: Google Test, Google Benchmark, spdlog (diagnostics only), Doxygen theme +- Test executable: `unittests` +- Benchmark executable: `benchmarks` +- Custom target: `docs` (when Doxygen is enabled) + +### `CMakePresets.json` +CMake presets (version 4) with a hidden `base` preset. Defines presets for: +- `debug` — Debug build +- `release` — Release build +- `benchmarks` — Release with benchmarks enabled +- `benchmarks-diagnostic` — RelWithDebInfo with diagnostics and libpfm +- `docs` — Documentation build +- `coverage` — Debug with coverage instrumentation +- `asan` — Debug with AddressSanitizer + +### `.clang-format` +Chromium-based C++ formatting configuration. Simplified from the full Chromium style by removing Windows-specific include priorities and IPC macro block definitions. Key settings: +- `BasedOnStyle: Chromium` +- `Standard: Cpp11` +- `InsertBraces: true` +- `InsertNewlineAtEOF: true` +- `IncludeBlocks: Regroup` with generic priority categories + +### `.gitignore` +Standard C++ project ignores: +- `build/`, `.vscode/`, `Testing/` +- `plans/*`, `venv/`, `docs/*` +- `CMakeUserPresets.json` +- `_deps/`, gcov outputs (`*.gcda`, `*.gcno`, `*.gcov`) + +### `README.md` +Minimal project README used as the Doxygen main page. + +### `AGENTS.md` +Project documentation for AI coding assistants. Contains: +- Project overview and architecture conventions +- Technology stack (C++20, CMake, Google Test, Google Benchmark) +- Build commands with all CMake options +- Testing patterns and style guidelines +- Common tasks for AI agents (adding components, modifying SIMD code, adding tests) +- Performance philosophy + +## Directories + +### `include//` +Header-only library API. Contains a placeholder header (`.hpp`) with: +- Doxygen file documentation +- Example function in the project's namespace +- `#pragma once` guard + +### `src/tests/` +Unit test scaffold. Contains `unittests.cpp` with: +- Google Test includes +- Basic assertion test against the placeholder header +- `gtest_main` supplies the test runner entry point + +### `src/benchmarks/` +Benchmark scaffold. Contains `benchmarks.cpp` with: +- Google Benchmark includes +- Example benchmark using `benchmark::DoNotOptimize` +- `BENCHMARK_MAIN()` macro + +### `src/docs/` +Doxygen configuration. Contains: +- `Doxyfile.in` — Trimmed Doxygen config (~300 lines vs. 1100+ in full). Only non-default settings are specified. Key templated values: + - `PROJECT_NAME` + - `INPUT` (points to `include/` and `README.md`) + - `STRIP_FROM_PATH` (strips source dir from file paths) + - `IMAGE_PATH` + - `HTML_EXTRA_STYLESHEET` (doxygen-awesome-css) + - `USE_MDFILE_AS_MAINPAGE` +- `images/` — Empty directory for documentation images + +### `scripts/` +Utility scripts. Contains: +- `coverage_report.sh` — Runs the `coverage` CMake preset, executes tests, and generates gcov reports. Excludes `_deps/`, `third_party/`, and `src/benchmarks/` from coverage. + +### `.github/workflows/` +CI/CD workflows: + +#### `build-test.yml` +Builds the project with AddressSanitizer and runs unit tests on `ubuntu-latest`. Triggered on pushes and PRs to `main`. + +#### `linter.yml` +Runs `clang-format --dry-run --Werror` on all C/C++ files. Triggered on pushes to `main` and all PRs. + +#### `coverage.yml` +Runs the coverage script and uploads results to Codecov. Also uploads coverage artifacts. Triggered on pushes and PRs to `main`. + +#### `doxygen.yml` +Installs Doxygen, builds documentation with the `docs` preset, and deploys HTML output to GitHub Pages. Triggered on pushes to `main` and manual dispatch. + +## Template Substitution + +All generated files use these placeholders, replaced by the script: + +| Placeholder | Example input | Example output | +|-------------|---------------|----------------| +| `{{PROJECT_NAME}}` | `my-lib` | `my-lib` | +| `{{NAMESPACE}}` | `mylib` | `mylib` | +| `{{PROJECT_NAME_UPPER}}` | `MY_LIB` | `MY_LIB` | +| `{{HEADER_NAME}}` | `my_lib.hpp` | `my_lib.hpp` | diff --git a/.kilo/skills/setup-cpp-repo/scripts/init_cpp_project.py b/.kilo/skills/setup-cpp-repo/scripts/init_cpp_project.py new file mode 100644 index 0000000..c859090 --- /dev/null +++ b/.kilo/skills/setup-cpp-repo/scripts/init_cpp_project.py @@ -0,0 +1,1051 @@ +#!/usr/bin/env python3 +""" +init_cpp_project.py - Scaffold a new C++20 repository following Pixie conventions. + +Usage: + init_cpp_project.py --name [--namespace ] [--output-dir ] + +Example: + init_cpp_project.py --name my-lib --namespace mylib --output-dir . +""" + +import argparse +import os +import sys +from pathlib import Path + + +# --------------------------------------------------------------------------- +# Helper functions +# --------------------------------------------------------------------------- + +def to_upper(name: str) -> str: + """Convert project name to uppercase with underscores.""" + return name.replace("-", "_").upper() + + +def to_snake(name: str) -> str: + """Convert project name to snake_case for filenames.""" + return name.replace("-", "_") + + +# --------------------------------------------------------------------------- +# Templates +# --------------------------------------------------------------------------- + +CMAKE_LISTS_TXT = """cmake_minimum_required(VERSION 3.18) +project({{PROJECT_NAME}}) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(MARCH "native" CACHE STRING "march compiler flag") +add_compile_options("-march=${MARCH}") +message(STATUS "MARCH is '${MARCH}'") + +option(DISABLE_AVX512 "Disable AVX512 instructions" OFF) +if(DISABLE_AVX512) + add_compile_options("-mno-avx512f") + message(STATUS "DISABLE_AVX512 is ON") +endif() + +option(ENABLE_ADDRESS_SANITIZER "Enable AddressSanitizer" OFF) +if(ENABLE_ADDRESS_SANITIZER) + add_compile_options(-fsanitize=address -fno-omit-frame-pointer) + add_link_options(-fsanitize=address) + message(STATUS "AddressSanitizer is ON") +endif() + +option({{PROJECT_NAME_UPPER}}_COVERAGE "Enable coverage instrumentation" OFF) +if({{PROJECT_NAME_UPPER}}_COVERAGE) + add_compile_options(-O0 -g --coverage) + add_link_options(--coverage) + message(STATUS "Coverage instrumentation is ON") +endif() + +# --------------------------------------------------------------------------- +# Build options +# --------------------------------------------------------------------------- +option({{PROJECT_NAME_UPPER}}_TESTS "Build unit tests" ON) +option({{PROJECT_NAME_UPPER}}_BENCHMARKS "Build benchmarks" OFF) +option({{PROJECT_NAME_UPPER}}_DIAGNOSTICS "Include diagnostic logs" OFF) +option({{PROJECT_NAME_UPPER}}_DOCS "Build Doxygen documentation" OFF) + +if({{PROJECT_NAME_UPPER}}_DIAGNOSTICS) + add_compile_definitions({{PROJECT_NAME_UPPER}}_DIAGNOSTICS) + set({{PROJECT_NAME_UPPER}}_DIAGNOSTICS_LIBS spdlog::spdlog_header_only) +endif() + +# --------------------------------------------------------------------------- +# Dependencies (fetched only when needed) +# --------------------------------------------------------------------------- +include(FetchContent) + +if({{PROJECT_NAME_UPPER}}_DIAGNOSTICS) + set(SPDLOG_BUILD_SHARED OFF CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_EXAMPLE OFF CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_TESTING OFF CACHE BOOL "" FORCE) + set(SPDLOG_INSTALL OFF CACHE BOOL "" FORCE) + FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog.git + GIT_TAG v1.14.1 + ) + FetchContent_MakeAvailable(spdlog) +endif() + +if({{PROJECT_NAME_UPPER}}_BENCHMARKS) + FetchContent_Declare( + googlebenchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG v1.9.4 + ) + set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable Google Benchmark tests") + FetchContent_MakeAvailable(googlebenchmark) +endif() + +if({{PROJECT_NAME_UPPER}}_TESTS) + if(NOT TARGET gtest_main) + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.17.0 + ) + FetchContent_MakeAvailable(googletest) + endif() + include(GoogleTest) +endif() + +# --------------------------------------------------------------------------- +# Unit tests +# --------------------------------------------------------------------------- +if({{PROJECT_NAME_UPPER}}_TESTS) + enable_testing() + + add_executable(unittests + src/tests/unittests.cpp) + target_include_directories(unittests + PUBLIC include) + target_link_libraries(unittests + gtest_main + ${{{PROJECT_NAME_UPPER}}_DIAGNOSTICS_LIBS}) + gtest_discover_tests(unittests) +endif() + +# --------------------------------------------------------------------------- +# Benchmarks +# --------------------------------------------------------------------------- +if({{PROJECT_NAME_UPPER}}_BENCHMARKS) + add_executable(benchmarks + src/benchmarks/benchmarks.cpp) + target_include_directories(benchmarks + PUBLIC include) + target_link_libraries(benchmarks + benchmark + benchmark_main + ${{{PROJECT_NAME_UPPER}}_DIAGNOSTICS_LIBS}) +endif() + +# --------------------------------------------------------------------------- +# Documentation (Doxygen) +# --------------------------------------------------------------------------- +if({{PROJECT_NAME_UPPER}}_DOCS) + find_package(Doxygen REQUIRED) + + FetchContent_Declare( + doxygen-awesome-css + URL https://github.com/jothepro/doxygen-awesome-css/archive/refs/heads/main.zip + ) + FetchContent_MakeAvailable(doxygen-awesome-css) + + FetchContent_GetProperties(doxygen-awesome-css SOURCE_DIR AWESOME_CSS_DIR) + + set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/src/docs/Doxyfile.in) + set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/docs/Doxyfile) + configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) + + add_custom_target(docs + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM) +endif() +""" + +CMAKE_PRESETS_JSON = """{ + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 18, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "debug", + "displayName": "Debug", + "inherits": "base", + "binaryDir": "${sourceDir}/build/debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "release", + "displayName": "Release", + "inherits": "base", + "binaryDir": "${sourceDir}/build/release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "benchmarks", + "displayName": "Benchmarks", + "inherits": "base", + "binaryDir": "${sourceDir}/build/benchmarks", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "{{PROJECT_NAME_UPPER}}_BENCHMARKS": "ON" + } + }, + { + "name": "benchmarks-diagnostic", + "displayName": "Benchmarks diagnostic build", + "inherits": "base", + "binaryDir": "${sourceDir}/build/release-with-deb", + "cacheVariables": { + "BENCHMARK_ENABLE_LIBPFM": "ON", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "{{PROJECT_NAME_UPPER}}_DIAGNOSTICS": "ON", + "{{PROJECT_NAME_UPPER}}_BENCHMARKS": "ON" + } + }, + { + "name": "docs", + "displayName": "Docs", + "inherits": "base", + "binaryDir": "${sourceDir}/build/docs", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "{{PROJECT_NAME_UPPER}}_DOCS": "ON" + } + }, + { + "name": "coverage", + "displayName": "Coverage", + "inherits": "base", + "binaryDir": "${sourceDir}/build/coverage", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "{{PROJECT_NAME_UPPER}}_BENCHMARKS": "OFF", + "{{PROJECT_NAME_UPPER}}_COVERAGE": "ON" + } + }, + { + "name": "asan", + "displayName": "AddressSanitizer", + "inherits": "base", + "binaryDir": "${sourceDir}/build/asan", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "{{PROJECT_NAME_UPPER}}_BENCHMARKS": "OFF", + "ENABLE_ADDRESS_SANITIZER": "ON" + } + } + ], + "buildPresets": [ + { + "name": "debug", + "displayName": "Build Debug", + "configurePreset": "debug" + }, + { + "name": "release", + "displayName": "Build Release", + "configurePreset": "release" + }, + { + "name": "benchmarks", + "displayName": "Build Benchmarks", + "configurePreset": "benchmarks" + }, + { + "name": "benchmarks-diagnostic", + "displayName": "Benchmarks diagnostic", + "configurePreset": "benchmarks-diagnostic" + }, + { + "name": "docs", + "displayName": "Build Docs", + "configurePreset": "docs", + "targets": [ + "docs" + ] + }, + { + "name": "coverage", + "displayName": "Build Coverage", + "configurePreset": "coverage" + }, + { + "name": "asan", + "displayName": "Build AddressSanitizer", + "configurePreset": "asan" + } + ] +} +""" + +CLANG_FORMAT = """# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector >' in existing files gets formatted to +# 'vector>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11 + +# TODO(crbug.com/1392808): Remove when InsertBraces has been upstreamed into +# the Chromium style (is implied by BasedOnStyle: Chromium). +InsertBraces: true +InsertNewlineAtEOF: true + +# Sort #includes by following +# https://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes +IncludeBlocks: Regroup +IncludeCategories: + # C system headers. + - Regex: '^<.*\\.h>' + Priority: 1 + # C++ standard library headers. + - Regex: '^<.*>' + Priority: 2 + # Project headers (quoted includes). + - Regex: '^".*"' + Priority: 3 + # Other libraries. + - Regex: '.*' + Priority: 4 +""" + +GITIGNORE = """build/ +.vscode/ +Testing/ +plans/* +venv/ +docs/* +src/docs/presentations/* +CMakeUserPresets.json +_deps/ +*.gcda +*.gcno +*.gcov +""" + +README_MD = """# {{PROJECT_NAME}} + +{{PROJECT_NAME}} is a C++20 header-only library. + +## Build + +```bash +cmake --preset release +cmake --build --preset release -j +./build/release/unittests +``` +""" + +AGENTS_MD = """# AGENTS.md - AI Coding Assistant Guidelines for {{PROJECT_NAME}} + +## Project Overview + +{{PROJECT_NAME}} is a **C++20 header-only library**. It provides [TODO: brief description]. + +## Skills + +./.kilo/skills/ contains project-specific skills, use them when appropriate. + +## Architecture + +### Project Layout Conventions + +- **`include/`**: Header-only library API (all implementations here, no `.cpp` files) +- **`src/*_tests.cpp`**: Unit tests (Google Test) +- **`src/*_benchmarks.cpp`**: Performance benchmarks (Google Benchmark) +- **`src/docs/`**: Doxygen configuration + +### Key Design Decisions + +1. **Header-only library**: All code in `include/`; no compiled library. +2. **Non-owning spans**: Use `std::span` for external data where appropriate. +3. **SIMD conditional compilation**: Use `#ifdef {{PROJECT_NAME_UPPER}}_AVX512_SUPPORT` / `{{PROJECT_NAME_UPPER}}_AVX2_SUPPORT` with scalar fallbacks. +4. **Target domain**: Optimized for practical data sizes. +5. **Platform**: Linux/Unix is the primary target platform. + +### Why Header-Only? + +- **SIMD flexibility**: Users compile with their target `-march` flags. +- **Better inlining**: Compiler sees full implementation. +- **No ABI issues**: Works across compilers and standard library versions. +- **Easy integration**: Users just `#include` headers. +- **Template-friendly**: No explicit instantiation needed. + +## Technology Stack + +- **Language**: C++20 (required features: `std::span`, `std::popcount`, ``) +- **Build**: CMake >= 3.18 +- **Testing**: Google Test v1.17.0 +- **Benchmarking**: Google Benchmark v1.9.4 +- **SIMD**: AVX-512 (primary), AVX2 (fallback), scalar fallbacks +- **Style**: Chromium C++ style (`.clang-format`) + +### Dependencies + +The library itself is header-only and has **no runtime dependencies**. Build-time dependencies are managed via CMake FetchContent and controlled by options: + +| Option | Default | What it enables | +|--------|---------|-----------------| +| `{{PROJECT_NAME_UPPER}}_TESTS` | `ON` | Unit tests (fetches Google Test) | +| `{{PROJECT_NAME_UPPER}}_BENCHMARKS` | `OFF` | Benchmarks (fetches Google Benchmark) | + +## Build Commands + +```bash +# Standard build (Release) +cmake -B build/release -DCMAKE_BUILD_TYPE=Release +cmake --build build/release -j + +# Debug build +cmake -B build/debug -DCMAKE_BUILD_TYPE=Debug +cmake --build build/debug -j + +# Without AVX-512 (AVX2 fallback) +cmake -B build/release -DDISABLE_AVX512=ON +cmake --build build/release -j + +# With AddressSanitizer +cmake -B build/asan -DENABLE_ADDRESS_SANITIZER=ON +cmake --build build/asan -j + +# Custom march flag +cmake -B build/release -DMARCH=icelake-client +cmake --build build/release -j + +# Tests only (no benchmarks) +cmake -B build/release -D{{PROJECT_NAME_UPPER}}_BENCHMARKS=OFF +cmake --build build/release -j +``` + +## Testing + +### Running Tests + +```bash +./build/release/unittests +``` + +### Testing Patterns + +- **Differential testing**: Compare against naive reference implementations. +- **Randomized testing**: Random inputs with configurable seed. +- **Exhaustive short inputs**: Test all patterns for small sizes. + +## Code Style Guidelines + +1. **Formatting**: Run `clang-format` before committing (Chromium style) +2. **Namespace**: All library code in `{{NAMESPACE}}` namespace +3. **Documentation**: Use Doxygen-style comments for public API +4. **Constants**: Use `constexpr` for compile-time values +5. **Alignment**: Be aware of data alignment; prefer 64-byte aligned array allocations where performance matters + +## CI/CD Workflows + +- **build-test.yml**: Builds and runs tests with AddressSanitizer +- **linter.yml**: Clang-format checks on all C/C++ files +- **coverage.yml**: Coverage reporting with codecov upload +- **doxygen.yml**: Documentation generation and GitHub Pages deployment + +## Common Tasks for AI Agents + +### Adding a New Component + +1. Create header in `include/{{NAMESPACE}}/` with Doxygen documentation +2. Add unit tests in `src/tests/_tests.cpp` +3. Add benchmarks in `src/benchmarks/_benchmarks.cpp` +4. Update `CMakeLists.txt` with new executables +5. Run `clang-format` on new files + +### Modifying SIMD Code + +1. Provide implementations for: + - AVX-512 (`#ifdef {{PROJECT_NAME_UPPER}}_AVX512_SUPPORT`) + - AVX2 (`#ifdef {{PROJECT_NAME_UPPER}}_AVX2_SUPPORT`) + - Scalar fallback +2. Test with `-DDISABLE_AVX512=ON` to verify fallback works +3. Benchmark to ensure performance is maintained + +### Adding Tests + +1. Use Google Test framework +2. Include naive reference implementation for differential testing +3. Add edge cases: empty input, single element, boundary conditions +4. Use random testing with configurable seed for reproducibility + +## Performance Philosophy + +- **Goal**: Best practical performance (not just asymptotic complexity) +- **Approach**: Benchmark-driven optimization using Google Benchmark +- **SIMD**: Leverage vectorized operations where beneficial +- **Cache efficiency**: Align data structures to cache line boundaries (64 bytes) +""" + +DOXYFILE_IN = """# Doxyfile + +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "{{PROJECT_NAME}}" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +PROJECT_ICON = +OUTPUT_DIRECTORY = docs +CREATE_SUBDIRS = NO +CREATE_SUBDIRS_LEVEL = 8 +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +PYTHON_DOCSTRING = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +MARKDOWN_STRICT = YES +TOC_INCLUDE_HEADINGS = 6 +MARKDOWN_ID_STYLE = DOXYGEN +AUTOLINK_SUPPORT = YES +AUTOLINK_IGNORE_WORDS = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +NUM_PROC_THREADS = 1 +TIMESTAMP = NO +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +RESOLVE_UNNAMED_PARAMS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_UNDOC_NAMESPACES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = SYSTEM +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_HEADERFILE = YES +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +EXTERNAL_TOOL_PATH = +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = YES +WARN_NO_PARAMDOC = NO +WARN_IF_UNDOC_ENUM_VAL = NO +WARN_LAYOUT_FILE = YES +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LINE_FORMAT = "at line $line of file $file" +WARN_LOGFILE = +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include \ + @CMAKE_CURRENT_SOURCE_DIR@/README.md +INPUT_ENCODING = UTF-8 +INPUT_FILE_ENCODING = +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.h \ + *.hh \ + *.hxx \ + *.hpp +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/src/docs/images +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = @CMAKE_CURRENT_SOURCE_DIR@/README.md +IMPLICIT_DIR_DOCS = YES +FORTRAN_COMMENT_AFTER = 72 +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_ADD_INC_PATHS = YES +CLANG_OPTIONS = +CLANG_DATABASE_PATH = +ALPHABETICAL_INDEX = YES +IGNORE_PREFIX = +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = @AWESOME_CSS_DIR@/doxygen-awesome.css +HTML_EXTRA_FILES = +HTML_COLORSTYLE = AUTO_LIGHT +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_CODE_FOLDING = YES +HTML_COPY_CLIPBOARD = YES +HTML_PROJECT_COOKIE = +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDURL = +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +SITEMAP_URL = +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +PAGE_OUTLINE_PANEL = YES +FULL_SIDEBAR = NO +ENUM_VALUES_PER_LINE = 4 +SHOW_ENUM_VALUES = NO +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +OBFUSCATE_EMAILS = YES +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +FORMULA_MACROFILE = +USE_MATHJAX = NO +MATHJAX_VERSION = MathJax_2 +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +GENERATE_LATEX = NO +""" + +COVERAGE_REPORT_SH = """#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +BUILD_DIR="${ROOT_DIR}/build/coverage" + +cmake --preset coverage +cmake --build --preset coverage + +"${BUILD_DIR}/unittests" + +cd "${BUILD_DIR}" +find . -name "*.gcda" > gcov_files.txt +while read -r f; do + case "${f}" in + *"/_deps/"*|*"/third_party/"*|*"/src/benchmarks/"*) + ;; + *) + gcov -pb "${f}" >> coverage.txt + ;; + esac +done < gcov_files.txt +echo "gcov report written to ${BUILD_DIR}/coverage.txt" +""" + +BUILD_TEST_YML = """name: Tests (ASan) + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Create Build Directory + run: mkdir build + + - name: Configure CMake + working-directory: ./build + run: cmake -DDISABLE_AVX512=ON -DENABLE_ADDRESS_SANITIZER=ON -D{{PROJECT_NAME_UPPER}}_BENCHMARKS=OFF .. + + - name: Build Project + working-directory: ./build + run: make -j + + - name: Run Unittests + working-directory: ./build + run: ./unittests +""" + +LINTER_YML = """name: Clang Format Lint + +on: + pull_request: + push: + branches: [main] + +jobs: + clang-format: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install clang-format + run: sudo apt-get update && sudo apt-get install -y clang-format + + - name: Run clang-format check + run: | + mapfile -t FILES < <(find include src -type f \\( -name '*.cpp' -o -name '*.hpp' -o -name '*.cc' -o -name '*.c' -o -name '*.h' \\)) + clang-format --version + if [ ${#FILES[@]} -eq 0 ]; then + echo "No C/C++ files found." + exit 0 + fi + + clang-format --dry-run --Werror "${FILES[@]}" +""" + +COVERAGE_YML = """name: coverage + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + coverage: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Create Build Directory + run: mkdir build + + - name: Run coverage + run: ./scripts/coverage_report.sh + + - name: Upload to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: build/coverage/coverage.txt + flags: gcov + fail_ci_if_error: false + + - name: Upload coverage artifacts + uses: actions/upload-artifact@v4 + with: + name: coverage-gcov + path: | + build/coverage/coverage.txt + build/coverage/*.gcov +""" + +DOXYGEN_YML = """# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Doxygen v1.13.2 + run: | + transformed_version=$(echo "1.13.2" | tr '.' '_') + wget https://github.com/doxygen/doxygen/releases/download/Release_${transformed_version}/doxygen-1.13.2.linux.bin.tar.gz + tar -xzf doxygen-1.13.2.linux.bin.tar.gz + sudo mv doxygen-1.13.2/bin/doxygen /usr/local/bin/doxygen + shell: bash + - name: Cmake configure + run: cmake -S ${{github.workspace}} -B ${{github.workspace}}/build -D{{PROJECT_NAME_UPPER}}_DOCS=ON -D{{PROJECT_NAME_UPPER}}_TESTS=OFF -D{{PROJECT_NAME_UPPER}}_BENCHMARKS=OFF + - name: Build docs + run: cmake --build ${{github.workspace}}/build --target docs + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: ${{github.workspace}}/build/docs/html + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 +""" + +HEADER_HPP = """#pragma once + +/** + * @file {{HEADER_NAME}} + * @brief Main header for the {{PROJECT_NAME}} library + */ + +namespace {{NAMESPACE}} { + +/** + * @brief Example function. + * + * TODO: Replace with actual library functionality. + */ +inline int example() { + return 42; +} + +} // namespace {{NAMESPACE}} +""" + +UNITTESTS_CPP = """#include + +#include "{{NAMESPACE}}/{{HEADER_NAME}}" + +TEST(ExampleTest, BasicAssertion) { + EXPECT_EQ({{NAMESPACE}}::example(), 42); +} +""" + +BENCHMARKS_CPP = """#include + +#include "{{NAMESPACE}}/{{HEADER_NAME}}" + +static void BM_Example(benchmark::State& state) { + for (auto _ : state) { + benchmark::DoNotOptimize({{NAMESPACE}}::example()); + } +} + +BENCHMARK(BM_Example); + +BENCHMARK_MAIN(); +""" + + +# --------------------------------------------------------------------------- +# Generation logic +# --------------------------------------------------------------------------- + +def generate(args: argparse.Namespace) -> None: + project_name = args.name + namespace = args.namespace or project_name.replace("-", "") + project_name_upper = to_upper(project_name) + header_name = f"{to_snake(project_name)}.hpp" + output_dir = Path(args.output_dir).resolve() / project_name + + if output_dir.exists(): + print(f"Error: output directory already exists: {output_dir}") + sys.exit(1) + + substitutions = { + "{{PROJECT_NAME}}": project_name, + "{{NAMESPACE}}": namespace, + "{{PROJECT_NAME_UPPER}}": project_name_upper, + "{{HEADER_NAME}}": header_name, + } + + def sub(text: str) -> str: + for key, value in substitutions.items(): + text = text.replace(key, value) + return text + + # Create directories + (output_dir / "include" / namespace).mkdir(parents=True) + (output_dir / "src" / "tests").mkdir(parents=True) + (output_dir / "src" / "benchmarks").mkdir(parents=True) + (output_dir / "src" / "docs").mkdir(parents=True) + (output_dir / "src" / "docs" / "images").mkdir(parents=True) + (output_dir / "scripts").mkdir(parents=True) + (output_dir / ".github" / "workflows").mkdir(parents=True) + + # Write files + files = { + output_dir / "CMakeLists.txt": sub(CMAKE_LISTS_TXT), + output_dir / "CMakePresets.json": sub(CMAKE_PRESETS_JSON), + output_dir / ".clang-format": sub(CLANG_FORMAT), + output_dir / ".gitignore": sub(GITIGNORE), + output_dir / "README.md": sub(README_MD), + output_dir / "AGENTS.md": sub(AGENTS_MD), + output_dir / "src" / "docs" / "Doxyfile.in": sub(DOXYFILE_IN), + output_dir / "scripts" / "coverage_report.sh": sub(COVERAGE_REPORT_SH), + output_dir / ".github" / "workflows" / "build-test.yml": sub(BUILD_TEST_YML), + output_dir / ".github" / "workflows" / "linter.yml": sub(LINTER_YML), + output_dir / ".github" / "workflows" / "coverage.yml": sub(COVERAGE_YML), + output_dir / ".github" / "workflows" / "doxygen.yml": sub(DOXYGEN_YML), + output_dir / "include" / namespace / header_name: sub(HEADER_HPP), + output_dir / "src" / "tests" / "unittests.cpp": sub(UNITTESTS_CPP), + output_dir / "src" / "benchmarks" / "benchmarks.cpp": sub(BENCHMARKS_CPP), + } + + for path, content in files.items(): + path.write_text(content) + print(f"Created: {path.relative_to(output_dir.parent)}") + + # Make coverage script executable + (output_dir / "scripts" / "coverage_report.sh").chmod(0o755) + + print(f"\\nProject '{project_name}' generated successfully at {output_dir}") + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Scaffold a new C++20 repository following Pixie conventions." + ) + parser.add_argument("--name", required=True, help="Project name (e.g., my-lib)") + parser.add_argument( + "--namespace", + help="C++ namespace (defaults to project name with hyphens removed)", + ) + parser.add_argument( + "--output-dir", + default=".", + help="Output directory (default: current directory)", + ) + args = parser.parse_args() + generate(args) + + +if __name__ == "__main__": + main() From a520cc0b542abe36794da35c6b7392de91a64f0a Mon Sep 17 00:00:00 2001 From: Nikolay Malkovsky Date: Sat, 9 May 2026 17:34:59 +0300 Subject: [PATCH 4/4] Tighter cutoff --- include/pixie/bits.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/pixie/bits.h b/include/pixie/bits.h index 5285604..aa4b371 100644 --- a/include/pixie/bits.h +++ b/include/pixie/bits.h @@ -791,7 +791,8 @@ static inline void excess_positions_512_lut(const uint64_t* s, const int word_delta = 2 * static_cast(std::popcount(word)) - 64; const int target_local = target_x - cur; - if (target_local < -64 || target_local > 64) { + const int d = 2 * target_local - word_delta; + if (d < -64 || d > 64) { cur += word_delta; continue; }