Skip to content

Latest commit

 

History

History
54 lines (37 loc) · 5.01 KB

CLAUDE.md

File metadata and controls

54 lines (37 loc) · 5.01 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

ea_data_structures is a header-only C++20 library of data structures, smart pointers, allocators, and utilities. Everything lives under the EA:: namespace. The library is also shaped to work as a JUCE module (see the BEGIN_JUCE_MODULE_DECLARATION block in ea_data_structures/ea_data_structures.h), which is why every feature is included through that single umbrella header.

Build

The main CMake target is an INTERFACE library — there is nothing to compile on its own. Consumers link against ea_data_structures and include ea_data_structures/ea_data_structures.h:

add_subdirectory(path/to/cpp_data_structures)
target_link_libraries(my_target PRIVATE ea_data_structures)

The INTERFACE target declares target_compile_features(... INTERFACE cxx_std_20), so consumers automatically get a C++20-or-higher requirement propagated onto anything that links it.

Tests

The Tests/ target and NanoTest fetch are only enabled when this repo is the top-level CMake project (PROJECT_IS_TOP_LEVEL). Consumers that add_subdirectory this repo as a dependency don't pay that cost.

cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure

Each nano::test("Name") registers as an individual CTest entry, so you can run one test with ctest --test-dir build -R Vector.contains or directly via ./build/Tests/ea_data_structures_tests --test Vector.contains. --list-tests on the executable lists everything it registered.

The top-level build sets CMAKE_CXX_STANDARD 20 because NanoTest's own static libs don't declare a standard themselves. _clang-format and .clang-tidy at the repo root define the expected style and checks; run clang-format / clang-tidy against changed files before committing.

Code layout

Everything user-facing is re-exported from ea_data_structures/ea_data_structures.h. When adding a new public header, add its #include there — otherwise JUCE-module consumers won't see it. The subdirectories group related concerns:

  • Structures/ — containers (Vector, Array, MapVector, SmallVector, StaticVector, FixedDynamicArray, OwnedVector, MultiVector, CircularBuffer, Fifo, BufferView, CopyOnWrite, Filtered, SharedGUIData). SizeType.h is the shared size alias.
  • Pointers/ — ownership and type-erasure primitives (OwningPointer, Ref, RefOrOwn, Any, AnyRef, Cloneable, CallbackFunc, DynamicFunc).
  • Allocators/ — allocator machinery backing SmallVector / StaticVector, plus a PMR wrapper and MultiPoolAllocator.
  • Flags/ — concurrency and atomic helpers (Locks, RecursiveSpinLock, CopyableAtomic, AtomicHelpers, Bool).
  • ValueWrapper/ — Value and Constructed (in-place-optional-like object with no heap allocation).
  • Utilities/ — free-function helpers (VectorUtilities, MapUtilities, TupleUtilities, GenericUtilities, StaticObjects).

Conventions that matter for edits

  • Always run clang-format on every changed file.
  • Use modern, RAII style.
  • int size semantics, not size_t. The Vector / Array wrappers deliberately expose int-based sizes and indices — do not "fix" this to size_t. Helper methods (contains, eraseIf, addIfNotThere, sort, …) are the whole point of these wrappers over raw STL. size() asserts that the count fits an int; getSize() is the full size_t, for STL calls and for a Span over more than an int describes, and Span builds from a container's getSize() when it has one. Span wraps std::span the way Vector wraps std::vector — getSpan() beside getVector() / getArray().
  • Array is constexpr throughout. Every member except the two sort overloads (std::sort only becomes constexpr in C++26) is usable in a constant expression, as are the Vectors:: search and reverse helpers they delegate to (getIndexOf, getIndexIf, countIf, contains, find, findIf, reverse, rotate). That is what lets a type that stores an Array — a matrix, a lookup table — keep its own constexpr, so don't add a non-constexpr member without a reason. Accessors need const overloads for the same reason: a constexpr object is a const one.
  • Real-time safety. SharedGUIData / GUIToRealTime, Fifo, CircularBuffer, and Flags/ types are designed for audio/real-time threads — preserve lock-free / allocation-free behavior when editing them.
  • Atomic<T> (in Flags/) static-asserts T is always lock-free; keep that guarantee intact.
  • Formatting: Allman braces, 4-space indent, 85-column limit, left-aligned pointers, SortIncludes: false (header order is intentional — notably in ea_data_structures.h), Standard: c++20.
  • Braces on control flow: for and if bodies use curly braces whenever the body spans more than one line (e.g. a nested if, a wrapped statement, or multiple statements). A body that fits on a single line may omit braces.