Pure Rust • #![no_std] Rust • Python • Node.js • .NET • C++20 • Java • C ABI 64-Bit & 32-Bit Embedded RocksDB MemTable Plugin glibc-hwcaps (x86-64-v1..v4)

Modern Judy Arrays & High-Performance Digital Tree Engine

Clean-room pure-Rust implementation of digital trees modernized for modern 64-bit microarchitectures with zero-allocation immediates, SWAR/SIMD vectorization, and lock-free OCC reader concurrency.

Why “Expanse”?

Partitioning digital trees by key expanse, rather than population.

Expanse is the Judy design's own defining term — so central that the published descriptions stop to define it before anything else, and use it as the precise contrast with population-partitioned trees (B-trees, binary trees):

“Expanse, population, and density are not commonly used terms in tree search literature, so let's define them here: Expanse is a range of possible keys […]”
— Doug Baskins, A 10-Minute Description of How Judy Arrays Work and Why They Are So Fast (2002)
“A digital tree divides up the population (index set) uniformly by expanse (dividing and redividing the initial expanse evenly), while other methods, such as b-trees, divide up the population by the distribution of the population itself.”
— Alan Silverstein, Judy IV Shop Manual (2002), “Digital Trees”

Naming the project after the underlying mechanism honors the algorithm itself without inheriting legacy C codebase baggage. Expanse is developed with strict clean-room discipline: zero exposure to LGPL source code, adhering exclusively to published design specifications and black-box differential test suites.

Architectural Highlights

Engineered for cache-line density, hardware SIMD lanes, and lock-free multi-core throughput.

Zero-Alloc Immediates

Up to 7 keys in sets and up to 3 key-value pairs in maps are packed directly inside tagged 64-bit edge words, bypassing heap allocation entirely for small collections.

Adaptive Compression Ladder

Trie branches dynamically morph between Linear leaves (sorted key arrays), Bitmap leaves (64-bit subexpanse bitboards), and full uncompressed 256-way digital branches.

🚀

Lock-Free OCC Concurrency

SyncExpanseMap and SyncExpanseSet employ epoch-based optimistic concurrency control (OCC). Readers perform lock-free traversals with zero reader-lock cache-line bouncing.

🎯

SIMD & SWAR Acceleration

Search kernels utilize vector instructions (AVX2, AVX-512, ARM NEON) with bitwise SWAR fallbacks, scanning linear leaves in single clock cycles.

📦

glibc-hwcaps Multi-Arch

Debian and RPM packages provide optimized runtime libraries automatically selected by the dynamic loader for x86-64-v2, v3 (AVX2), and v4 (AVX-512).

🔗

Drop-in Judy C ABI Parity

Provides 100% C ABI compatibility with stock libjudy (Judy1, JudyL, JudySL, JudyHS) alongside modern, type-safe expanse_* C interfaces.

🌱

32-Bit Embedded (#![no_std])

Compact 8-byte Edge32 layout saving 50% structural SRAM on ARM Cortex-M and RISC-V RV32 microcontrollers, with 32-byte cache alignment and zero-alloc inlined payloads.

Explore the Interactive Data Visualizer

Inspect tagged pointer layouts, simulate dynamic compression transitions across the ladder, and step through branch bitboard operations in real-time.

Launch Visualizer →

Measured Micro-Benchmarks

Deterministic instruction counting and latency benchmarks against industry data structures.

Ordered Range Scan 100,000 keys sequential scan (higher is better) ▲ Throughput (M keys / sec) 100M 50M 0 88.4 M/s ExpanseMap 3.4× speedup 26.0 M/s BTreeMap 1.0× baseline Point Lookup Latency 1,000,000 keys random queries (lower is better) ▼ Latency (ns / op) 40 ns 20 ns 0 15.8 ns ExpanseSet fastest 24.2 ns Roaring 1.5× 32.3 ns Stock Judy 2.0× baseline Memory Footprint 100,000 keys in 256-key clusters (lower is better) ▼ Density (Bytes / key) 20 B 10 B 0 0.36 B ExpanseSet -98% heap 0.38 B Roaring -98% heap 16.00 B BTreeSet 44× larger
MULTITHREADED OCC CONCURRENCY SCALABILITY (SyncExpanseMap) Concurrent read throughput across 1..16 threads (1,000,000 keys, 100% Read, Honeycomb 16-Core Server) SyncExpanseMap Linear Ideal ▲ Throughput (M ops / sec) 0 100M 200M 300M 1 Thread 2 Threads 4 Threads 8 Threads 16 Threads 21.8 M/s 41.7 M/s (1.9×) 82.9 M/s (3.8×) 156.5 M/s (7.2×) 260.9 M/s (12.0×) Measured on 16-core Intel i9-12900F • Lock-free optimistic concurrency reader scaling
YCSB Workload E (OLAP Scan) 95% Range Scan, 5% Insert (higher is better) ▲ Throughput (M ops / sec) 15M 7.5M 0 13.1 M/s Expanse 7.2× speedup 3.96 M/s BTreeMap 2.2× 1.81 M/s SkipMap 1.0× baseline YCSB Workload F (Atomic RMW) 50% Read, 50% RMW (higher is better) ▲ Throughput (M ops / sec) 16M 8.0M 0 14.2 M/s Expanse 8.1× speedup 4.19 M/s BTreeMap 2.4× 1.76 M/s SkipMap 1.0× baseline Small-Payload Inlining ≤ 7B payloads, zero heap alloc (lower is better) ▼ Latency (ns / op) 70 ns 35 ns 0 13.4 ns ExpanseBlobMap 4.3× faster (0 alloc) 58.2 ns BTreeMap (Heap) 1.0× (16B header)

Installation & Quickstart Hub

Zero-cost bindings and native packages across Rust, Python, Node.js/Bun, .NET/C#, C++20, Java, C ABI, RocksDB, Linux APT/RPM repos, and PHP.

Add core Expanse engine to your Cargo.toml:

cargo add expanse-trie

Usage example in Rust (Maps, Sets, Off-Heap Blobs, Lock-Free OCC):

use expanse_trie::{ExpanseMap, ExpanseSet, ExpanseBlobMap, SyncExpanseMap};

// 64-bit integer map with zero-allocation immediates
let mut map = ExpanseMap::new();
map.insert(42, 100);
assert_eq!(map.get(42), Some(100));

// Variable-length byte blob map with slab arena & hot metadata
let mut blobs = ExpanseBlobMap::new();
blobs.insert(1, b"hello expanse", 0x2A);
assert_eq!(blobs.get(1), Some(&b"hello expanse"[..]));

// Thread-safe lock-free OCC map (zero reader locks)
let sync_map = SyncExpanseMap::new();
sync_map.insert(99, 500);
let reader = sync_map.reader();
assert_eq!(reader.get(99), Some(500));

Canonical Documentation

Comprehensive architectural and algorithmic references.