Skip to content

Commit 98e1116

Browse files
authored
Merge pull request #55 from JayKickliter/jsk/cleanup-docs
Cleanup documentation
2 parents 85b7f1b + f0e6490 commit 98e1116

8 files changed

Lines changed: 104 additions & 76 deletions

File tree

README.md

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,43 @@
22

33
# HexTree
44

5-
hextree provides tree structures that represent geographic regions
6-
with [H3 cell]s.
5+
HexTree provides tree structures for efficiently representing geographic
6+
regions using [H3 cell]s. It takes advantage of H3's hierarchical structure
7+
to automatically compact large regions and provide fast spatial queries.
78

89
The primary structures are:
910

1011
- [**HexTreeMap**]: an H3 cell-to-value map.
11-
- [**HexTreeSet**]: an H3 cell set for hit-testing.
12+
- [**HexTreeSet**]: an H3 cell set for spatial containment testing.
1213

1314
You can think of `HexTreeMap` vs. `HexTreeSet` as [`HashMap`] vs. [`HashSet`].
1415

1516
## How is this different from `HashMap<H3Cell, V>`?
1617

17-
The key feature of a hextree is that its keys (H3 cells) are
18-
hierarchical. For instance, if you previously inserted an entry for a
19-
low-res cell, but later query for a higher-res child cell, the tree
20-
returns the value for the lower res cell. Additionally, with
21-
[compaction], trees can automatically coalesce adjacent high-res cells
22-
into their parent cell. For very large regions, the compaction process
23-
_can_ continue to lowest resolution cells (res-0), possibly removing
24-
millions of redundant cells from the tree. For example, a set of
25-
4,795,661 res-7 cells representing North America coalesces [into a
26-
42,383 element `HexTreeSet`][us915].
27-
28-
A hextree's internal structure exactly matches the semantics of an [H3
29-
cell]. The root of the tree has 122 resolution-0 nodes, followed by 15
30-
levels of 7-ary nodes. The level of an occupied node, or leaf node, is
31-
the same as its corresponding H3 cell resolution.
18+
HexTree leverages H3's hierarchical cell structure in two key ways:
19+
20+
**Hierarchical Queries**: When you query for a cell, the tree returns
21+
a value even if only a parent cell was inserted. For instance, if you
22+
insert a low-res cell but later query for a higher-res child cell, the
23+
tree returns the value from the parent.
24+
25+
**Automatic Compaction**: With [compaction], the tree can automatically
26+
coalesce 7 adjacent child cells into their parent cell, dramatically
27+
reducing memory usage. For very large regions, compaction can continue
28+
recursively to the lowest resolution cells (res-0), possibly removing
29+
millions of redundant cells. For example, 4,795,661 res-7 cells
30+
representing North America compact [into just 42,383 elements][us915].
31+
32+
The internal structure mirrors H3's hierarchy: the root contains 122
33+
resolution-0 base cells, with each level below being a 7-ary tree
34+
(matching H3's 7 possible child cells per parent). The tree supports
35+
up to 15 levels of resolution, where the depth of a leaf node corresponds
36+
to its H3 cell resolution.
3237

3338
## Features
3439

3540
* **`serde`**: support for serialization via [serde].
41+
* **`disktree`**: on-disk memory-mapped storage for large trees (enables `serde`, `byteorder`, and `memmap`).
3642

3743
## License
3844

src/cell.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
//! This has two different types representing H3 indices is slightly
1+
//! This has two different types representing H3 indices in slightly
22
//! different ways, [Index] & [Cell]. Index is lower level and allows
3-
//! you create invalid H3 indices. Cell is higher level and enforces
3+
//! you to create invalid H3 indices. Cell is higher level and enforces
44
//! invariants.
55
66
use crate::{Error, Result};
77
use std::{convert::TryFrom, fmt};
88

99
/// A low-level type for H3 [index manipulation].
1010
///
11-
/// Node that all setters take consume `self` and return a new
11+
/// Note that all setters consume `self` and return a new
1212
/// `Index`.
1313
///
1414
/// [index manipulation]: https://observablehq.com/@nrabinowitz/h3-index-bit-layout?collection=@nrabinowitz/h3
@@ -112,7 +112,7 @@ impl Index {
112112
}
113113
}
114114

115-
/// Consumes `self` and returns a new Index with it's resolution
115+
/// Consumes `self` and returns a new Index with its resolution
116116
/// `res` digit set to `digit`.
117117
///
118118
/// This function does not check `res` nor `digit` for validity
@@ -129,7 +129,10 @@ impl Index {
129129
}
130130
}
131131

