25std::uint64_t read_u64_le(
const std::uint8_t* p) {
27 for (
int i = 0; i < 8; ++i)
28 v |=
static_cast<std::uint64_t
>(p[i]) << (8 * i);
32double read_f64_le(
const std::uint8_t* p) {
33 const std::uint64_t bits = read_u64_le(p);
35 std::memcpy(&d, &bits,
sizeof(d));
39void write_u64_le(std::uint8_t* p, std::uint64_t v) {
40 for (
int i = 0; i < 8; ++i)
41 p[i] =
static_cast<std::uint8_t
>((v >> (8 * i)) & 0xFF);
44void write_f64_le(std::uint8_t* p,
double v) {
46 std::memcpy(&bits, &v,
sizeof(bits));
47 write_u64_le(p, bits);
58 n.min_y = read_f64_le(b.
data() + 8);
59 n.max_x = read_f64_le(b.
data() + 16);
60 n.max_y = read_f64_le(b.
data() + 24);
61 n.offset = read_u64_le(b.
data() + 32);
67 n.
min_x = std::numeric_limits<double>::infinity();
68 n.min_y = std::numeric_limits<double>::infinity();
69 n.max_x = -std::numeric_limits<double>::infinity();
70 n.max_y = -std::numeric_limits<double>::infinity();
87 write_f64_le(out + 0,
min_x);
88 write_f64_le(out + 8,
min_y);
89 write_f64_le(out + 16,
max_x);
90 write_f64_le(out + 24,
max_y);
91 write_u64_le(out + 32,
offset);
114 std::uint64_t n = num_items;
115 std::uint64_t num_nodes = n;
129 if (num_items == 0) {
133 std::vector<std::uint64_t> level_num_nodes;
134 std::uint64_t n = num_items;
135 std::uint64_t num_nodes = n;
136 level_num_nodes.push_back(n);
140 level_num_nodes.push_back(n);
146 std::vector<std::uint64_t> level_offsets;
147 std::uint64_t acc = num_nodes;
148 for (std::uint64_t size : level_num_nodes) {
150 level_offsets.push_back(acc);
153 std::vector<LevelBound> bounds;
154 bounds.reserve(level_num_nodes.size());
155 for (std::size_t i = 0; i < level_num_nodes.size(); ++i) {
156 bounds.push_back(
LevelBound{level_offsets[i], level_offsets[i] + level_num_nodes[i]});
162 std::uint64_t num_items, std::uint16_t
node_size,
164 std::vector<SearchResultItem> results;
170 const std::uint64_t leaf_nodes_offset = level_bounds.front().start;
173 std::deque<std::pair<std::uint64_t, std::size_t>> queue;
174 queue.emplace_back(0, level_bounds.size() - 1);
176 while (!queue.empty()) {
177 const auto [node_index, level] = queue.front();
180 if (level >= level_bounds.size()) {
187 if (node_index < level_bounds[level].start || node_index >= level_bounds[level].end) {
190 const bool is_leaf = (level == 0);
191 const std::uint64_t end = std::min<std::uint64_t>(
193 if (end <= node_index)
196 const std::uint64_t length = end - node_index;
200 const std::uint64_t byte_len =
203 auto block =
reader.
read(byte_offset, byte_len);
204 if (block.size() < byte_len) {
208 for (std::uint64_t pos = node_index; pos < end; ++pos) {
209 const std::uint64_t slot = pos - node_index;
218 const std::size_t child_level = level - 1;
219 if (item.
offset < level_bounds[child_level].start ||
220 item.
offset >= level_bounds[child_level].end) {
223 queue.emplace_back(item.
offset, child_level);
230 results.begin(), results.end(),
Every failure the library reports is one of these.
Synchronous byte-range source.
virtual std::vector< std::uint8_t > read(std::uint64_t offset, std::uint64_t length)=0
Read length bytes at offset, subject to the contract above.
Minimal C++17 stand-in for std::span: a non-owning view over contiguous memory.
std::size_t size() const noexcept
T * data() const noexcept
std::uint64_t checked_mul(std::uint64_t a, std::uint64_t b, const char *what="mul")
std::uint64_t checked_add(std::uint64_t a, std::uint64_t b, const char *what="add")
std::uint64_t ceil_div(std::uint64_t a, std::uint64_t b)
ceil(a / b) without the (a + b - 1) overflow hazard.
std::uint64_t rtree_num_nodes(std::uint64_t num_items, std::uint16_t node_size)
Total node count in the tree, per the Rust level-bounds loop (packed_rtree/mod.rs:342-375).
span< const std::uint8_t > bytes_view
The workhorse alias: a read-only view over bytes.
std::vector< SearchResultItem > rtree_search_bbox(RangeReader &reader, std::uint64_t index_begin, std::uint64_t num_items, std::uint16_t node_size, const BBox &query)
Breadth-first bbox search over the packed R-tree, reading nodes through the supplied reader.
std::vector< LevelBound > rtree_level_bounds(std::uint64_t num_items, std::uint16_t node_size)
Mirrors generate_level_bounds (packed_rtree/mod.rs:342-375).
std::uint64_t index_begin
Half-open [start, end) node index range for one tree level, in the flat node array shared by every le...
One R-tree node entry: 4 doubles then a u64, all little-endian, 40 bytes with no padding (packed_rtre...
static NodeItem decode(bytes_view b)
static NodeItem empty(std::uint64_t offset)
The "empty" node used as the fold/aggregation identity: any real bbox's expand widens it.
void expand(const NodeItem &r)
Widens this node's bbox to also cover r, leaving offset untouched.
static constexpr std::size_t kSize
bool intersects(const BBox &q) const
Mirrors NodeItem::intersects (packed_rtree/mod.rs:122-134), which uses strict < and >: touching edges...
void encode(std::uint8_t *out) const
Writes this node's 40 bytes (4 LE f64 then a LE u64), matching decode's layout exactly.
One hit from an index traversal.