FenwickTreeLibrary
This library implements a 0-indexed Fenwick Tree for tracking cumulative values over a dynamic array. It is suitable for systems where frequent prefix sum queries and point updates are required, such as time-based accounting, queuing systems, or share tracking.
Design Characteristics
O(log n)
complexity for both updates and prefix sum queries.Storage-efficient using a
mapping(uint256 => int256)
, instead of an array.Only supports lengths that are exact powers of two (
2^k
), which simplifies internal logic and allows future extensions viaextend()
.
Invariants and Constraints
The tree must be initialized with a power-of-two length > 0 via
initialize(...)
.Index bounds are enforced — access beyond the current capacity reverts with
IndexOutOfBounds()
.To support dynamic resizing,
extend()
can double the current tree length (up to a safe limit).Use of negative values is supported in
modify(...)
, allowing decrement operations.
Data Structures
struct Tree {
mapping(uint256 index => int256) _values; // Internal Fenwick Tree nodes.
uint256 _length; // Capacity of the tree (must be power of two).
}
Functions
initialize(Tree storage tree, uint256 length_)
initialize(Tree storage tree, uint256 length_)
Initializes the tree with the specified length.
Reverts with
InvalidLength()
iflength_ == 0
or not a power of two.Only callable once (re-initialization is not allowed).
length(Tree storage tree) → uint256
length(Tree storage tree) → uint256
Returns the current capacity of the tree.
extend(Tree storage tree)
extend(Tree storage tree)
Doubles the tree's capacity.
Preserves prefix sum structure.
Reverts with
InvalidLength()
on overflow.
modify(Tree storage tree, uint256 index, int256 value)
modify(Tree storage tree, uint256 index, int256 value)
Increments or decrements the value at a given index by value
.
Performs
tree[index] += value
.Reverts if index is out of bounds.
No-op if
value == 0
.
get(Tree storage tree, uint256 index) → int256
get(Tree storage tree, uint256 index) → int256
Returns the prefix sum for the range [0, index]
.
If
index >= length
, it is clamped tolength - 1
.
get(Tree storage tree, uint256 from, uint256 to) → int256
get(Tree storage tree, uint256 from, uint256 to) → int256
Returns the sum over the range [from, to]
(inclusive).
Returns
0
iffrom > to
.
Internals
_modify(...)
_modify(...)
Low-level implementation of Fenwick update using bitwise operations:
Updates
tree[index]
and propagates changes upward viaindex |= index + 1
.
_get(...)
_get(...)
Assembly-optimized prefix sum computation:
Aggregates values by descending via
index := and(index, index + 1) - 1
.