1use roaring::RoaringBitmap;
13use std::collections::HashSet;
14
15pub trait Postings: Clone {
17 fn empty() -> Self;
18 fn from_sorted(ids: &[u32]) -> Self;
20 fn insert(&mut self, id: u32);
21 fn contains(&self, id: u32) -> bool;
22 fn len(&self) -> usize;
23 fn is_empty(&self) -> bool {
24 self.len() == 0
25 }
26 fn and(&self, other: &Self) -> Self;
28 fn or(&self, other: &Self) -> Self;
30 fn and_not(&self, other: &Self) -> Self;
32 fn or_inplace(&mut self, other: &Self);
34 fn to_sorted(&self) -> Vec<u32>;
36 fn native_bytes(&self) -> usize;
38
39 fn serialize_deltagap(&self) -> Vec<u8> {
41 let ids = self.to_sorted();
42 let mut out = Vec::new();
43 let mut prev: u32 = 0;
44 for id in ids {
45 let mut n = id.wrapping_sub(prev);
46 prev = id;
47 loop {
48 let b = (n & 0x7f) as u8;
49 n >>= 7;
50 if n != 0 {
51 out.push(b | 0x80);
52 } else {
53 out.push(b);
54 break;
55 }
56 }
57 }
58 out
59 }
60
61 fn deserialize_deltagap(bytes: &[u8]) -> Self
63 where
64 Self: Sized,
65 {
66 let mut ids = Vec::new();
67 let mut prev: u32 = 0;
68 let mut i = 0;
69 while i < bytes.len() {
70 let mut shift = 0u32;
71 let mut val: u32 = 0;
72 loop {
73 let b = bytes[i];
74 i += 1;
75 val |= ((b & 0x7f) as u32) << shift;
76 if b & 0x80 == 0 {
77 break;
78 }
79 shift += 7;
80 }
81 prev = prev.wrapping_add(val);
82 ids.push(prev);
83 }
84 Self::from_sorted(&ids)
85 }
86}
87
88#[derive(Clone, Default)]
91pub struct SetPostings(pub HashSet<u32>);
92
93impl Postings for SetPostings {
94 fn empty() -> Self {
95 SetPostings(HashSet::new())
96 }
97 fn from_sorted(ids: &[u32]) -> Self {
98 SetPostings(ids.iter().copied().collect())
99 }
100 fn insert(&mut self, id: u32) {
101 self.0.insert(id);
102 }
103 fn contains(&self, id: u32) -> bool {
104 self.0.contains(&id)
105 }
106 fn len(&self) -> usize {
107 self.0.len()
108 }
109 fn and(&self, other: &Self) -> Self {
110 let (small, big) = if self.0.len() <= other.0.len() {
112 (&self.0, &other.0)
113 } else {
114 (&other.0, &self.0)
115 };
116 SetPostings(small.iter().copied().filter(|id| big.contains(id)).collect())
117 }
118 fn or(&self, other: &Self) -> Self {
119 let mut out = self.0.clone();
120 out.extend(other.0.iter().copied());
121 SetPostings(out)
122 }
123 fn and_not(&self, other: &Self) -> Self {
124 SetPostings(self.0.iter().copied().filter(|id| !other.0.contains(id)).collect())
125 }
126 fn or_inplace(&mut self, other: &Self) {
127 self.0.extend(other.0.iter().copied());
128 }
129 fn to_sorted(&self) -> Vec<u32> {
130 let mut v: Vec<u32> = self.0.iter().copied().collect();
131 v.sort_unstable();
132 v
133 }
134 fn native_bytes(&self) -> usize {
135 let cap = (self.0.len() as f64 / 0.875).ceil() as usize;
137 cap * 5
138 }
139}
140
141#[derive(Clone, Default, Debug)]
144pub struct RoarPostings(pub RoaringBitmap);
145
146impl Postings for RoarPostings {
147 fn empty() -> Self {
148 RoarPostings(RoaringBitmap::new())
149 }
150 fn from_sorted(ids: &[u32]) -> Self {
151 match RoaringBitmap::from_sorted_iter(ids.iter().copied()) {
153 Ok(b) => RoarPostings(b),
154 Err(_) => {
155 let mut b = RoaringBitmap::new();
156 b.extend(ids.iter().copied());
157 RoarPostings(b)
158 }
159 }
160 }
161 fn insert(&mut self, id: u32) {
162 self.0.insert(id);
163 }
164 fn contains(&self, id: u32) -> bool {
165 self.0.contains(id)
166 }
167 fn len(&self) -> usize {
168 self.0.len() as usize
169 }
170 fn and(&self, other: &Self) -> Self {
171 RoarPostings(&self.0 & &other.0)
172 }
173 fn or(&self, other: &Self) -> Self {
174 RoarPostings(&self.0 | &other.0)
175 }
176 fn and_not(&self, other: &Self) -> Self {
177 RoarPostings(&self.0 - &other.0)
178 }
179 fn or_inplace(&mut self, other: &Self) {
180 self.0 |= &other.0;
181 }
182 fn to_sorted(&self) -> Vec<u32> {
183 self.0.iter().collect()
184 }
185 fn native_bytes(&self) -> usize {
186 self.0.serialized_size()
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 fn roundtrip<B: Postings>() {
195 let ids = [0u32, 1, 2, 5, 300, 70000, 70001, 1_000_000];
196 let b = B::from_sorted(&ids);
197 let bytes = b.serialize_deltagap();
198 let back = B::deserialize_deltagap(&bytes);
199 assert_eq!(back.to_sorted(), ids.to_vec());
200 }
201
202 #[test]
203 fn deltagap_roundtrip_both_backends() {
204 roundtrip::<SetPostings>();
205 roundtrip::<RoarPostings>();
206 }
207
208 #[test]
209 fn set_algebra_parity() {
210 let a_ids = [1u32, 2, 3, 4, 5, 100, 200];
211 let b_ids = [3u32, 4, 5, 6, 200, 300];
212 let (sa, sb) = (SetPostings::from_sorted(&a_ids), SetPostings::from_sorted(&b_ids));
213 let (ra, rb) = (RoarPostings::from_sorted(&a_ids), RoarPostings::from_sorted(&b_ids));
214 assert_eq!(sa.and(&sb).to_sorted(), ra.and(&rb).to_sorted());
215 assert_eq!(sa.or(&sb).to_sorted(), ra.or(&rb).to_sorted());
216 assert_eq!(sa.and_not(&sb).to_sorted(), ra.and_not(&rb).to_sorted());
217 }
218}