vers_vecs/trees/bp/mod.rs
1//! A succinct tree data structure backed by the balanced parenthesis representation.
2//! The tree supports navigation operations between parent, child, and sibling nodes in `O(log n)`
3//! time, as well as subtree size, level-order, and ancestor queries in `O(log n)` time.
4//! The tree is succinct (ideally sublinear space overhead) and pointer-less.
5
6use crate::bit_vec::fast_rs_vec::SelectIntoIter;
7use crate::trees::mmt::MinMaxTree;
8use crate::trees::{IsAncestor, LevelTree, SubtreeSize, Tree};
9use crate::{BitVec, RsVec};
10use std::cmp::{max, min};
11use std::iter::FusedIterator;
12
13/// The default block size for the tree, used in several const generics
14const DEFAULT_BLOCK_SIZE: usize = 512;
15
16const OPEN_PAREN: u64 = 1;
17const CLOSE_PAREN: u64 = 0;
18
19mod builder;
20// re-export the builders toplevel
21pub use builder::BpBuilder;
22
23#[cfg(feature = "bp_u16_lookup")]
24mod lookup;
25#[cfg(feature = "bp_u16_lookup")]
26use lookup::{process_block_bwd, process_block_fwd, LOOKUP_BLOCK_SIZE};
27
28#[cfg(not(feature = "bp_u16_lookup"))]
29mod lookup_query;
30#[cfg(not(feature = "bp_u16_lookup"))]
31use lookup_query::{process_block_bwd, process_block_fwd, LOOKUP_BLOCK_SIZE};
32
33/// A succinct tree data structure based on balanced parenthesis expressions.
34/// A tree with `n` nodes is encoded in a bit vector using `2n` bits plus the rank/select overhead
35/// of the [`RsVec`] implementation.
36/// Additionally, a small pointerless heap data structure stores
37/// additional meta information required to perform most tree operations.
38///
39/// The tree is thus pointer-less and succinct.
40/// It supports tree navigation operations between parent, child, and sibling nodes, both in
41/// depth-first search order and in level order.
42/// All operations run in `O(log n)` time with small overheads.
43///
44/// ## Lookup Table
45/// The tree internally uses a lookup table for subqueries on blocks of bits.
46/// The lookup table requires 4 KiB of memory and is compiled into the binary.
47/// If the `bp_u16_lookup` feature is enabled, a larger lookup table is used, which requires 128 KiB of
48/// memory, but answers queries faster.
49///
50/// ## Block Size
51/// The tree has a block size of 512 bits by default, which can be changed by setting the
52/// `BLOCK_SIZE` generic parameter.
53/// This block size is expected to be a good choice for most applications,
54/// as it will fit a cache line.
55///
56/// If you want to tune the parameter,
57/// the block size should be chosen based on the expected size of the tree and the available memory.
58/// Smaller block sizes increase the size of the supporting data structure but reduce the time
59/// complexity of some operations by a constant amount.
60/// Larger block sizes are best combined with the `bp_u16_lookup` feature to keep the query time
61/// low.
62/// In any case, benchmarking for the specific use case is recommended for tuning.
63///
64/// ## Unbalanced Parentheses
65/// The tree is implemented in a way to theoretically support unbalanced parenthesis expressions
66/// (which encode invalid trees) without panicking.
67/// However, some operations may behave erratically if the parenthesis expression isn't balanced.
68/// Generally, operations specify if they require a balanced tree.
69///
70/// The results of the operations are unspecified,
71/// meaning no guarantees are made about the stability of the results across versions
72/// (except the operations not panicking).
73/// However, for research purposes, this behavior can be useful and should yield expected results
74/// in most cases.
75///
76/// Only the basic operations like [`fwd_search`] and [`bwd_search`],
77/// as well as the tree navigation operations
78/// (defined by the traits [`Tree`], [`IsAncestor`], [`LevelTree`], and [`SubtreeSize`]),
79/// are included in this guarantee.
80/// Additional operations like iterators may panic if the tree is unbalanced (this is documented per
81/// operation).
82///
83/// # Examples
84///
85/// The high-level approach to building a tree is to use the [`BpBuilder`] to construct the tree
86/// using depth-first traversal of all its nodes.
87/// ```rust
88/// # #![allow(long_running_const_eval)] // for some reason this is needed for test cases
89/// use vers_vecs::{BitVec, BpBuilder, BpTree, TreeBuilder, Tree};
90///
91/// let mut builder = BpBuilder::<512>::new();
92///
93/// // build the tree by depth-first traversal
94/// builder.enter_node();
95/// builder.enter_node();
96/// builder.enter_node();
97/// builder.leave_node();
98/// builder.enter_node();
99/// builder.leave_node();
100/// builder.leave_node();
101/// builder.enter_node();
102/// builder.leave_node();
103/// builder.leave_node();
104///
105/// let tree = builder.build().unwrap();
106/// let root = tree.root().unwrap();
107/// assert_eq!(root, 0);
108/// assert_eq!(tree.first_child(root), Some(1));
109/// assert_eq!(tree.next_sibling(1), Some(7));
110/// assert_eq!(tree.next_sibling(7), None);
111///
112/// assert_eq!(root, 0);
113/// assert_eq!(tree.depth(2), 2);
114/// assert_eq!(tree.depth(7), 1);
115/// ```
116///
117/// Alternatively, the tree can be constructed from a [`BitVec`] containing the parenthesis
118/// expression directly.
119/// This is also how trees with unbalanced parenthesis expressions can be constructed.
120///
121/// ```rust
122/// # #![allow(long_running_const_eval)]
123/// use vers_vecs::{BitVec, BpTree, Tree};
124/// let bv = BitVec::pack_sequence_u8(&[0b1101_0111, 0b0010_0100], 8);
125/// let tree = BpTree::<4>::from_bit_vector(bv);
126///
127/// let nodes = tree.dfs_iter().collect::<Vec<_>>();
128/// assert_eq!(nodes, vec![0, 1, 2, 4, 6, 7, 10, 13]);
129/// ```
130///
131/// [`RsVec`]: RsVec
132/// [`fwd_search`]: BpTree::fwd_search
133/// [`bwd_search`]: BpTree::bwd_search
134/// [`Tree`]: Tree
135/// [`IsAncestor`]: IsAncestor
136/// [`LevelTree`]: LevelTree
137/// [`SubtreeSize`]: SubtreeSize
138/// [`BpBuilder`]: BpBuilder
139/// [`BitVec`]: BitVec
140#[derive(Clone, Debug)]
141#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
142pub struct BpTree<const BLOCK_SIZE: usize = DEFAULT_BLOCK_SIZE> {
143 vec: RsVec,
144 min_max_tree: MinMaxTree,
145}
146
147impl<const BLOCK_SIZE: usize> BpTree<BLOCK_SIZE> {
148 /// Construct a new `BpTree` from a given bit vector.
149 #[must_use]
150 pub fn from_bit_vector(bv: BitVec) -> Self {
151 let min_max_tree = MinMaxTree::excess_tree(&bv, BLOCK_SIZE);
152 let vec = bv.into();
153 Self { vec, min_max_tree }
154 }
155
156 /// Search for a position where the excess relative to the starting `index` is `relative_excess`.
157 /// Returns `None` if no such position exists.
158 /// The initial position is never considered in the search.
159 /// Searches forward in the bit vector.
160 ///
161 /// # Arguments
162 /// - `index`: The starting index.
163 /// - `relative_excess`: The desired relative excess value.
164 pub fn fwd_search(&self, index: usize, mut relative_excess: i64) -> Option<usize> {
165 // check for greater than or equal length minus one, because the last element
166 // won't ever have a result from fwd_search
167 if index >= (self.vec.len() - 1) {
168 return None;
169 }
170
171 let block_index = (index + 1) / BLOCK_SIZE;
172 self.fwd_search_block(index, block_index, &mut relative_excess)
173 .map_or_else(
174 |()| {
175 // find the block that contains the desired relative excess
176 let block = self.min_max_tree.fwd_search(block_index, relative_excess);
177
178 // check the result block for the exact position
179 block.and_then(|(block, mut relative_excess)| {
180 self.fwd_search_block(block * BLOCK_SIZE - 1, block, &mut relative_excess)
181 .ok()
182 })
183 },
184 Some,
185 )
186 }
187
188 /// Perform the forward search within one block. If this doesn't yield a result, the caller must
189 /// continue the search in the min-max-tree.
190 ///
191 /// Returns Ok(index) if an index with the desired relative excess is found, or None(excess)
192 /// with the excess at the end of the current block if no index with the desired relative excess
193 /// is found.
194 #[inline(always)]
195 fn fwd_search_block(
196 &self,
197 start_index: usize,
198 block_index: usize,
199 relative_excess: &mut i64,
200 ) -> Result<usize, ()> {
201 let block_boundary = min((block_index + 1) * BLOCK_SIZE, self.vec.len());
202
203 // the boundary at which we can start with table lookups
204 let lookup_boundary = min(
205 (start_index + 1).div_ceil(LOOKUP_BLOCK_SIZE as usize) * LOOKUP_BLOCK_SIZE as usize,
206 block_boundary,
207 );
208 for i in start_index + 1..lookup_boundary {
209 let bit = self.vec.get_unchecked(i);
210 *relative_excess -= if bit == 1 { 1 } else { -1 };
211
212 if *relative_excess == 0 {
213 return Ok(i);
214 }
215 }
216
217 // the boundary up to which we can use table lookups
218 let upper_lookup_boundary = max(
219 lookup_boundary,
220 (block_boundary / LOOKUP_BLOCK_SIZE as usize) * LOOKUP_BLOCK_SIZE as usize,
221 );
222
223 for i in (lookup_boundary..upper_lookup_boundary).step_by(LOOKUP_BLOCK_SIZE as usize) {
224 if let Ok(idx) = process_block_fwd(
225 self.vec
226 .get_bits_unchecked(i, LOOKUP_BLOCK_SIZE as usize)
227 .try_into()
228 .unwrap(),
229 relative_excess,
230 ) {
231 return Ok(i + idx as usize);
232 }
233 }
234
235 // if the upper_lookup_boundary isn't the block_boundary (which happens in non-full blocks, i.e. the last
236 // block in the vector)
237 for i in upper_lookup_boundary..block_boundary {
238 let bit = self.vec.get_unchecked(i);
239 *relative_excess -= if bit == 1 { 1 } else { -1 };
240
241 if *relative_excess == 0 {
242 return Ok(i);
243 }
244 }
245
246 Err(())
247 }
248
249 /// Search for a position where the excess relative to the starting `index` is `relative_excess`.
250 /// Returns `None` if no such position exists.
251 /// The initial position is never considered in the search.
252 /// Searches backward in the bit vector.
253 ///
254 /// # Arguments
255 /// - `index`: The starting index.
256 /// - `relative_excess`: The desired relative excess value.
257 pub fn bwd_search(&self, index: usize, mut relative_excess: i64) -> Option<usize> {
258 if index >= self.vec.len() {
259 return None;
260 }
261
262 // if the index is 0, we cant have a valid result anyway, and this would overflow the
263 // subtraction below, so we report None
264 if index == 0 {
265 return None;
266 }
267
268 // calculate the block we start searching in. It starts at index - 1, so we don't accidentally
269 // search the mM tree and immediately find `index` as the position
270 let block_index = (index - 1) / BLOCK_SIZE;
271
272 // check the current block
273 self.bwd_search_block(index, block_index, &mut relative_excess)
274 .map_or_else(
275 |()| {
276 // find the block that contains the desired relative excess
277 let block = self.min_max_tree.bwd_search(block_index, relative_excess);
278
279 // check the result block for the exact position
280 block.and_then(|(block, mut relative_excess)| {
281 self.bwd_search_block((block + 1) * BLOCK_SIZE, block, &mut relative_excess)
282 .ok()
283 })
284 },
285 Some,
286 )
287 }
288
289 /// Perform the backward search within one block. If this doesn't yield a result, the caller must
290 /// continue the search in the min-max-tree.
291 ///
292 /// Returns Ok(index) if an index with the desired relative excess is found, or None(excess)
293 /// with the excess at the end of the current block if no index with the desired relative excess
294 /// is found.
295 #[inline(always)]
296 fn bwd_search_block(
297 &self,
298 start_index: usize,
299 block_index: usize,
300 relative_excess: &mut i64,
301 ) -> Result<usize, ()> {
302 let block_boundary = min(block_index * BLOCK_SIZE, self.vec.len());
303
304 // the boundary at which we can start with table lookups
305 let lookup_boundary = max(
306 ((start_index - 1) / LOOKUP_BLOCK_SIZE as usize) * LOOKUP_BLOCK_SIZE as usize,
307 block_boundary,
308 );
309 for i in (lookup_boundary..start_index).rev() {
310 let bit = self.vec.get_unchecked(i);
311 *relative_excess += if bit == 1 { 1 } else { -1 };
312
313 if *relative_excess == 0 {
314 return Ok(i);
315 }
316 }
317
318 for i in (block_boundary..lookup_boundary)
319 .step_by(LOOKUP_BLOCK_SIZE as usize)
320 .rev()
321 {
322 if let Ok(idx) = process_block_bwd(
323 self.vec
324 .get_bits_unchecked(i, LOOKUP_BLOCK_SIZE as usize)
325 .try_into()
326 .unwrap(),
327 relative_excess,
328 ) {
329 return Ok(i + idx as usize);
330 }
331 }
332
333 Err(())
334 }
335
336 /// Find the position of the matching closing parenthesis for the opening parenthesis at `index`.
337 /// If the bit at `index` is not an opening parenthesis, the result is meaningless.
338 /// If there is no matching closing parenthesis, `None` is returned.
339 #[must_use]
340 pub fn close(&self, index: usize) -> Option<usize> {
341 if index >= self.vec.len() {
342 return None;
343 }
344
345 self.fwd_search(index, -1)
346 }
347
348 /// Find the position of the matching opening parenthesis for the closing parenthesis at `index`.
349 /// If the bit at `index` is not a closing parenthesis, the result is meaningless.
350 /// If there is no matching opening parenthesis, `None` is returned.
351 #[must_use]
352 pub fn open(&self, index: usize) -> Option<usize> {
353 if index >= self.vec.len() {
354 return None;
355 }
356
357 self.bwd_search(index, -1)
358 }
359
360 /// Find the position of the opening parenthesis that encloses the position `index`.
361 /// This works regardless of whether the bit at `index` is an opening or closing parenthesis.
362 /// If there is no enclosing parenthesis, `None` is returned.
363 #[must_use]
364 pub fn enclose(&self, index: usize) -> Option<usize> {
365 if index >= self.vec.len() {
366 return None;
367 }
368
369 self.bwd_search(
370 index,
371 if self.vec.get_unchecked(index) == 1 {
372 -1
373 } else {
374 -2
375 },
376 )
377 }
378
379 /// Get the excess of open parentheses up to and including the position `index`.
380 /// The excess is the number of open parentheses minus the number of closing parentheses.
381 /// If `index` is out of bounds, the total excess of the parentheses expression is returned.
382 #[must_use]
383 pub fn excess(&self, index: usize) -> i64 {
384 debug_assert!(index < self.vec.len(), "Index out of bounds");
385 self.vec.rank1(index + 1) as i64 - self.vec.rank0(index + 1) as i64
386 }
387
388 /// Iterate over the nodes of the tree.
389 /// The iterator yields the nodes in depth-first (pre-)order.
390 /// This method is an alias for [`dfs_iter`].
391 ///
392 /// If the tree is unbalanced, the iterator returns the node handles in the order they appear in
393 /// the parenthesis expression, and it will return handles that don't have a matching closing
394 /// parenthesis.
395 ///
396 /// [`dfs_iter`]: BpTree::dfs_iter
397 pub fn iter(
398 &self,
399 ) -> impl Iterator<Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle> + use<'_, BLOCK_SIZE> {
400 self.dfs_iter()
401 }
402
403 /// Iterate over the nodes of the tree in depth-first (pre-)order.
404 /// This is the most efficient way to iterate over all nodes of the tree.
405 ///
406 /// If the tree is unbalanced, the iterator returns the node handles in the order they appear in
407 /// the parenthesis expression, and it will return handles that don't have a matching closing
408 /// parenthesis.
409 pub fn dfs_iter(
410 &self,
411 ) -> impl Iterator<Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle> + use<'_, BLOCK_SIZE> {
412 self.vec.iter1()
413 }
414
415 /// Iterate over the nodes of a valid tree in depth-first (post-)order.
416 /// This is slower than the pre-order iteration.
417 ///
418 /// # Panics
419 /// The iterator may panic at any point if the parenthesis expression is unbalanced.
420 pub fn dfs_post_iter(
421 &self,
422 ) -> impl Iterator<Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle> + use<'_, BLOCK_SIZE> {
423 self.vec.iter0().map(|n| self.open(n).unwrap())
424 }
425
426 /// Iterate over a subtree rooted at `node` in depth-first (pre-)order.
427 /// The iteration starts with the node itself.
428 ///
429 /// Calling this method on an invalid node handle, or an unbalanced parenthesis expression,
430 /// will produce an iterator over an unspecified subset of nodes.
431 pub fn subtree_iter(
432 &self,
433 node: <BpTree<BLOCK_SIZE> as Tree>::NodeHandle,
434 ) -> impl Iterator<Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle> + use<'_, BLOCK_SIZE> {
435 debug_assert!(
436 self.vec.get(node) == Some(OPEN_PAREN),
437 "Node handle is invalid"
438 );
439
440 let index = self.vec.rank1(node);
441 let close = self.close(node).unwrap_or(node);
442 let subtree_size = self.vec.rank1(close) - index;
443
444 self.vec.iter1().skip(index).take(subtree_size)
445 }
446
447 /// Iterate over a subtree rooted at `node` in depth-first (post-)order.
448 /// This is slower than the pre-order iteration.
449 /// The iteration ends with the node itself.
450 ///
451 /// # Panics
452 /// Calling this method on an invalid node handle, or an unbalanced parenthesis expression,
453 /// will produce an iterator over an unspecified subset of nodes, or panic either during
454 /// construction or iteration.
455 pub fn subtree_post_iter(
456 &self,
457 node: <BpTree<BLOCK_SIZE> as Tree>::NodeHandle,
458 ) -> impl Iterator<Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle> + use<'_, BLOCK_SIZE> {
459 debug_assert!(
460 self.vec.get(node) == Some(OPEN_PAREN),
461 "Node handle is invalid"
462 );
463
464 let index = self.vec.rank0(node);
465 let close = self.close(node).unwrap_or(node);
466 let subtree_size = self.vec.rank0(close) + 1 - index;
467
468 self.vec
469 .iter0()
470 .skip(index)
471 .take(subtree_size)
472 .map(|n| self.open(n).unwrap())
473 }
474
475 /// Iterate over the children of a node in the tree.
476 /// The iterator yields the children in the order they appear in the parenthesis expression.
477 /// If the node is a leaf, the iterator is empty.
478 /// If the node is not a valid node handle, or the tree is unbalanced,
479 /// the iterator will produce an unspecified subset of the tree's nodes.
480 pub fn children(
481 &self,
482 node: <BpTree<BLOCK_SIZE> as Tree>::NodeHandle,
483 ) -> impl Iterator<Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle> + use<'_, BLOCK_SIZE> {
484 debug_assert!(
485 self.vec.get(node) == Some(OPEN_PAREN),
486 "Node handle is invalid"
487 );
488
489 ChildrenIter::<BLOCK_SIZE, true>::new(self, node)
490 }
491
492 /// Iterate over the children of a node in the tree in reverse order.
493 /// The iterator yields the children in the reverse order they appear in the parenthesis expression.
494 /// If the node is a leaf, the iterator is empty.
495 /// If the node is not a valid node handle, or the tree is unbalanced,
496 /// the iterator will produce an unspecified subset of the tree's nodes.
497 pub fn rev_children(
498 &self,
499 node: <BpTree<BLOCK_SIZE> as Tree>::NodeHandle,
500 ) -> impl Iterator<Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle> + use<'_, BLOCK_SIZE> {
501 debug_assert!(
502 self.vec.get(node) == Some(OPEN_PAREN),
503 "Node handle is invalid"
504 );
505
506 ChildrenIter::<BLOCK_SIZE, false>::new(self, node)
507 }
508
509 /// Transform the tree into a [`RsVec`] containing the balanced parenthesis expression.
510 /// This consumes the tree and returns the underlying bit vector with the rank and select
511 /// support structure.
512 /// The remaining min-max-tree support structure of the `BpTree` is discarded.
513 /// Since the tree is innately immutable, this is the only way to access the underlying bit
514 /// vector for potential modification.
515 /// Modification requires turning the `RsVec` back into a `BitVec`, discarding the rank and select
516 /// support structure, however.
517 ///
518 /// # Examples
519 /// ```rust
520 /// use vers_vecs::{BitVec, RsVec, BpTree, Tree};
521 ///
522 /// let bv = BitVec::pack_sequence_u8(&[0b1101_0111, 0b0010_0100], 8);
523 /// let tree = BpTree::<4>::from_bit_vector(bv);
524 /// assert_eq!(tree.size(), 8);
525 ///
526 /// let rs_vec = tree.into_parentheses_vec();
527 /// let mut bv = rs_vec.into_bit_vec();
528 ///
529 /// bv.flip_bit(15);
530 /// bv.append_bits(0, 2);
531 /// let tree = BpTree::<4>::from_bit_vector(bv);
532 /// assert_eq!(tree.size(), 9);
533 /// ```
534 #[must_use]
535 pub fn into_parentheses_vec(self) -> RsVec {
536 self.vec
537 }
538
539 /// Returns the number of bytes used on the heap for this tree. This does not include
540 /// allocated space that is not used (e.g. by the allocation behavior of `Vec`).
541 #[must_use]
542 pub fn heap_size(&self) -> usize {
543 self.vec.heap_size() + self.min_max_tree.heap_size()
544 }
545}
546
547impl<const BLOCK_SIZE: usize> Tree for BpTree<BLOCK_SIZE> {
548 type NodeHandle = usize;
549
550 fn root(&self) -> Option<Self::NodeHandle> {
551 if self.vec.is_empty() {
552 None
553 } else {
554 Some(0)
555 }
556 }
557
558 fn parent(&self, node: Self::NodeHandle) -> Option<Self::NodeHandle> {
559 debug_assert!(
560 self.vec.get(node) == Some(OPEN_PAREN),
561 "Node handle is invalid"
562 );
563
564 self.enclose(node)
565 }
566
567 fn first_child(&self, node: Self::NodeHandle) -> Option<Self::NodeHandle> {
568 debug_assert!(
569 self.vec.get(node) == Some(OPEN_PAREN),
570 "Node handle is invalid"
571 );
572
573 if let Some(bit) = self.vec.get(node + 1) {
574 if bit == OPEN_PAREN {
575 return Some(node + 1);
576 }
577 }
578
579 None
580 }
581
582 fn next_sibling(&self, node: Self::NodeHandle) -> Option<Self::NodeHandle> {
583 debug_assert!(
584 self.vec.get(node) == Some(OPEN_PAREN),
585 "Node handle is invalid"
586 );
587 self.close(node).and_then(|i| {
588 self.vec
589 .get(i + 1)
590 .and_then(|bit| if bit == OPEN_PAREN { Some(i + 1) } else { None })
591 })
592 }
593
594 fn previous_sibling(&self, node: Self::NodeHandle) -> Option<Self::NodeHandle> {
595 debug_assert!(
596 self.vec.get(node) == Some(OPEN_PAREN),
597 "Node handle is invalid"
598 );
599 if node == 0 {
600 None
601 } else {
602 self.vec.get(node - 1).and_then(|bit| {
603 if bit == CLOSE_PAREN {
604 self.open(node - 1)
605 } else {
606 None
607 }
608 })
609 }
610 }
611
612 fn last_child(&self, node: Self::NodeHandle) -> Option<Self::NodeHandle> {
613 debug_assert!(
614 self.vec.get(node) == Some(OPEN_PAREN),
615 "Node handle is invalid"
616 );
617 self.vec.get(node + 1).and_then(|bit| {
618 if bit == OPEN_PAREN {
619 if let Some(i) = self.close(node) {
620 self.open(i - 1)
621 } else {
622 None
623 }
624 } else {
625 None
626 }
627 })
628 }
629
630 fn node_index(&self, node: Self::NodeHandle) -> usize {
631 debug_assert!(
632 self.vec.get(node) == Some(OPEN_PAREN),
633 "Node handle is invalid"
634 );
635 self.vec.rank1(node)
636 }
637
638 fn node_handle(&self, index: usize) -> Self::NodeHandle {
639 self.vec.select1(index)
640 }
641
642 fn is_leaf(&self, node: Self::NodeHandle) -> bool {
643 debug_assert!(
644 self.vec.get(node) == Some(OPEN_PAREN),
645 "Node handle is invalid"
646 );
647 self.vec.get(node + 1) == Some(CLOSE_PAREN)
648 }
649
650 fn depth(&self, node: Self::NodeHandle) -> u64 {
651 debug_assert!(
652 self.vec.get(node) == Some(OPEN_PAREN),
653 "Node handle is invalid"
654 );
655 let excess: u64 = self.excess(node).try_into().unwrap_or(0);
656 excess.saturating_sub(1)
657 }
658
659 fn size(&self) -> usize {
660 self.vec.rank1(self.vec.len())
661 }
662
663 fn is_empty(&self) -> bool {
664 self.vec.is_empty()
665 }
666}
667
668impl<const BLOCK_SIZE: usize> IsAncestor for BpTree<BLOCK_SIZE> {
669 fn is_ancestor(
670 &self,
671 ancestor: Self::NodeHandle,
672 descendant: Self::NodeHandle,
673 ) -> Option<bool> {
674 debug_assert!(
675 self.vec.get(ancestor) == Some(OPEN_PAREN),
676 "Node handle is invalid"
677 );
678 debug_assert!(
679 self.vec.get(descendant) == Some(OPEN_PAREN),
680 "Node handle is invalid"
681 );
682
683 self.close(ancestor)
684 .map(|closing| ancestor <= descendant && descendant < closing)
685 }
686}
687
688impl<const BLOCK_SIZE: usize> LevelTree for BpTree<BLOCK_SIZE> {
689 fn level_ancestor(&self, node: Self::NodeHandle, level: u64) -> Option<Self::NodeHandle> {
690 if level == 0 {
691 return Some(node);
692 }
693
694 #[allow(clippy::cast_possible_wrap)]
695 // if the level exceeds 2^63, we accept that the result is wrong
696 self.bwd_search(node, -(level as i64))
697 }
698
699 fn level_next(&self, node: Self::NodeHandle) -> Option<Self::NodeHandle> {
700 self.fwd_search(self.close(node)?, 1)
701 }
702
703 fn level_prev(&self, node: Self::NodeHandle) -> Option<Self::NodeHandle> {
704 self.open(self.bwd_search(node, 1)?)
705 }
706
707 fn level_leftmost(&self, level: u64) -> Option<Self::NodeHandle> {
708 // fwd_search doesn't support returning the input position
709 if level == 0 {
710 return Some(0);
711 }
712
713 #[allow(clippy::cast_possible_wrap)]
714 // if the level exceeds 2^63, we accept that the result is wrong
715 self.fwd_search(0, level as i64)
716 }
717
718 fn level_rightmost(&self, level: u64) -> Option<Self::NodeHandle> {
719 #[allow(clippy::cast_possible_wrap)]
720 // if the level exceeds 2^63, we accept that the result is wrong
721 self.open(self.bwd_search(self.size() * 2 - 1, level as i64)?)
722 }
723}
724
725impl<const BLOCK_SIZE: usize> SubtreeSize for BpTree<BLOCK_SIZE> {
726 fn subtree_size(&self, node: Self::NodeHandle) -> Option<usize> {
727 debug_assert!(
728 self.vec.get(node) == Some(OPEN_PAREN),
729 "Node handle is invalid"
730 );
731
732 self.close(node)
733 .map(|c| self.vec.rank1(c) - self.vec.rank1(node))
734 }
735}
736
737impl<const BLOCK_SIZE: usize> IntoIterator for BpTree<BLOCK_SIZE> {
738 type Item = <BpTree<BLOCK_SIZE> as Tree>::NodeHandle;
739 type IntoIter = SelectIntoIter<false>;
740
741 fn into_iter(self) -> Self::IntoIter {
742 self.vec.into_iter1()
743 }
744}
745
746impl<const BLOCK_SIZE: usize> From<BitVec> for BpTree<BLOCK_SIZE> {
747 fn from(bv: BitVec) -> Self {
748 Self::from_bit_vector(bv)
749 }
750}
751
752impl<const BLOCK_SIZE: usize> From<BpTree<BLOCK_SIZE>> for BitVec {
753 fn from(value: BpTree<BLOCK_SIZE>) -> Self {
754 value.into_parentheses_vec().into_bit_vec()
755 }
756}
757
758impl<const BLOCK_SIZE: usize> From<BpTree<BLOCK_SIZE>> for RsVec {
759 fn from(value: BpTree<BLOCK_SIZE>) -> Self {
760 value.into_parentheses_vec()
761 }
762}
763
764/// An iterator over the children of a node.
765/// Calls to `next` return the next child node handle in the order they appear in the parenthesis
766/// expression.
767struct ChildrenIter<'a, const BLOCK_SIZE: usize, const FORWARD: bool> {
768 tree: &'a BpTree<BLOCK_SIZE>,
769 current_sibling: Option<usize>,
770}
771
772impl<'a, const BLOCK_SIZE: usize, const FORWARD: bool> ChildrenIter<'a, BLOCK_SIZE, FORWARD> {
773 fn new(tree: &'a BpTree<BLOCK_SIZE>, node: usize) -> Self {
774 Self {
775 tree,
776 current_sibling: if FORWARD {
777 tree.first_child(node)
778 } else {
779 tree.last_child(node)
780 },
781 }
782 }
783}
784
785impl<const BLOCK_SIZE: usize, const FORWARD: bool> Iterator
786 for ChildrenIter<'_, BLOCK_SIZE, FORWARD>
787{
788 type Item = usize;
789
790 fn next(&mut self) -> Option<Self::Item> {
791 let current = self.current_sibling?;
792 let next = if FORWARD {
793 self.tree.next_sibling(current)
794 } else {
795 self.tree.previous_sibling(current)
796 };
797 self.current_sibling = next;
798 Some(current)
799 }
800}
801
802impl<const BLOCK_SIZE: usize, const FORWARD: bool> FusedIterator
803 for ChildrenIter<'_, BLOCK_SIZE, FORWARD>
804{
805}
806
807#[cfg(test)]
808mod tests;