132-
/// [HexTreeMap][crate::HexTreeMap]'s key type.
132+
/// A validated H3 cell index.
133+
///
134+
/// This is the key type for [HexTreeMap][crate::HexTreeMap]. A `Cell`
135+
/// is guaranteed to be a valid H3 cell (mode 1 index).
133136
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
134137
#[cfg_attr(
135138
feature = "serde",
@@ -153,7 +156,7 @@ impl Cell {
153156
if
154157
// reserved must be 0
155158
!idx.reserved() &&
156-
// we only care about mode 1 (cell) indicies
159+
// we only care about mode 1 (cell) indices
157160
idx.mode() == 1 &&
158161
// there are only 122 base cells
159162
idx.base() < 122
@@ -172,8 +175,9 @@ impl Cell {
172175

173176
/// Returns this cell's parent at the specified resolution.
174177
///
175-
/// Returns Some if `res` is less-than or equal-to this cell's
176-
/// resolution, otherwise returns None.
178+
/// Returns `Some` if `res` is less than or equal to this cell's
179+
/// resolution. Returns `None` if `res` is greater than this cell's
180+
/// resolution (you cannot get a higher-resolution parent).
177181
#[inline]
178182
pub const fn to_parent(&self, res: u8) -> Option<Self> {
179183
match self.res() {
@@ -203,12 +207,12 @@ impl Cell {
203207
Index(self.0).res()
204208
}
205209

206-
/// Returns true if `self` is related to `other`.
210+
/// Returns `true` if this cell is related to another cell.
207211
///
208-
/// "Related" can be any of the following:
209-
/// - `self` == `other`
210-
/// - `self` is a parent cell of `other`
211-
/// - `other` is a parent cell of `self`
212+
/// Two cells are related if they share a parent-child relationship:
213+
/// - `self` and `other` are the same cell, or
214+
/// - `self` is an ancestor (parent, grandparent, etc.) of `other`, or
215+
/// - `other` is an ancestor of `self`
212216
#[inline]
213217
pub fn is_related_to(&self, other: &Self) -> bool {
214218
let common_res = std::cmp::min(self.res(), other.res());
@@ -238,7 +242,7 @@ impl TryFrom<i64> for Cell {
238242
}
239243
}
240244

241-
/// A type for building up Cells in an iterative matter when
245+
/// A type for building up Cells in an iterative manner when
242246
/// tree-walking.
243247
pub(crate) struct CellStack(Option<Cell>);
244248

@@ -282,7 +286,7 @@ impl CellStack {
282286
}
283287
}
284288

285-
/// If self currency contains a cell, this replaces the digit at
289+
/// If self currently contains a cell, this replaces the digit at
286290
/// its current res and returns what was there. If self is empty,
287291
/// nothing is replaced and None is returned.
288292
pub fn swap(&mut self, digit: u8) -> Option<u8> {

src/compaction.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
1-
//! User pluggable compaction.
1+
//! User-pluggable compaction strategies.
2+
//!
3+
//! Compaction allows the tree to automatically coalesce child cells into
4+
//! their parent when certain conditions are met, reducing memory usage
5+
//! and improving query performance.
26
37
use crate::Cell;
48

5-
/// A user provided compactor.
9+
/// A user-provided compactor.
610
///
7-
/// The compactor trait allows you customize compaction behavior after
11+
/// The compactor trait allows you to customize compaction behavior after
812
/// calling `insert` on a tree.
913
pub trait Compactor<V> {
1014
/// Called after every insert into a non-leaf node.
1115
///
12-
/// Given an intermediate (not-leaf) node's cell and up to 7
16+
/// Given an intermediate (non-leaf) node's cell and up to 7
1317
/// children, you can choose to leave the node alone by returning
14-
/// `None`, or turn it into a leaf-node by return `Some(value)`.
18+
/// `None`, or turn it into a leaf node by returning `Some(value)`.
1519
fn compact(&mut self, cell: Cell, children: [Option<&V>; 7]) -> Option<V>;
1620
}
1721

18-
/// Does not perform any compaction.
22+
/// A compactor that performs no compaction.
23+
///
24+
/// This is the default compactor and leaves all inserted cells as-is.
1925
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
2026
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2127
pub struct NullCompactor;
@@ -26,7 +32,11 @@ impl<V> Compactor<V> for NullCompactor {
2632
}
2733
}
2834

29-
/// Compacts when all children are complete.
35+
/// A compactor that coalesces nodes when all 7 children are present.
36+
///
37+
/// This is typically used with `HexTreeSet` (where values are `()`).
38+
/// When all 7 children of a node are complete, they are replaced with
39+
/// a single parent cell.
3040
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
3141
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3242
pub struct SetCompactor;
@@ -41,7 +51,11 @@ impl Compactor<()> for SetCompactor {
4151
}
4252
}
4353

44-
/// Compacts when all children are complete and have the same value.
54+
/// A compactor that coalesces nodes when all 7 children have equal values.
55+
///
56+
/// When all 7 children of a node are present and have the same value,
57+
/// they are replaced with a single parent cell containing that value.
58+
/// This is useful for maps where large contiguous regions share the same value.
4559
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
4660
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4761
pub struct EqCompactor;

src/disktree/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
//! An on-disk hextree.
1+
//! On-disk memory-mapped storage for HexTree.
2+
//!
3+
//! DiskTree provides a serialized, memory-mapped representation of a HexTreeMap,
4+
//! allowing you to store and query very large trees without loading them entirely
5+
//! into memory.
26
37
#[cfg(not(target_pointer_width = "64"))]
48
compile_warning!("disktree may silently fail on non-64bit systems");
@@ -36,7 +40,7 @@ mod tests {
3640
}
3741

3842
// Construct map with a compactor that automatically combines
39-
// cells with the same save value.
43+
// cells with the same value.
4044
let mut monaco = HexTreeMap::with_compactor(EqCompactor);
4145

4246
// Now extend the map with cells and a region value.
@@ -190,7 +194,7 @@ mod tests {
190194
}
191195

192196
// Construct map with a compactor that automatically combines
193-
// cells with the same save value.
197+
// cells with the same value.
194198
let mut monaco = HexTreeMap::new();
195199

196200
// Now extend the map with cells and a region value.
@@ -204,7 +208,7 @@ mod tests {
204208
.unwrap();
205209
let monaco_disktree = DiskTreeMap::open(path).unwrap();
206210

207-
// Create the iterator with the user-defined deserialzer.
211+
// Create the iterator with the user-defined deserializer.
208212
let disktree_iter = monaco_disktree.iter().unwrap();
209213
let start = std::time::Instant::now();
210214
let mut disktree_collection = Vec::new();
@@ -294,7 +298,7 @@ mod tests {
294298
assert_eq!(
295299
leaf_vec.len(),
296300
1,
297-
"Iterator must have extactly one element for a leaf"
301+
"Iterator must have exactly one element for a leaf"
298302
);
299303
assert_eq!(hextree_leaf, leaf_vec[0].0);
300304
}

src/disktree/tree.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ use std::{
1616
pub(crate) const HDR_MAGIC: &[u8] = b"hextree\0";
1717
pub(crate) const HDR_SZ: usize = HDR_MAGIC.len() + 1;
1818

19-
/// An on-disk hextree map.
19+
/// A memory-mapped, on-disk HexTreeMap.
20+
///
21+
/// This structure provides read-only access to a HexTreeMap that has
22+
/// been serialized to disk.
2023
pub struct DiskTreeMap(pub(crate) Box<dyn AsRef<[u8]> + Send + Sync + 'static>);
2124

2225
impl DiskTreeMap {

src/hex_tree_map.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use std::{cmp::PartialEq, iter::FromIterator};
4242
/// }
4343
///
4444
/// // Construct map with a compactor that automatically combines
45-
/// // cells with the same save value.
45+
/// // cells with the same value.
4646
/// let mut monaco = HexTreeMap::with_compactor(EqCompactor);
4747
///
4848
/// // Now extend the map with cells and a region value.
@@ -66,7 +66,7 @@ use std::{cmp::PartialEq, iter::FromIterator};
6666
pub struct HexTreeMap<V, C = NullCompactor> {
6767
/// All h3 0 base cell indices in the tree
6868
pub(crate) nodes: Box<[Option<Box<Node<V>>>]>,
69-
/// User-provided compator. Defaults to the null compactor.
69+
/// User-provided compactor. Defaults to the null compactor.
7070
compactor: C,
7171
}
7272

@@ -121,7 +121,7 @@ impl<V, C> HexTreeMap<V, C> {
121121
/// `self`.
122122
///
123123
/// This method is useful if you want to use one compaction
124-
/// strategy for creating an initial, then another one for updates
124+
/// strategy for creating an initial tree, then another one for updates
125125
/// later.
126126
pub fn replace_compactor<NewC>(self, new_compactor: NewC) -> HexTreeMap<V, NewC> {
127127
HexTreeMap {
@@ -130,12 +130,11 @@ impl<V, C> HexTreeMap<V, C> {
130130
}
131131
}
132132

133-
/// Returns the number of H3 cells in the set.
133+
/// Returns the number of H3 cells in the map.
134134
///
135-
/// This method only considers complete, or leaf, cells in the
136-
/// set. Due to automatic compaction, this number may be
137-
/// significantly smaller than the number of source cells used to
138-
/// create the set.
135+
/// This method only counts leaf cells (complete entries) in the
136+
/// map. Due to automatic compaction, this number may be
137+
/// significantly smaller than the number of cells originally inserted.
139138
pub fn len(&self) -> usize {
140139
self.nodes.iter().flatten().map(|node| node.len()).sum()
141140
}
@@ -145,17 +144,15 @@ impl<V, C> HexTreeMap<V, C> {
145144
self.len() == 0
146145
}
147146

148-
/// Returns `true` if the set fully contains `cell`.
147+
/// Returns `true` if the map fully contains `cell`.
149148
///
150-
/// This method will return `true` if any of the following are
151-
/// true:
149+
/// This method returns `true` if any of the following are true:
152150
///
153-
/// 1. There was an earlier [insert][Self::insert] call with
154-
/// precisely this target cell.
155-
/// 2. Several previously inserted cells coalesced into
156-
/// precisely this target cell.
157-
/// 3. The set contains a complete (leaf) parent of this target
158-
/// cell due to 1 or 2.
151+
/// 1. This exact cell was previously inserted.
152+
/// 2. Several previously inserted cells were compacted into
153+
/// this cell as their parent.
154+
/// 3. The map contains a parent of this cell (due to 1 or 2),
155+
/// meaning this cell inherits its parent's value.
159156
pub fn contains(&self, cell: Cell) -> bool {
160157
let base_cell = cell.base();
161158
match self.nodes[base_cell as usize].as_ref() {
@@ -167,11 +164,11 @@ impl<V, C> HexTreeMap<V, C> {
167164
}
168165
}
169166

170-
/// Returns a reference to the value corresponding to the given
171-
/// target cell or one of its parents.
167+
/// Returns a reference to the value for the given cell or its nearest parent.
172168
///
173-
/// Note that this method also returns a Cell, which may be a
174-
/// parent of the target cell provided.
169+
/// Returns `Some((cell, value))` where `cell` is either the queried cell
170+
/// or a parent cell that contains it. Returns `None` if no matching cell
171+
/// or parent is found.
175172
#[inline]
176173
pub fn get(&self, cell: Cell) -> Option<(Cell, &V)> {
177174
match self.get_raw(cell) {
@@ -192,11 +189,11 @@ impl<V, C> HexTreeMap<V, C> {
192189
}
193190
}
194191

195-
/// Returns a mutable reference to the value corresponding to the
196-
/// given target cell or one of its parents.
192+
/// Returns a mutable reference to the value for the given cell or its nearest parent.
197193
///
198-
/// Note that this method also returns a Cell, which may be a
199-
/// parent of the target cell provided.
194+
/// Returns `Some((cell, value))` where `cell` is either the queried cell
195+
/// or a parent cell that contains it. Returns `None` if no matching cell
196+
/// or parent is found.
200197
#[inline]
201198
pub fn get_mut(&mut self, cell: Cell) -> Option<(Cell, &mut V)> {
202199
match self.get_raw_mut(cell) {
@@ -242,7 +239,7 @@ impl<V, C> HexTreeMap<V, C> {
242239
crate::iteration::IterMut::new(&mut self.nodes, CellStack::new())
243240
}
244241

245-
/// An iterator visiting the specified cell or its children
242+
/// An iterator visiting the specified cell or its children with
246243
/// references to the values.
247244
pub fn descendants(&self, cell: Cell) -> impl Iterator<Item = (Cell, &V)> {
248245
let base_cell = cell.base();

src/hex_tree_set.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{compaction::SetCompactor, Cell, HexTreeMap};
22
use std::iter::FromIterator;
33

44
/// A HexTreeSet is a structure for representing geographical regions
5-
/// and efficiently testing performing hit-tests on that region. Or,
5+
/// and efficiently performing hit-tests on that region. Or,
66
/// in other words: I have a region defined; does it contain this
77
/// point on earth?
88
///

0 commit comments

Comments
 (0)