1#[cfg(not(feature = "std"))]
10use crate::nostd_prelude::*;
11use crate::seg_map::{HS_PROMOTE, SegMap};
12use crate::small_set::{AddResult, SmallSetData, promote};
13use crate::value::{SetData, SmallBytes, Value, set_member_weight};
14use crate::{Entry, Store, StoreError};
15use alloc::sync::Arc;
16
17impl Store {
18 fn set_value_mut(
23 &mut self,
24 key: &[u8],
25 ) -> Result<Option<&mut Value>, StoreError> {
26 match self.live_entry_mut(key) {
27 None => Ok(None),
28 Some(e) => match &e.value {
29 Value::Set(_) | Value::SegSet(_) | Value::SmallSetInline(_) => {
30 Ok(Some(&mut e.value))
31 }
32 _ => Err(StoreError::WrongType),
33 },
34 }
35 }
36
37 fn drop_if_empty_set(&mut self, key: &[u8]) {
38 let empty = match self.map.get(key).map(|e| &e.value) {
39 Some(Value::Set(s)) => s.is_empty(),
40 Some(Value::SegSet(s)) => s.is_empty(),
41 Some(Value::SmallSetInline(s)) => s.is_empty(),
42 _ => false,
43 };
44 if empty {
45 self.remove_entry(key);
46 }
47 }
48
49 pub fn sadd(
51 &mut self,
52 key: &[u8],
53 members: &[&[u8]],
54 ) -> Result<usize, StoreError> {
55 if members.is_empty() {
56 return Ok(0);
57 }
58 let mut added = 0usize;
59 let mut delta: i64 = 0;
60 for m in members {
61 match self.sadd_one(key, m)? {
62 SaddOutcome::AddedInline => added += 1,
63 SaddOutcome::AddedHeap(w) => {
64 added += 1;
65 delta += w;
66 }
67 SaddOutcome::AlreadyPresent => {}
68 }
69 }
70 self.account_delta(key, delta);
71 Ok(added)
72 }
73
74 fn sadd_one(&mut self, key: &[u8], m: &[u8]) -> Result<SaddOutcome, StoreError> {
76 if self.set_value_mut(key)?.is_none() {
77 return Ok(self.sadd_create(key, m));
78 }
79 let v = self.set_value_mut(key)?.expect("present and a set type");
80 match v {
81 Value::SmallSetInline(s) => match s.try_add(m) {
82 AddResult::Added => Ok(SaddOutcome::AddedInline),
83 AddResult::AlreadyPresent => Ok(SaddOutcome::AlreadyPresent),
84 AddResult::NoRoom => {
85 let outcome = promote_inline_set_and_add(v, m);
86 self.reweigh_entry(key);
87 Ok(outcome)
88 }
89 },
90 Value::Set(s) if s.len() >= HS_PROMOTE => {
93 let added = promote_flat_set_to_seg(v, m);
94 self.reweigh_entry(key);
95 if added {
97 Ok(SaddOutcome::AddedHeap(0))
98 } else {
99 Ok(SaddOutcome::AlreadyPresent)
100 }
101 }
102 Value::Set(s) => {
103 let smb = SmallBytes::from_slice(m);
104 let w = set_member_weight(&smb) as i64;
105 if Arc::make_mut(s).insert(smb) {
106 Ok(SaddOutcome::AddedHeap(w))
107 } else {
108 Ok(SaddOutcome::AlreadyPresent)
109 }
110 }
111 Value::SegSet(s) => {
112 let smb = SmallBytes::from_slice(m);
113 let w = set_member_weight(&smb) as i64;
114 if Arc::make_mut(s).insert(smb, ()).is_none() {
115 Ok(SaddOutcome::AddedHeap(w))
116 } else {
117 Ok(SaddOutcome::AlreadyPresent)
118 }
119 }
120 _ => Err(StoreError::WrongType),
121 }
122 }
123
124 fn sadd_create(&mut self, key: &[u8], m: &[u8]) -> SaddOutcome {
126 if let Some(inline) = SmallSetData::with_one(m) {
127 self.insert_entry(
128 SmallBytes::from_slice(key),
129 Entry::new(Value::SmallSetInline(inline), None),
130 );
131 } else {
132 let smb = SmallBytes::from_slice(m);
133 let mut s = SetData::with_capacity(1);
134 s.insert(smb);
135 self.insert_entry(
136 SmallBytes::from_slice(key),
137 Entry::new(Value::Set(Arc::new(s)), None),
138 );
139 }
140 SaddOutcome::AddedInline
141 }
142
143 pub fn srem(
145 &mut self,
146 key: &[u8],
147 members: &[&[u8]],
148 ) -> Result<usize, StoreError> {
149 let (removed, delta) = {
150 let mut r = 0usize;
151 let mut d: i64 = 0;
152 if let Some(v) = self.set_value_mut(key)? {
153 match v {
154 Value::SmallSetInline(s) => {
155 for m in members {
156 if s.try_remove(m) {
157 r += 1;
158 }
159 }
160 }
161 Value::Set(s) => {
162 let set_mut = Arc::make_mut(s);
163 for m in members {
164 if set_mut.remove(*m) {
165 r += 1;
166 d -= set_member_weight(&SmallBytes::from_slice(m)) as i64;
167 }
168 }
169 }
170 Value::SegSet(s) => {
171 let set_mut = Arc::make_mut(s);
172 for m in members {
173 if set_mut.remove(m).is_some() {
174 r += 1;
175 d -= set_member_weight(&SmallBytes::from_slice(m)) as i64;
176 }
177 }
178 }
179 _ => return Err(StoreError::WrongType),
180 }
181 }
182 (r, d)
183 };
184 self.account_delta(key, delta);
185 self.drop_if_empty_set(key);
186 Ok(removed)
187 }
188
189 pub fn spop(&mut self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>, StoreError> {
194 let mut draws: Vec<u64> = (0..count).map(|_| self.rng.next_u64()).collect();
195 let (out, delta) = {
196 let mut o: Vec<Vec<u8>> = Vec::new();
197 let mut d: i64 = 0;
198 if let Some(v) = self.set_value_mut(key)? {
199 match v {
200 Value::SmallSetInline(s) => {
201 let mut all: Vec<Vec<u8>> = s.iter_slices().map(<[u8]>::to_vec).collect();
202 let k = shuffle_prefix(&mut all, count, &mut draws);
203 all.truncate(k);
204 for m in &all {
205 s.try_remove(m.as_slice());
206 }
207 o = all;
208 }
209 Value::Set(s) => {
210 (o, d) = flat_spop_draws(Arc::make_mut(s), &draws, count);
211 }
212 Value::SegSet(s) => {
213 (o, d) = seg_spop_draws(Arc::make_mut(s), &draws, count);
214 }
215 _ => return Err(StoreError::WrongType),
216 }
217 }
218 (o, d)
219 };
220 self.account_delta(key, delta);
221 self.drop_if_empty_set(key);
222 Ok(out)
223 }
224}
225
226
227fn promote_inline_set_and_add(v: &mut Value, m: &[u8]) -> SaddOutcome {
230 let Value::SmallSetInline(s) = v else { unreachable!("matched inline") };
231 let mut promoted = promote(s);
232 let smb = SmallBytes::from_slice(m);
233 let w = set_member_weight(&smb) as i64;
234 let inserted = promoted.insert(smb);
235 debug_assert!(inserted, "promote re-inserts existing inline");
236 *v = Value::Set(Arc::new(promoted));
237 if inserted {
238 SaddOutcome::AddedHeap(w)
239 } else {
240 SaddOutcome::AlreadyPresent
241 }
242}
243
244fn promote_flat_set_to_seg(v: &mut Value, m: &[u8]) -> bool {
247 let Value::Set(s) = v else { unreachable!("matched Set") };
248 let flat = Arc::try_unwrap(core::mem::take(s)).unwrap_or_else(|a| (*a).clone());
249 let mut seg: SegMap<()> = SegMap::default();
250 for member in flat.iter() {
251 seg.insert(member.clone(), ());
252 }
253 let added = seg.insert(SmallBytes::from_slice(m), ()).is_none();
254 *v = Value::SegSet(Arc::new(seg));
255 added
256}
257
258fn flat_spop_draws(set_mut: &mut SetData, draws: &[u64], count: usize) -> (Vec<Vec<u8>>, i64) {
260 let (mut o, mut d) = (Vec::new(), 0i64);
261 for slot in draws.iter().take(count) {
262 if set_mut.is_empty() {
263 break;
264 }
265 let Some(m) = set_mut
266 .iter_from_slot(*slot as usize)
267 .next()
268 .map(kevy_bytes::SmallBytes::to_vec)
269 else {
270 break;
271 };
272 if set_mut.remove(m.as_slice()) {
273 d -= set_member_weight(&SmallBytes::from_slice(&m)) as i64;
274 }
275 o.push(m);
276 }
277 (o, d)
278}
279
280fn seg_spop_draws(set_mut: &mut SegMap<()>, draws: &[u64], count: usize) -> (Vec<Vec<u8>>, i64) {
282 let (mut o, mut d) = (Vec::new(), 0i64);
283 for draw in draws.iter().take(count) {
284 if set_mut.is_empty() {
285 break;
286 }
287 let Some(m) = set_mut.rand_entry(*draw).map(|(m, ())| m.to_vec()) else {
288 break;
289 };
290 if set_mut.remove(m.as_slice()).is_some() {
291 d -= set_member_weight(&SmallBytes::from_slice(&m)) as i64;
292 }
293 o.push(m);
294 }
295 (o, d)
296}
297
298enum SaddOutcome {
300 AddedInline,
301 AddedHeap(i64),
302 AlreadyPresent,
303}
304
305pub(crate) fn shuffle_prefix<T>(items: &mut [T], k: usize, draws: &mut Vec<u64>) -> usize {
309 let n = items.len();
310 let k = k.min(n);
311 for i in 0..k {
312 let span = (n - i) as u64;
313 let d = draws.pop().unwrap_or(i as u64);
314 items.swap(i, i + crate::rng::below(d, span) as usize);
315 }
316 k
317}