Skip to main content

lb_tantivy/
docset.rs

1use std::borrow::{Borrow, BorrowMut};
2
3use crate::fastfield::AliveBitSet;
4use crate::DocId;
5
6/// Sentinel value returned when a [`DocSet`] has been entirely consumed.
7///
8/// This is not `u32::MAX` as one would have expected, due to the lack of SSE2 instructions
9/// to compare `[u32; 4]`.
10pub const TERMINATED: DocId = i32::MAX as u32;
11
12/// The collect_block method on `SegmentCollector` uses a buffer of this size.
13/// Passed results to `collect_block` will not exceed this size and will be
14/// exactly this size as long as we can fill the buffer.
15pub const COLLECT_BLOCK_BUFFER_LEN: usize = 64;
16
17/// Represents an iterable set of sorted doc ids.
18pub trait DocSet: Send {
19    /// Goes to the next element.
20    ///
21    /// The DocId of the next element is returned.
22    /// In other words we should always have :
23    /// ```compile_fail
24    /// let doc = docset.advance();
25    /// assert_eq!(doc, docset.doc());
26    /// ```
27    ///
28    /// If we reached the end of the `DocSet`, [`TERMINATED`] should be returned.
29    ///
30    /// Calling `.advance()` on a terminated `DocSet` should be supported, and [`TERMINATED`] should
31    /// be returned.
32    fn advance(&mut self) -> DocId;
33
34    /// Advances the `DocSet` forward until reaching the target, or going to the
35    /// lowest [`DocId`] greater than the target.
36    ///
37    /// If the end of the `DocSet` is reached, [`TERMINATED`] is returned.
38    ///
39    /// Calling `.seek(target)` on a terminated `DocSet` is legal. Implementation
40    /// of `DocSet` should support it.
41    ///
42    /// Calling `seek(TERMINATED)` is also legal and is the normal way to consume a `DocSet`.
43    fn seek(&mut self, target: DocId) -> DocId {
44        let mut doc = self.doc();
45        debug_assert!(doc <= target);
46        while doc < target {
47            doc = self.advance();
48        }
49        doc
50    }
51
52    /// Fills a given mutable buffer with the next doc ids from the
53    /// `DocSet`
54    ///
55    /// If that many `DocId`s are available, the method should
56    /// fill the entire buffer and return the length of the buffer.
57    ///
58    /// If we reach the end of the `DocSet` before filling
59    /// it entirely, then the buffer is filled up to this point, and
60    /// return value is the number of elements that were filled.
61    ///
62    /// # Warning
63    ///
64    /// This method is only here for specific high-performance
65    /// use case where batching. The normal way to
66    /// go through the `DocId`'s is to call `.advance()`.
67    fn fill_buffer(&mut self, buffer: &mut [DocId; COLLECT_BLOCK_BUFFER_LEN]) -> usize {
68        if self.doc() == TERMINATED {
69            return 0;
70        }
71        for (i, buffer_val) in buffer.iter_mut().enumerate() {
72            *buffer_val = self.doc();
73            if self.advance() == TERMINATED {
74                return i + 1;
75            }
76        }
77        buffer.len()
78    }
79
80    /// Returns the current document
81    /// Right after creating a new `DocSet`, the docset points to the first document.
82    ///
83    /// If the `DocSet` is empty, `.doc()` should return [`TERMINATED`].
84    fn doc(&self) -> DocId;
85
86    /// Returns a best-effort hint of the
87    /// length of the docset.
88    fn size_hint(&self) -> u32;
89
90    /// Returns the number documents matching.
91    /// Calling this method consumes the `DocSet`.
92    fn count(&mut self, alive_bitset: &AliveBitSet) -> u32 {
93        let mut count = 0u32;
94        let mut doc = self.doc();
95        while doc != TERMINATED {
96            if alive_bitset.is_alive(doc) {
97                count += 1u32;
98            }
99            doc = self.advance();
100        }
101        count
102    }
103
104    /// Returns the count of documents, deleted or not.
105    /// Calling this method consumes the `DocSet`.
106    ///
107    /// Of course, the result is an upper bound of the result
108    /// given by `count()`.
109    fn count_including_deleted(&mut self) -> u32 {
110        let mut count = 0u32;
111        let mut doc = self.doc();
112        while doc != TERMINATED {
113            count += 1u32;
114            doc = self.advance();
115        }
116        count
117    }
118}
119
120impl DocSet for &mut dyn DocSet {
121    fn advance(&mut self) -> u32 {
122        (**self).advance()
123    }
124
125    fn seek(&mut self, target: DocId) -> DocId {
126        (**self).seek(target)
127    }
128
129    fn doc(&self) -> u32 {
130        (**self).doc()
131    }
132
133    fn size_hint(&self) -> u32 {
134        (**self).size_hint()
135    }
136
137    fn count(&mut self, alive_bitset: &AliveBitSet) -> u32 {
138        (**self).count(alive_bitset)
139    }
140
141    fn count_including_deleted(&mut self) -> u32 {
142        (**self).count_including_deleted()
143    }
144}
145
146impl<TDocSet: DocSet + ?Sized> DocSet for Box<TDocSet> {
147    fn advance(&mut self) -> DocId {
148        let unboxed: &mut TDocSet = self.borrow_mut();
149        unboxed.advance()
150    }
151
152    fn seek(&mut self, target: DocId) -> DocId {
153        let unboxed: &mut TDocSet = self.borrow_mut();
154        unboxed.seek(target)
155    }
156
157    fn fill_buffer(&mut self, buffer: &mut [DocId; COLLECT_BLOCK_BUFFER_LEN]) -> usize {
158        let unboxed: &mut TDocSet = self.borrow_mut();
159        unboxed.fill_buffer(buffer)
160    }
161
162    fn doc(&self) -> DocId {
163        let unboxed: &TDocSet = self.borrow();
164        unboxed.doc()
165    }
166
167    fn size_hint(&self) -> u32 {
168        let unboxed: &TDocSet = self.borrow();
169        unboxed.size_hint()
170    }
171
172    fn count(&mut self, alive_bitset: &AliveBitSet) -> u32 {
173        let unboxed: &mut TDocSet = self.borrow_mut();
174        unboxed.count(alive_bitset)
175    }
176
177    fn count_including_deleted(&mut self) -> u32 {
178        let unboxed: &mut TDocSet = self.borrow_mut();
179        unboxed.count_including_deleted()
180    }
181}