Skip to main content

miden_crypto/merkle/mmr/
forest.rs

1use core::{
2    fmt::{Binary, Display},
3    ops::{BitAnd, BitOr, BitXor, BitXorAssign},
4};
5
6use super::{InOrderIndex, MmrError};
7use crate::{
8    Felt,
9    utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
10};
11
12/// A compact representation of trees in a forest. Used in the Merkle forest (MMR).
13///
14/// Each active bit of the stored number represents a disjoint tree with number of leaves
15/// equal to the bit position.
16///
17/// The forest value has the following interpretations:
18/// - its value is the number of leaves in the forest
19/// - the version number (MMR is append only so the number of leaves always increases)
20/// - bit count corresponds to the number of trees (trees) in the forest
21/// - each true bit position determines the depth of a tree in the forest
22///
23/// Examples:
24/// - `Forest(0)` is a forest with no trees.
25/// - `Forest(0b01)` is a forest with a single leaf/node (the smallest tree possible).
26/// - `Forest(0b10)` is a forest with a single binary tree with 2 leaves (3 nodes).
27/// - `Forest(0b11)` is a forest with two trees: one with 1 leaf (1 node), and one with 2 leaves (3
28///   nodes).
29/// - `Forest(0b1010)` is a forest with two trees: one with 8 leaves (15 nodes), one with 2 leaves
30///   (3 nodes).
31/// - `Forest(0b1000)` is a forest with one tree, which has 8 leaves (15 nodes).
32///
33/// Forest sizes are capped at [`Forest::MAX_LEAVES`]. Use [`Forest::new`] or
34/// [`Forest::append_leaf`] to enforce the limit.
35#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
36pub struct Forest(usize);
37
38impl Forest {
39    /// Maximum number of leaves supported by the forest.
40    ///
41    /// Rationale:
42    /// - We require `MAX_LEAVES <= usize::MAX / 2 + 1` so `num_nodes()` stays indexable via
43    ///   `usize`.
44    /// - We choose `usize::MAX / 2` (hard cutoff) rather than `usize::MAX / 2 + 1` so the cap is
45    ///   always of the form `2^k - 1` on all targets.
46    /// - With that shape, bitwise OR/XOR of valid forest values remains within bounds, so OR/XOR
47    ///   does not need additional overflow protection.
48    pub const MAX_LEAVES: usize = if (u32::MAX as usize) < (usize::MAX / 2) {
49        u32::MAX as usize
50    } else {
51        usize::MAX / 2
52    };
53
54    /// Creates an empty forest (no trees).
55    pub const fn empty() -> Self {
56        Self(0)
57    }
58
59    /// Creates a forest with `num_leaves` leaves, returning an error if the value is too large.
60    pub fn new(num_leaves: usize) -> Result<Self, DeserializationError> {
61        if !Self::is_valid_size(num_leaves) {
62            return Err(DeserializationError::InvalidValue(format!(
63                "forest size {} exceeds maximum {}",
64                num_leaves,
65                Self::MAX_LEAVES
66            )));
67        }
68        Ok(Self(num_leaves))
69    }
70
71    /// Creates a forest with a given height.
72    ///
73    /// This is equivalent to creating a forest with `1 << height` leaves.
74    ///
75    /// # Panics
76    ///
77    /// This will panic if `height` is greater than `usize::BITS - 1`.
78    pub fn with_height(height: usize) -> Self {
79        assert!(height < usize::BITS as usize);
80        Self::new(1 << height).expect("forest height exceeds maximum")
81    }
82
83    /// Returns true if `num_leaves` is within the supported bounds.
84    pub const fn is_valid_size(num_leaves: usize) -> bool {
85        num_leaves <= Self::MAX_LEAVES
86    }
87
88    /// Returns true if there are no trees in the forest.
89    pub fn is_empty(self) -> bool {
90        self.0 == 0
91    }
92
93    /// Adds exactly one more leaf to the capacity of this forest.
94    ///
95    /// Some smaller trees might be merged together.
96    pub fn append_leaf(&mut self) -> Result<(), MmrError> {
97        if self.0 >= Self::MAX_LEAVES {
98            return Err(MmrError::ForestSizeExceeded {
99                requested: self.0.saturating_add(1),
100                max: Self::MAX_LEAVES,
101            });
102        }
103        self.0 += 1;
104        Ok(())
105    }
106
107    /// Returns a count of leaves in the entire underlying forest (MMR).
108    pub fn num_leaves(self) -> usize {
109        self.0
110    }
111
112    /// Return the total number of nodes of a given forest.
113    ///
114    /// This relies on the `Forest` invariant that `num_leaves() <= Forest::MAX_LEAVES`.
115    /// The internal assertion is a defensive check and should be unreachable for values created
116    /// through validated constructors/deserializers.
117    pub const fn num_nodes(self) -> usize {
118        assert!(self.0 <= Self::MAX_LEAVES);
119        if self.0 <= usize::MAX / 2 {
120            self.0 * 2 - self.num_trees()
121        } else {
122            // If `self.0 > usize::MAX / 2` then we need 128-bit math to double it.
123            let (inner, num_trees) = (self.0 as u128, self.num_trees() as u128);
124            (inner * 2 - num_trees) as usize
125        }
126    }
127
128    /// Return the total number of trees of a given forest (the number of active bits).
129    pub const fn num_trees(self) -> usize {
130        self.0.count_ones() as usize
131    }
132
133    /// Returns the height (bit position) of the largest tree in the forest.
134    ///
135    /// # Panics
136    ///
137    /// This will panic if the forest is empty.
138    pub fn largest_tree_height_unchecked(self) -> usize {
139        // ilog2 is computed with leading zeros, which itself is computed with the intrinsic ctlz.
140        // [Rust 1.67.0] x86 uses the `bsr` instruction. AArch64 uses the `clz` instruction.
141        self.0.ilog2() as usize
142    }
143
144    /// Returns the height (bit position) of the largest tree in the forest.
145    ///
146    /// If the forest cannot be empty, use [`largest_tree_height_unchecked`] for performance.
147    ///
148    /// [`largest_tree_height_unchecked`]: Self::largest_tree_height_unchecked
149    pub fn largest_tree_height(self) -> Option<usize> {
150        if self.is_empty() {
151            return None;
152        }
153
154        Some(self.largest_tree_height_unchecked())
155    }
156
157    /// Returns a forest with only the largest tree present.
158    ///
159    /// # Panics
160    ///
161    /// This will panic if the forest is empty.
162    pub fn largest_tree_unchecked(self) -> Self {
163        Self::with_height(self.largest_tree_height_unchecked())
164    }
165
166    /// Returns a forest with only the largest tree present.
167    ///
168    /// If forest cannot be empty, use `largest_tree` for better performance.
169    pub fn largest_tree(self) -> Self {
170        if self.is_empty() {
171            return Self::empty();
172        }
173
174        self.largest_tree_unchecked()
175    }
176
177    /// Returns the height (bit position) of the smallest tree in the forest.
178    ///
179    /// # Panics
180    ///
181    /// This will panic if the forest is empty.
182    pub fn smallest_tree_height_unchecked(self) -> usize {
183        // Trailing_zeros is computed with the intrinsic cttz. [Rust 1.67.0] x86 uses the `bsf`
184        // instruction. AArch64 uses the `rbit clz` instructions.
185        self.0.trailing_zeros() as usize
186    }
187
188    /// Returns the height (bit position) of the smallest tree in the forest.
189    ///
190    /// If the forest cannot be empty, use [`smallest_tree_height_unchecked`] for better
191    /// performance.
192    ///
193    /// [`smallest_tree_height_unchecked`]: Self::smallest_tree_height_unchecked
194    pub fn smallest_tree_height(self) -> Option<usize> {
195        if self.is_empty() {
196            return None;
197        }
198
199        Some(self.smallest_tree_height_unchecked())
200    }
201
202    /// Returns a forest with only the smallest tree present.
203    ///
204    /// # Panics
205    ///
206    /// This will panic if the forest is empty.
207    pub fn smallest_tree_unchecked(self) -> Self {
208        Self::with_height(self.smallest_tree_height_unchecked())
209    }
210
211    /// Returns a forest with only the smallest tree present.
212    ///
213    /// If forest cannot be empty, use `smallest_tree` for performance.
214    pub fn smallest_tree(self) -> Self {
215        if self.is_empty() {
216            return Self::empty();
217        }
218        self.smallest_tree_unchecked()
219    }
220
221    /// Keeps only trees larger than the reference tree.
222    ///
223    /// For example, if we start with the bit pattern `0b0101_0110`, and keep only the trees larger
224    /// than tree index 1, that targets this bit:
225    /// ```text
226    /// Forest(0b0101_0110).trees_larger_than(1)
227    ///                        ^
228    /// Becomes:      0b0101_0100
229    ///                        ^
230    /// ```
231    /// And keeps only trees *after* that bit, meaning that the tree at `tree_idx` is also removed,
232    /// resulting in `0b0101_0100`.
233    ///
234    /// ```
235    /// # use miden_crypto::merkle::mmr::Forest;
236    /// let range = Forest::new(0b0101_0110).unwrap();
237    /// assert_eq!(range.trees_larger_than(1), Forest::new(0b0101_0100).unwrap());
238    /// ```
239    pub fn trees_larger_than(self, tree_idx: u32) -> Self {
240        let mask = high_bitmask(tree_idx + 1);
241        Self::new(self.0 & mask).expect("forest size exceeds maximum")
242    }
243
244    /// Creates a new forest with all possible trees smaller than the smallest tree in this
245    /// forest.
246    ///
247    /// This forest must have exactly one tree.
248    ///
249    /// # Panics
250    /// With debug assertions enabled, this function panics if this forest does not have
251    /// exactly one tree.
252    ///
253    /// For a non-panicking version of this function, see [`Forest::all_smaller_trees()`].
254    pub fn all_smaller_trees_unchecked(self) -> Self {
255        debug_assert_eq!(self.num_trees(), 1);
256        Self::new(self.0 - 1).expect("forest size exceeds maximum")
257    }
258
259    /// Creates a new forest with all possible trees smaller than the smallest tree in this
260    /// forest, or returns `None` if this forest has more or less than one tree.
261    ///
262    /// If the forest cannot have more or less than one tree, use
263    /// [`Forest::all_smaller_trees_unchecked()`] for performance.
264    pub fn all_smaller_trees(self) -> Option<Forest> {
265        if self.num_trees() != 1 {
266            return None;
267        }
268        Some(self.all_smaller_trees_unchecked())
269    }
270
271    /// Returns a forest with exactly one tree, one size (depth) larger than the current one.
272    ///
273    /// # Errors
274    /// Returns an error if the resulting forest would exceed [`Forest::MAX_LEAVES`].
275    pub(crate) fn next_larger_tree(self) -> Result<Self, MmrError> {
276        debug_assert_eq!(self.num_trees(), 1);
277        let value = self.0.saturating_mul(2);
278        if value > Self::MAX_LEAVES {
279            return Err(MmrError::ForestSizeExceeded { requested: value, max: Self::MAX_LEAVES });
280        }
281        Ok(Forest(value))
282    }
283
284    /// Returns true if the forest contains a single-node tree.
285    pub fn has_single_leaf_tree(self) -> bool {
286        self.0 & 1 != 0
287    }
288
289    /// Add a single-node tree if not already present in the forest.
290    pub fn with_single_leaf(self) -> Self {
291        // Setting the lowest bit cannot exceed MAX_LEAVES when MAX_LEAVES is 2^k - 1.
292        Self(self.0 | 1)
293    }
294
295    /// Remove the single-node tree if present in the forest.
296    pub fn without_single_leaf(self) -> Self {
297        // Clearing the lowest bit does not add leaves.
298        Self(self.0 & (usize::MAX - 1))
299    }
300
301    /// Returns a new forest that does not have the trees that `other` has.
302    pub fn without_trees(self, other: Forest) -> Self {
303        // Clearing bits does not add leaves.
304        Self(self.0 & !other.0)
305    }
306
307    /// Returns index of the forest tree for a specified leaf index.
308    pub fn tree_index(&self, leaf_idx: usize) -> usize {
309        let root = self
310            .leaf_to_corresponding_tree(leaf_idx)
311            .expect("position must be part of the forest");
312        let smaller_tree_mask =
313            Self::new(2_usize.pow(root) - 1).expect("forest size exceeds maximum");
314        let num_smaller_trees = (*self & smaller_tree_mask).num_trees();
315        self.num_trees() - num_smaller_trees - 1
316    }
317
318    /// Returns the smallest tree's root element as an [InOrderIndex].
319    ///
320    /// This function takes the smallest tree in this forest, "pretends" that it is a subtree of a
321    /// fully balanced binary tree, and returns the in-order index of that balanced tree's root
322    /// node.
323    ///
324    /// If the forest cannot be empty, use [`root_in_order_index_unchecked`] for performance.
325    ///
326    /// [`root_in_order_index_unchecked`]: Self::root_in_order_index_unchecked
327    pub fn root_in_order_index(&self) -> Option<InOrderIndex> {
328        if self.is_empty() {
329            return None;
330        }
331
332        Some(self.root_in_order_index_unchecked())
333    }
334
335    /// Returns the smallest tree's root element as an [InOrderIndex].
336    ///
337    /// See [`root_in_order_index`](Self::root_in_order_index) for details.
338    ///
339    /// # Panics
340    ///
341    /// This will panic if the forest is empty, which has no trees and therefore no root index.
342    pub fn root_in_order_index_unchecked(&self) -> InOrderIndex {
343        assert!(!self.is_empty(), "the empty forest has no root in-order index");
344
345        // Count total size of all trees in the forest.
346        let nodes = self.num_nodes();
347
348        // Add the count for the parent nodes that separate each tree. These are allocated but
349        // currently empty, and correspond to the nodes that will be used once the trees are merged.
350        let open_trees = self.num_trees() - 1;
351
352        // Remove the leaf-count of the rightmost subtree. The target tree root index comes before
353        // the subtree, for the in-order tree walk.
354        let right_subtree_count = self.smallest_tree_unchecked().num_leaves() - 1;
355
356        let idx = nodes + open_trees - right_subtree_count;
357
358        InOrderIndex::new(idx.try_into().unwrap())
359    }
360
361    /// Returns the in-order index of the rightmost element (the smallest tree).
362    ///
363    /// If the forest cannot be empty, use [`rightmost_in_order_index_unchecked`] for performance.
364    ///
365    /// [`rightmost_in_order_index_unchecked`]: Self::rightmost_in_order_index_unchecked
366    pub fn rightmost_in_order_index(&self) -> Option<InOrderIndex> {
367        if self.is_empty() {
368            return None;
369        }
370
371        Some(self.rightmost_in_order_index_unchecked())
372    }
373
374    /// Returns the in-order index of the rightmost element (the smallest tree).
375    ///
376    /// # Panics
377    ///
378    /// This will panic if the forest is empty, which has no elements and therefore no rightmost
379    /// index.
380    pub fn rightmost_in_order_index_unchecked(&self) -> InOrderIndex {
381        assert!(!self.is_empty(), "the empty forest has no rightmost in-order index");
382
383        // Count total size of all trees in the forest.
384        let nodes = self.num_nodes();
385
386        // Add the count for the parent nodes that separate each tree. These are allocated but
387        // currently empty, and correspond to the nodes that will be used once the trees are merged.
388        let open_trees = self.num_trees() - 1;
389
390        let idx = nodes + open_trees;
391
392        InOrderIndex::new(idx.try_into().unwrap())
393    }
394
395    /// Checks if an in-order index corresponds to a valid node in the forest.
396    ///
397    /// Returns `true` if the index points to an actual node within one of the trees,
398    /// `false` if the index is:
399    /// - Zero (invalid, as `InOrderIndex` is 1-indexed)
400    /// - Beyond the forest bounds
401    /// - A separator position between trees (these positions are reserved for future parent nodes
402    ///   when trees are merged, but don't correspond to actual nodes yet)
403    ///
404    /// # Example
405    /// For a forest with 7 leaves (0b111 = trees of 4, 2, and 1 leaves):
406    /// - Valid indices: 1-7 (first tree), 9-11 (second tree), 13 (third tree)
407    /// - Invalid separator indices: 8 (between first and second), 12 (between second and third)
408    pub fn is_valid_in_order_index(&self, idx: &InOrderIndex) -> bool {
409        // Index 0 is never valid (InOrderIndex is 1-indexed)
410        if idx.inner() == 0 {
411            return false;
412        }
413
414        // Empty forest has no valid indices
415        if self.is_empty() {
416            return false;
417        }
418
419        let idx_val = idx.inner();
420        let mut offset = 0usize;
421
422        // Iterate through trees from largest to smallest
423        for tree in TreeSizeIterator::new(*self).rev() {
424            let tree_nodes = tree.num_nodes();
425            let tree_start = offset + 1;
426            let tree_end = offset + tree_nodes;
427
428            if idx_val >= tree_start && idx_val <= tree_end {
429                return true;
430            }
431
432            // Move offset past this tree and the separator position
433            offset = tree_end + 1;
434        }
435
436        false
437    }
438
439    /// Given a leaf index in the current forest, return the tree number responsible for the
440    /// leaf.
441    ///
442    /// The result is a tree position `p`:
443    /// - `p+1` is the depth of the tree.
444    /// - Because the root element is not part of the proof, `p` is the length of the authentication
445    ///   path.
446    /// - `2^p` is equal to the number of leaves in this particular tree.
447    /// - And `2^(p+1)-1` corresponds to the size of the tree.
448    ///
449    /// For example, given a forest with 6 leaves whose forest is `0b110`:
450    /// ```text
451    ///       __ tree 2 __
452    ///      /            \
453    ///    ____          ____         _ tree 1 _
454    ///   /    \        /    \       /          \
455    ///  0      1      2      3     4            5
456    /// ```
457    ///
458    /// Leaf indices `0..=3` are in the tree at index 2 and leaf indices `4..=5` are in the tree at
459    /// index 1.
460    pub fn leaf_to_corresponding_tree(self, leaf_idx: usize) -> Option<u32> {
461        let forest = self.0;
462
463        if leaf_idx >= forest {
464            None
465        } else {
466            // - each bit in the forest is a unique tree and the bit position is its power-of-two
467            //   size
468            // - each tree is associated to a consecutive range of positions equal to its size from
469            //   left-to-right
470            // - this means the first tree owns from `0` up to the `2^k_0` first positions, where
471            //   `k_0` is the highest set bit position, the second tree from `2^k_0 + 1` up to
472            //   `2^k_1` where `k_1` is the second highest bit, so on.
473            // - this means the highest bits work as a category marker, and the position is owned by
474            //   the first tree which doesn't share a high bit with the position
475            let before = forest & leaf_idx;
476            let after = forest ^ before;
477            let tree_idx = after.ilog2();
478
479            Some(tree_idx)
480        }
481    }
482
483    /// Given a leaf index in the current forest, return the leaf index in the tree to which
484    /// the leaf belongs.
485    pub(super) fn leaf_relative_position(self, leaf_idx: usize) -> Option<usize> {
486        let tree_idx = self.leaf_to_corresponding_tree(leaf_idx)?;
487        let mask = high_bitmask(tree_idx + 1);
488        Some(leaf_idx - (self.0 & mask))
489    }
490}
491
492impl Display for Forest {
493    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
494        write!(f, "{}", self.0)
495    }
496}
497
498impl Binary for Forest {
499    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
500        write!(f, "{:b}", self.0)
501    }
502}
503
504impl BitAnd<Forest> for Forest {
505    type Output = Self;
506
507    fn bitand(self, rhs: Self) -> Self::Output {
508        Self::new(self.0 & rhs.0).expect("forest size exceeds maximum")
509    }
510}
511
512// Compile-time invariant: MAX_LEAVES must be exactly 2^k - 1.
513const _: () =
514    assert!(Forest::MAX_LEAVES != 0 && (Forest::MAX_LEAVES & (Forest::MAX_LEAVES + 1)) == 0);
515
516impl BitOr<Forest> for Forest {
517    type Output = Self;
518
519    fn bitor(self, rhs: Self) -> Self::Output {
520        Self(self.0 | rhs.0)
521    }
522}
523
524impl BitXor<Forest> for Forest {
525    type Output = Self;
526
527    fn bitxor(self, rhs: Self) -> Self::Output {
528        Self(self.0 ^ rhs.0)
529    }
530}
531
532impl BitXorAssign<Forest> for Forest {
533    fn bitxor_assign(&mut self, rhs: Self) {
534        self.0 ^= rhs.0;
535    }
536}
537
538impl TryFrom<Felt> for Forest {
539    type Error = MmrError;
540
541    fn try_from(value: Felt) -> Result<Self, Self::Error> {
542        let value = usize::try_from(value.as_canonical_u64()).map_err(|_| {
543            MmrError::ForestSizeExceeded {
544                requested: usize::MAX,
545                max: Self::MAX_LEAVES,
546            }
547        })?;
548        if value > Self::MAX_LEAVES {
549            return Err(MmrError::ForestSizeExceeded { requested: value, max: Self::MAX_LEAVES });
550        }
551        Ok(Self(value))
552    }
553}
554
555pub(crate) fn largest_tree_from_mask(mask: usize) -> Forest {
556    if mask == 0 {
557        Forest::empty()
558    } else {
559        let bit = mask.ilog2();
560        Forest::new(1usize << bit).expect("forest size exceeds maximum")
561    }
562}
563
564impl From<Forest> for Felt {
565    fn from(value: Forest) -> Self {
566        Felt::new_unchecked(value.0 as u64)
567    }
568}
569
570/// Return a bitmask for the bits including and above the given position.
571pub(crate) fn high_bitmask(bit: u32) -> usize {
572    if bit > usize::BITS - 1 { 0 } else { usize::MAX << bit }
573}
574
575// SERIALIZATION
576// ================================================================================================
577
578impl Serializable for Forest {
579    fn write_into<W: ByteWriter>(&self, target: &mut W) {
580        self.0.write_into(target);
581    }
582}
583
584impl Deserializable for Forest {
585    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
586        let value = source.read_usize()?;
587        Self::new(value)
588    }
589}
590
591// TREE SIZE ITERATOR
592// ================================================================================================
593
594/// Iterate over the trees within this `Forest`, from smallest to largest.
595///
596/// Each item is a "sub-forest", containing only one tree.
597pub struct TreeSizeIterator {
598    inner: Forest,
599}
600
601impl TreeSizeIterator {
602    pub fn new(value: Forest) -> TreeSizeIterator {
603        TreeSizeIterator { inner: value }
604    }
605}
606
607impl Iterator for TreeSizeIterator {
608    type Item = Forest;
609
610    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
611        let tree = self.inner.smallest_tree();
612
613        if tree.is_empty() {
614            None
615        } else {
616            self.inner = self.inner.without_trees(tree);
617            Some(tree)
618        }
619    }
620}
621
622impl DoubleEndedIterator for TreeSizeIterator {
623    fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
624        let tree = self.inner.largest_tree();
625
626        if tree.is_empty() {
627            None
628        } else {
629            self.inner = self.inner.without_trees(tree);
630            Some(tree)
631        }
632    }
633}
634
635// TESTS
636// ================================================================================================
637
638#[cfg(test)]
639mod tests {
640    use super::Forest;
641
642    #[test]
643    fn in_order_index_accessors_return_none_on_the_empty_forest() {
644        assert_eq!(Forest::empty().root_in_order_index(), None);
645        assert_eq!(Forest::empty().rightmost_in_order_index(), None);
646    }
647
648    #[test]
649    fn in_order_index_accessors_agree_with_unchecked_on_nonempty_forests() {
650        for leaves in [1usize, 2, 3, 7, 8] {
651            let forest = Forest::new(leaves).unwrap();
652            assert_eq!(forest.root_in_order_index(), Some(forest.root_in_order_index_unchecked()));
653            assert_eq!(
654                forest.rightmost_in_order_index(),
655                Some(forest.rightmost_in_order_index_unchecked())
656            );
657        }
658    }
659
660    #[test]
661    #[should_panic(expected = "no root in-order index")]
662    fn root_in_order_index_unchecked_panics_on_the_empty_forest() {
663        let _ = Forest::empty().root_in_order_index_unchecked();
664    }
665
666    #[test]
667    #[should_panic(expected = "no rightmost in-order index")]
668    fn rightmost_in_order_index_unchecked_panics_on_the_empty_forest() {
669        let _ = Forest::empty().rightmost_in_order_index_unchecked();
670    }
671}