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