|
JH-Toolkit v1.4.1
An engineering-oriented C++20 toolkit with duck-typed concepts, static design, async coroutines, and semantic containers — header-only, RTTI-free, and concurrency-friendly.
|
Contiguous AVL-based ordered container with fragmentation-free semantics. More...
#include <concepts>#include <cstddef>#include <utility>#include <cstdint>#include <iostream>#include <type_traits>#include <iterator>#include <stdexcept>#include <ranges>#include <vector>#include "jh/typing/monostate.h"#include "jh/conceptual/tuple_like.h"Go to the source code of this file.
Classes | |
| struct | jh::avl::avl_node< K, V > |
| Node element for the contiguous AVL tree. More... | |
| struct | jh::avl::avl_node< K, jh::typed::monostate > |
| Node element for set-style contiguous AVL trees. More... | |
| class | jh::avl::tree_map< K, V, Alloc > |
Contiguous-array AVL tree used by jh::ordered_map and jh::ordered_set. More... | |
| struct | jh::avl::tree_map< K, V, Alloc >::iterator |
| Bidirectional iterator providing in-order traversal. More... | |
| struct | jh::avl::tree_map< K, V, Alloc >::const_iterator |
| Const bidirectional iterator for in-order traversal. More... | |
Namespaces | |
| namespace | jh::avl |
Internal AVL-tree implementation namespace for jh::ordered_set and jh::ordered_map. | |
Typedefs | |
| template<typename K, typename Alloc = std::allocator<K>> | |
| using | jh::ordered_set |
| Ordered associative set based on a contiguous-array AVL tree. | |
| template<typename K, typename V, typename Alloc = std::allocator<std::pair<const K, V>>> | |
| using | jh::ordered_map |
| Ordered associative map based on a contiguous-array AVL tree. | |
Contiguous AVL-based ordered container with fragmentation-free semantics.
jh::ordered_set<K> and jh::ordered_map<K,V> implement a contiguous AVL tree stored inside a std::vector (or PMR-aware vector), eliminating pointer chasing and reducing allocator fragmentation. Nodes are referred to by indices instead of pointers, enabling stable, cache-friendly traversal and compact memory layout.
These containers are not intended as a full replacement for std::set or std::map, but serve as a predictable, fragmentation-free, and locality-optimized alternative for workloads where:
clear() behavior under PMR. Nodes are stored as AVL nodes in a contiguous vector:
std::set / std::map| Aspect | std::set std::map | jh::ordered_set ordered_map |
|---|---|---|
| Node layout | pointer-linked RB-tree | contiguous AVL (vector) |
| Fragmentation | high (many small allocations) | minimal (1 vector buffer) |
| Iterator stability | stable | stable except erased node |
| Erase cost | O(log N) | O(log N) + compactification |
| Traversal locality | poor (pointer chasing) | excellent |
PMR clear() | deep node destruction | O(1), vector reset |
| For >5k elements | stable but noisy | predictable, low jitter |
Modern allocators suffer from fragmentation under workloads that frequently construct and destroy many tree nodes (e.g., dynamic indexing, routing tables, message subscription graphs). The standard containers rely on one allocation per node, causing:
The contiguous AVL model eliminates these issues by placing all nodes into a single dynamic buffer. Erasing a node does not free any memory; it simply moves the last node into the removed slot. Combined with a monotonic-buffer resource, clear() becomes nearly O(1).
Benchmarks (Apple M3, LLVM clang++20, 2025) show stable behavior across 5 000-1 000 000 elements:
| Operation | std::set/map | jh::ordered_set/map | Notes |
|---|---|---|---|
| Random insert | fast start, large jitter | ≈ 10-40% overhead but small jitter | AVL maintenance but contiguous memory |
| Ordered insert | degenerates (right-heavy RB) | consistently faster | vector locality dominates |
| Random lookup | stable | comparable or slightly faster | branchless traversal & locality |
| Iteration | pointer chasing | ≈ 15-30% faster | sequential memory |
| Erase | stable | slightly slower worst-case | compacting cost |
| Clear (PMR) | O(N) destruct | O(1) | pool discard |
ordered_set often surpasses std::set. erase() never frees memory. clear() under PMR is almost zero-cost. erase() except the returned one. std::map::insert(hint)). 1.4.x
2025