|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Boost.OpenMethod is a C++17 header-only library implementing open multi-methods (multiple dispatch). Unlike traditional virtual functions where dispatch occurs only on the first (`this`) parameter, open methods dispatch based on the runtime types of multiple arguments. |
| 8 | + |
| 9 | +**Key Characteristics:** |
| 10 | +- C++17 required |
| 11 | +- Header-only library |
| 12 | +- Part of the Boost ecosystem |
| 13 | +- Supports both CMake and Boost.Build (b2) |
| 14 | + |
| 15 | +## Build System |
| 16 | + |
| 17 | +### CMake Build |
| 18 | + |
| 19 | +**Basic build:** |
| 20 | +```bash |
| 21 | +mkdir build && cd build |
| 22 | +cmake .. -DBOOST_SRC_DIR=/path/to/boost |
| 23 | +cmake --build . |
| 24 | +``` |
| 25 | + |
| 26 | +**Build with tests:** |
| 27 | +```bash |
| 28 | +cmake .. -DBOOST_OPENMETHOD_BUILD_TESTS=ON |
| 29 | +cmake --build . --target tests |
| 30 | +ctest |
| 31 | +``` |
| 32 | + |
| 33 | +**Build with examples:** |
| 34 | +```bash |
| 35 | +cmake .. -DBOOST_OPENMETHOD_BUILD_TESTS=ON -DBOOST_OPENMETHOD_BUILD_EXAMPLES=ON |
| 36 | +cmake --build . |
| 37 | +``` |
| 38 | + |
| 39 | +**Important CMake options:** |
| 40 | +- `BOOST_OPENMETHOD_BUILD_TESTS` - Enable tests (default: ON if root project) |
| 41 | +- `BOOST_OPENMETHOD_BUILD_EXAMPLES` - Enable examples (requires tests enabled) |
| 42 | +- `BOOST_OPENMETHOD_WARNINGS_AS_ERRORS` - Treat warnings as errors |
| 43 | +- `BOOST_SRC_DIR` - Path to Boost source directory (default: `../..` or `$BOOST_SRC_DIR` env var) |
| 44 | + |
| 45 | +### Boost.Build (b2) |
| 46 | + |
| 47 | +**Build and test:** |
| 48 | +```bash |
| 49 | +b2 test |
| 50 | +``` |
| 51 | + |
| 52 | +**Quick test (for CI):** |
| 53 | +```bash |
| 54 | +b2 test//quick |
| 55 | +``` |
| 56 | + |
| 57 | +## Testing |
| 58 | + |
| 59 | +### Running All Tests (CMake) |
| 60 | +```bash |
| 61 | +cd build |
| 62 | +ctest |
| 63 | +``` |
| 64 | + |
| 65 | +### Running a Single Test (CMake) |
| 66 | +```bash |
| 67 | +cd build |
| 68 | +ctest -R test_dispatch # Run specific test by name |
| 69 | +# or directly |
| 70 | +./boost_openmethod-test_dispatch |
| 71 | +``` |
| 72 | + |
| 73 | +### Test Structure |
| 74 | +- Test files: `test/test_*.cpp` - Standard unit tests using Boost.Test |
| 75 | +- Compile-fail tests: `test/compile_fail_*.cpp` - Tests that should fail to compile |
| 76 | +- Mixed build test: `test/mix_release_debug/` - Tests mixing debug/release builds |
| 77 | +- 21+ test files covering dispatch, policies, virtual_ptr, RTTI, errors, etc. |
| 78 | + |
| 79 | +### Debug Mode Features |
| 80 | +When building in Debug mode (`CMAKE_BUILD_TYPE=Debug`), runtime checks are automatically enabled via `BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS`. |
| 81 | + |
| 82 | +## Architecture |
| 83 | + |
| 84 | +### Layered Design |
| 85 | + |
| 86 | +The library is structured in three conceptual layers: |
| 87 | + |
| 88 | +1. **Preamble Layer** ([preamble.hpp](include/boost/openmethod/preamble.hpp)) |
| 89 | + - Foundational types: `type_id`, `vptr_type`, `virtual_<T>` |
| 90 | + - Registry and policy framework |
| 91 | + - Error types: `not_initialized`, `bad_call`, `no_overrider`, `ambiguous_call`, etc. |
| 92 | + - No executable dispatch code |
| 93 | + |
| 94 | +2. **Core API** ([core.hpp](include/boost/openmethod/core.hpp)) |
| 95 | + - `method<Id, ReturnType(Parameters...), Registry>` - Method implementation |
| 96 | + - `virtual_ptr<Class, Registry>` - "Wide pointer" combining object pointer + v-table pointer |
| 97 | + - Dispatch algorithms: `resolve_uni()` (single dispatch), `resolve_multi_*()` (multiple dispatch) |
| 98 | + - Override registration via `override_impl<>` |
| 99 | + - Class registration via `use_classes<>` |
| 100 | + |
| 101 | +3. **Macro Layer** ([macros.hpp](include/boost/openmethod/macros.hpp)) |
| 102 | + - `BOOST_OPENMETHOD(name, params, return_type)` - Declare method |
| 103 | + - `BOOST_OPENMETHOD_OVERRIDE(name, params, return_type)` - Declare overrider |
| 104 | + - `BOOST_OPENMETHOD_CLASSES(classes...)` - Register class hierarchy |
| 105 | + - Generates static registrar objects for automatic registration |
| 106 | + |
| 107 | +### Key Concepts |
| 108 | + |
| 109 | +**Open Methods**: Functions where dispatch depends on runtime types of multiple parameters, not just the first. |
| 110 | + |
| 111 | +**Virtual Parameters**: Parameters marked with `virtual_<T>` or `virtual_ptr<T>` that participate in dispatch. |
| 112 | + |
| 113 | +**Registries**: Template-parameterized contexts holding classes, methods, and policies. Default: `boost::openmethod::default_registry`. |
| 114 | + |
| 115 | +**Policies**: Pluggable components controlling behavior: |
| 116 | +- `rtti` - Type identification (std_rtti, static_rtti, custom) |
| 117 | +- `vptr` - V-table storage (vptr_vector, vptr_map) |
| 118 | +- `type_hash` - Type ID hashing (fast_perfect_hash with hash_fn function object) |
| 119 | +- `error_handler` - Error handling strategy (default_error_handler, throw_error_handler) |
| 120 | +- `output` - Diagnostic output destination (stderr_output) |
| 121 | +- `attributes` - Visibility/DLL decoration (dllexport, dllimport, local) |
| 122 | + |
| 123 | +**Dispatch Mechanisms**: |
| 124 | +- Single dispatch: Direct v-table lookup `vtbl[slot]` |
| 125 | +- Multi-dispatch: Stride-based indexing through multi-dimensional dispatch tables |
| 126 | + |
| 127 | +**virtual_ptr**: A "wide pointer" combining object pointer with v-table pointer |
| 128 | +for efficient dispatch. Key for enabling dispatch on non-polymorphic or smart |
| 129 | +pointer types. |
| 130 | + |
| 131 | +### Component Interaction |
| 132 | + |
| 133 | +``` |
| 134 | +User Code → Macros → Core API → Preamble → Policies |
| 135 | + ↓ |
| 136 | + Static Registration |
| 137 | +``` |
| 138 | + |
| 139 | +Static initializers generated by macros call core API functions to register |
| 140 | +classes, methods, and overriders. The `initialize()` function builds dispatch |
| 141 | +tables before first use. |
| 142 | + |
| 143 | +## Code Conventions |
| 144 | + |
| 145 | +### Formatting |
| 146 | +The project uses clang-format with an LLVM-based style: |
| 147 | +- `AlignAfterOpenBracket: AlwaysBreak` |
| 148 | +- `AllowShortFunctionsOnASingleLine: false` |
| 149 | +- No short blocks, if statements, or loops on single lines |
| 150 | + |
| 151 | +### Compiler Requirements |
| 152 | +Tests require these C++17 features (checked by Boost.Build): |
| 153 | +- auto nontype template params |
| 154 | +- deduction guides |
| 155 | +- fold expressions |
| 156 | +- if constexpr |
| 157 | +- inline variables |
| 158 | +- structured bindings |
| 159 | +- `<charconv>`, `<string_view>`, `<variant>` headers |
| 160 | + |
| 161 | +## Common Development Patterns |
| 162 | + |
| 163 | +### Working with Shared Libraries / DLL Support |
| 164 | + |
| 165 | +**Overview**: The library supports shared library usage on Windows with proper dllexport/dllimport decoration. |
| 166 | + |
| 167 | +**Key Pattern - Decoratable Static Variables**: |
| 168 | +All policy static variables use `BOOST_OPENMETHOD_DETAIL_MAKE_SYMBOL_WITH_ATTRIBUTES(name)` macro to enable DLL decoration. This generates three specializations of `global_state_<name>`: |
| 169 | +- Default (no attributes) |
| 170 | +- `__declspec(dllexport)` when registry has dllexport attributes |
| 171 | +- `__declspec(dllimport)` when registry has dllimport attributes |
| 172 | + |
| 173 | +**Affected Policies**: |
| 174 | +- `stderr_output::fn::os` - Output stream (via `global_state_os`) |
| 175 | +- `default_error_handler::fn::handler` - Error handler function (via `global_state_handler`) |
| 176 | +- `fast_perfect_hash::fn::hash_fn` - Hash factors struct (via `global_state_hash_fn`) |
| 177 | +- `vptr_map::fn::vptrs` - V-table pointer map (via `global_state_vptrs`) |
| 178 | +- `vptr_vector::fn::vptr_vector_vptrs` / `vptr_vector_indirect_vptrs` - V-table vectors |
| 179 | + |
| 180 | +**Example Usage**: |
| 181 | +```cpp |
| 182 | +// In header shared between library and client |
| 183 | +#ifdef LIBRARY_NAME |
| 184 | +#define MY_API boost::openmethod::declspec::dllexport |
| 185 | +#else |
| 186 | +#define MY_API boost::openmethod::declspec::dllimport |
| 187 | +#endif |
| 188 | + |
| 189 | +namespace boost::openmethod { |
| 190 | + MY_API boost_openmethod_attributes(default_registry_attributes); |
| 191 | +} |
| 192 | + |
| 193 | +BOOST_OPENMETHOD(my_method, (virtual_ptr<MyClass>), void, MY_API); |
| 194 | +``` |
| 195 | +
|
| 196 | +See `doc/modules/ROOT/examples/shared_libs/` for complete examples. |
| 197 | +
|
| 198 | +### Custom RTTI |
| 199 | +When `<typeinfo>` is unavailable or insufficient, use static_rtti or implement custom RTTI. See `doc/modules/ROOT/examples/custom_rtti/` and policies in `include/boost/openmethod/policies/`. |
| 200 | +
|
| 201 | +### Multiple Registries |
| 202 | +Registries are completely independent. Use separate registries to: |
| 203 | +- Isolate method sets |
| 204 | +- Apply different policies to different method families |
| 205 | +- Enable coexistence of incompatible configurations |
| 206 | +
|
| 207 | +Registry type must be specified consistently across related methods and classes. |
| 208 | +
|
| 209 | +## File Organization |
| 210 | +
|
| 211 | +- `include/boost/openmethod/` - Public headers |
| 212 | + - `core.hpp`, `macros.hpp`, `preamble.hpp` - Main headers |
| 213 | + - `initialize.hpp` - Dispatch table construction |
| 214 | + - `default_registry.hpp` - Default policy configuration |
| 215 | + - `detail/` - Internal implementation details |
| 216 | + - `policies/` - Policy implementations |
| 217 | + - `interop/` - Interoperability with other systems |
| 218 | +- `test/` - Unit tests and compile-fail tests |
| 219 | +- `doc/modules/ROOT/examples/` - Example programs |
| 220 | +- `doc/modules/ROOT/pages/` - AsciiDoc documentation |
| 221 | +
|
| 222 | +## Dependencies (Boost Libraries) |
| 223 | +
|
| 224 | +Required: |
| 225 | +- Boost.Assert |
| 226 | +- Boost.Config |
| 227 | +- Boost.Core |
| 228 | +- Boost.DynamicBitset |
| 229 | +- Boost.MP11 (metaprogramming) |
| 230 | +- Boost.Preprocessor |
| 231 | +
|
| 232 | +For testing: |
| 233 | +- Boost.Test |
| 234 | +- Boost.SmartPtr |
| 235 | +
|
| 236 | +For examples: |
| 237 | +- Boost.DLL (shared library examples) |
| 238 | +
|
| 239 | +## Development Workflow |
| 240 | +
|
| 241 | +1. Make changes to headers in `include/boost/openmethod/` |
| 242 | +2. Build tests: `cmake --build build --target tests` |
| 243 | +3. Run tests: `cd build && ctest` |
| 244 | +4. For changes affecting examples: enable `BOOST_OPENMETHOD_BUILD_EXAMPLES` |
| 245 | +5. Submit PRs against the `develop` branch |
| 246 | +
|
| 247 | +## Important Implementation Details |
| 248 | +
|
| 249 | +### Static Registration |
| 250 | +Classes, methods, and overriders register automatically via static constructors. This happens before `main()`. The `initialize()` function must be called before first method invocation to build dispatch tables. |
| 251 | +
|
| 252 | +### Dispatch Table Construction |
| 253 | +The `initialize()` function: |
| 254 | +1. Collects registered classes and overriders |
| 255 | +2. Builds class hierarchy using provided inheritance relationships |
| 256 | +3. Constructs dispatch tables using perfect hashing |
| 257 | +4. Validates configuration (in debug mode or with runtime_checks policy) |
| 258 | +
|
| 259 | +### Virtual Pointer Mechanics |
| 260 | +`virtual_ptr<T>` stores both object pointer and v-table pointer. It can be constructed from: |
| 261 | +- Raw pointers (requires prior `use_classes` registration) |
| 262 | +- Smart pointers (std::unique_ptr, std::shared_ptr, boost::intrusive_ptr) |
| 263 | +- References |
| 264 | +- Other virtual_ptr instances |
| 265 | +
|
| 266 | +The v-table pointer enables O(1) method dispatch. |
| 267 | +
|
| 268 | +### Policy Static Variables Pattern |
| 269 | +
|
| 270 | +When adding static variables to policies: |
| 271 | +
|
| 272 | +1. **Declare the variable storage** in `detail` namespace using `BOOST_OPENMETHOD_DETAIL_MAKE_SYMBOL_WITH_ATTRIBUTES(variable_name)` |
| 273 | +2. **Use type alias** in policy's `fn<Registry>` class: `using var_storage = detail::global_state_variable_name<Type, Registry>` |
| 274 | +3. **Access via storage**: `var_storage::variable_name` instead of direct static member |
| 275 | +4. **Define specialization** outside class: `template<class Registry> Type detail::global_state_variable_name<Type, Registry>::variable_name;` |
| 276 | +
|
| 277 | +This pattern ensures static variables can be properly decorated with dllexport/dllimport for shared library usage. |
| 278 | +
|
| 279 | +**Example from fast_perfect_hash**: |
| 280 | +```cpp |
| 281 | +// In detail namespace |
| 282 | +struct hash_fn { |
| 283 | + std::size_t mult, shift, min_value, max_value; |
| 284 | + auto operator()(type_id type) const -> std::size_t { |
| 285 | + return (mult * reinterpret_cast<uintptr>(type)) >> shift; |
| 286 | + } |
| 287 | +}; |
| 288 | +BOOST_OPENMETHOD_DETAIL_MAKE_SYMBOL_WITH_ATTRIBUTES(hash_fn); |
| 289 | +
|
| 290 | +// In policy |
| 291 | +template<class Registry> |
| 292 | +class fn { |
| 293 | + using factors_storage = detail::global_state_hash_fn<detail::hash_fn, Registry>; |
| 294 | +public: |
| 295 | + static auto hash(type_id type) -> std::size_t { |
| 296 | + return factors_storage::hash_fn(type); // Use via storage |
| 297 | + } |
| 298 | +}; |
| 299 | +``` |
0 commit comments