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}