Coverage Report

Created: 2026-11-03 08:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/papaya-0.2.4/src/raw/mod.rs
Line
Count
Source
1
mod alloc;
2
mod probe;
3
4
pub(crate) mod utils;
5
6
use std::hash::{BuildHasher, Hash};
7
use std::mem::MaybeUninit;
8
use std::sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize, Ordering};
9
use std::sync::Mutex;
10
use std::{hint, panic, ptr};
11
12
use self::alloc::{RawTable, Table};
13
use self::probe::Probe;
14
15
#[allow(unused_imports)] // Contains polyfills for APIs that stabilized after MSRV.
16
use self::utils::{untagged, AtomicPtrFetchOps, Counter, Parker, StrictProvenance, Tagged};
17
18
use crate::map::{Compute, Operation, ResizeMode};
19
use crate::Equivalent;
20
21
use seize::{Collector, LocalGuard, OwnedGuard};
22
use utils::{MapGuard, Stack, VerifiedGuard};
23
24
/// A lock-free hash-table.
25
pub struct HashMap<K, V, S> {
26
    /// A pointer to the root table.
27
    table: AtomicPtr<RawTable<Entry<K, V>>>,
28
29
    /// Collector for memory reclamation.
30
    collector: Collector,
31
32
    /// The resize mode, either blocking or incremental.
33
    resize: ResizeMode,
34
35
    /// An atomic counter of the number of keys in the table.
36
    count: Counter,
37
38
    /// The initial capacity provided to `HashMap::new`.
39
    ///
40
    /// The table is guaranteed to never shrink below this capacity.
41
    initial_capacity: usize,
42
43
    /// Hasher for keys.
44
    pub hasher: S,
45
}
46
47
/// Resize state for the hash-table.
48
pub struct State<T> {
49
    /// The next table used for resizing.
50
    pub next: AtomicPtr<RawTable<T>>,
51
52
    /// A lock acquired to allocate the next table.
53
    pub allocating: Mutex<()>,
54
55
    /// The number of entries that have been copied to the next table.
56
    pub copied: AtomicUsize,
57
58
    /// The number of entries that have been claimed by copiers,
59
    /// but not necessarily copied.
60
    pub claim: AtomicUsize,
61
62
    /// The status of the resize.
63
    pub status: AtomicU8,
64
65
    /// A thread parker for blocking on copy operations.
66
    pub parker: Parker,
67
68
    /// Entries whose retirement has been deferred by later tables.
69
    pub deferred: Stack<*mut T>,
70
}
71
72
impl<T> Default for State<T> {
73
0
    fn default() -> State<T> {
74
0
        State {
75
0
            next: AtomicPtr::new(ptr::null_mut()),
76
0
            allocating: Mutex::new(()),
77
0
            copied: AtomicUsize::new(0),
78
0
            claim: AtomicUsize::new(0),
79
0
            status: AtomicU8::new(State::PENDING),
80
0
            parker: Parker::default(),
81
0
            deferred: Stack::new(),
82
0
        }
83
0
    }
Unexecuted instantiation: <papaya::raw::State<papaya::raw::Entry<bytes::bytes::Bytes, ()>> as core::default::Default>::default
Unexecuted instantiation: <papaya::raw::State<_> as core::default::Default>::default
84
}
85
86
impl State<()> {
87
    /// A resize is in-progress.
88
    pub const PENDING: u8 = 0;
89
90
    /// The resize has been aborted, continue to the next table.
91
    pub const ABORTED: u8 = 1;
92
93
    /// The resize was complete and the table was promoted.
94
    pub const PROMOTED: u8 = 2;
95
}
96
97
// The result of an insert operation.
98
pub enum InsertResult<'g, V> {
99
    /// Inserted the given value.
100
    Inserted(&'g V),
101
102
    /// Replaced the given value.
103
    Replaced(&'g V),
104
105
    /// Error returned by `try_insert`.
106
    Error { current: &'g V, not_inserted: V },
107
}
108
109
// The raw result of an insert operation.
110
pub enum RawInsertResult<'g, K, V> {
111
    /// Inserted the given value.
112
    Inserted(&'g V),
113
114
    /// Replaced the given value.
115
    Replaced(&'g V),
116
117
    /// Error returned by `try_insert`.
118
    Error {
119
        current: &'g V,
120
        not_inserted: *mut Entry<K, V>,
121
    },
122
}
123
124
// An entry in the hash-table.
125
#[repr(C, align(8))] // Reserve the lower 3 bits for pointer tagging.
126
pub struct Entry<K, V> {
127
    /// The key for this entry.
128
    pub key: K,
129
130
    /// The value for this entry.
131
    pub value: V,
132
}
133
134
impl Entry<(), ()> {
135
    /// The entry is being copied to the new table, no updates are allowed on the old table.
136
    ///
137
    /// This bit is put down to initiate a copy, forcing all writers to complete the resize
138
    /// before making progress.
139
    const COPYING: usize = 0b001;
140
141
    /// The entry has been copied to the new table.
142
    ///
143
    /// This bit is put down after a copy completes. Both readers and writers must go to
144
    /// the new table to see the new state of the entry.
145
    ///
146
    /// In blocking mode this is unused.
147
    const COPIED: usize = 0b010;
148
149
    /// The entry was copied from a previous table.
150
    ///
151
    /// This bit indicates that an entry may still be accessible from previous tables
152
    /// because the resize is still in progress, and so it is unsafe to reclaim.
153
    ///
154
    /// In blocking mode this is unused.
155
    const BORROWED: usize = 0b100;
156
}
157
158
impl<K, V> utils::Unpack for Entry<K, V> {
159
    /// Mask for an entry pointer, ignoring any tag bits.
160
    const MASK: usize = !(Entry::COPYING | Entry::COPIED | Entry::BORROWED);
161
}
162
163
impl<K, V> Entry<K, V> {
164
    /// A sentinel pointer for a deleted entry.
165
    ///
166
    /// Null pointers are never copied to the new table, so this state is safe to use.
167
    /// Note that tombstone entries may still be marked as `COPYING`, so this state
168
    /// cannot be used for direct equality.
169
    const TOMBSTONE: *mut Entry<K, V> = Entry::COPIED as _;
170
}
171
172
/// The status of an entry.
173
enum EntryStatus<K, V> {
174
    /// The entry is a tombstone or null (potentially a null copy).
175
    Null,
176
177
    /// The entry is being copied.
178
    Copied(Tagged<Entry<K, V>>),
179
180
    /// A valid entry.
181
    Value(Tagged<Entry<K, V>>),
182
}
183
184
impl<K, V> From<Tagged<Entry<K, V>>> for EntryStatus<K, V> {
185
    /// Returns the status for this entry.
186
    #[inline]
187
0
    fn from(entry: Tagged<Entry<K, V>>) -> Self {
188
0
        if entry.ptr.is_null() {
189
0
            EntryStatus::Null
190
0
        } else if entry.tag() & Entry::COPYING != 0 {
191
0
            EntryStatus::Copied(entry)
192
        } else {
193
0
            EntryStatus::Value(entry)
194
        }
195
0
    }
Unexecuted instantiation: <papaya::raw::EntryStatus<bytes::bytes::Bytes, ()> as core::convert::From<papaya::raw::utils::tagged::Tagged<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>>::from
Unexecuted instantiation: <papaya::raw::EntryStatus<_, _> as core::convert::From<papaya::raw::utils::tagged::Tagged<papaya::raw::Entry<_, _>>>>::from
196
}
197
198
/// The state of an entry we attempted to update.
199
enum UpdateStatus<K, V> {
200
    /// Successfully replaced the given key and value.
201
    Replaced(Tagged<Entry<K, V>>),
202
203
    /// A new entry was written before we could update.
204
    Found(EntryStatus<K, V>),
205
}
206
207
/// The state of an entry we attempted to insert into.
208
enum InsertStatus<K, V> {
209
    /// Successfully inserted the value.
210
    Inserted,
211
212
    /// A new entry was written before we could update.
213
    Found(EntryStatus<K, V>),
214
}
215
216
impl<K, V, S> HashMap<K, V, S> {
217
    /// Creates new hash-table with the given options.
218
    #[inline]
219
24.9k
    pub fn new(
220
24.9k
        capacity: usize,
221
24.9k
        hasher: S,
222
24.9k
        collector: Collector,
223
24.9k
        resize: ResizeMode,
224
24.9k
    ) -> HashMap<K, V, S> {
225
        // The table is lazily allocated.
226
24.9k
        if capacity == 0 {
227
24.9k
            return HashMap {
228
24.9k
                collector,
229
24.9k
                resize,
230
24.9k
                hasher,
231
24.9k
                initial_capacity: 1,
232
24.9k
                table: AtomicPtr::new(ptr::null_mut()),
233
24.9k
                count: Counter::default(),
234
24.9k
            };
235
0
        }
236
237
0
        let capacity = probe::entries_for(capacity);
238
239
        // Initialize the table and mark it as the root.
240
0
        let mut table = Table::alloc(capacity);
241
0
        *table.state_mut().status.get_mut() = State::PROMOTED;
242
243
0
        HashMap {
244
0
            hasher,
245
0
            resize,
246
0
            collector,
247
0
            initial_capacity: capacity,
248
0
            table: AtomicPtr::new(table.raw),
249
0
            count: Counter::default(),
250
0
        }
251
24.9k
    }
<papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::new
Line
Count
Source
219
24.9k
    pub fn new(
220
24.9k
        capacity: usize,
221
24.9k
        hasher: S,
222
24.9k
        collector: Collector,
223
24.9k
        resize: ResizeMode,
224
24.9k
    ) -> HashMap<K, V, S> {
225
        // The table is lazily allocated.
226
24.9k
        if capacity == 0 {
227
24.9k
            return HashMap {
228
24.9k
                collector,
229
24.9k
                resize,
230
24.9k
                hasher,
231
24.9k
                initial_capacity: 1,
232
24.9k
                table: AtomicPtr::new(ptr::null_mut()),
233
24.9k
                count: Counter::default(),
234
24.9k
            };
235
0
        }
236
237
0
        let capacity = probe::entries_for(capacity);
238
239
        // Initialize the table and mark it as the root.
240
0
        let mut table = Table::alloc(capacity);
241
0
        *table.state_mut().status.get_mut() = State::PROMOTED;
242
243
0
        HashMap {
244
0
            hasher,
245
0
            resize,
246
0
            collector,
247
0
            initial_capacity: capacity,
248
0
            table: AtomicPtr::new(table.raw),
249
0
            count: Counter::default(),
250
0
        }
251
24.9k
    }
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::new
252
253
    /// Returns a guard for this collector
254
538k
    pub fn guard(&self) -> MapGuard<LocalGuard<'_>> {
255
        // Safety: Created the guard from our collector.
256
538k
        unsafe { MapGuard::new(self.collector().enter()) }
257
538k
    }
<papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::guard
Line
Count
Source
254
538k
    pub fn guard(&self) -> MapGuard<LocalGuard<'_>> {
255
        // Safety: Created the guard from our collector.
256
538k
        unsafe { MapGuard::new(self.collector().enter()) }
257
538k
    }
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::guard
258
259
    /// Returns an owned guard for this collector
260
0
    pub fn owned_guard(&self) -> MapGuard<OwnedGuard<'_>> {
261
        // Safety: Created the guard from our collector.
262
0
        unsafe { MapGuard::new(self.collector().enter_owned()) }
263
0
    }
264
265
    /// Verify a guard is valid to use with this map.
266
    #[inline]
267
0
    pub fn verify<'g, G>(&self, guard: &'g G) -> &'g MapGuard<G>
268
0
    where
269
0
        G: seize::Guard,
270
    {
271
0
        assert_eq!(
272
0
            *guard.collector(),
273
            self.collector,
274
            "Attempted to access map with incorrect guard"
275
        );
276
277
        // Safety: Verified the guard above.
278
0
        unsafe { MapGuard::from_ref(guard) }
279
0
    }
280
281
    /// Returns a reference to the root hash-table.
282
    #[inline]
283
538k
    fn root(&self, guard: &impl VerifiedGuard) -> Table<Entry<K, V>> {
284
        // Load the root table.
285
538k
        let raw = guard.protect(&self.table, Ordering::Acquire);
286
287
        // Safety: The root table is either null or a valid table allocation.
288
538k
        unsafe { Table::from_raw(raw) }
289
538k
    }
<papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::root::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Line
Count
Source
283
538k
    fn root(&self, guard: &impl VerifiedGuard) -> Table<Entry<K, V>> {
284
        // Load the root table.
285
538k
        let raw = guard.protect(&self.table, Ordering::Acquire);
286
287
        // Safety: The root table is either null or a valid table allocation.
288
538k
        unsafe { Table::from_raw(raw) }
289
538k
    }
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::root::<_>
290
291
    /// Returns a reference to the collector.
292
    #[inline]
293
538k
    pub fn collector(&self) -> &Collector {
294
538k
        &self.collector
295
538k
    }
<papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::collector
Line
Count
Source
293
538k
    pub fn collector(&self) -> &Collector {
294
538k
        &self.collector
295
538k
    }
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::collector
296
297
    /// Returns the number of entries in the table.
298
    #[inline]
299
0
    pub fn len(&self) -> usize {
300
0
        self.count.sum()
301
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::len
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::len
302
303
    /// Returns true if incremental resizing is enabled.
304
    #[inline]
305
0
    fn is_incremental(&self) -> bool {
306
0
        matches!(self.resize, ResizeMode::Incremental(_))
307
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::is_incremental
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::is_incremental
308
}
309
310
impl<K, V, S> HashMap<K, V, S>
311
where
312
    K: Hash + Eq,
313
    S: BuildHasher,
314
{
315
    /// Returns a reference to the entry corresponding to the key.
316
    #[inline]
317
0
    pub fn get<'g, Q>(&self, key: &Q, guard: &'g impl VerifiedGuard) -> Option<(&'g K, &'g V)>
318
0
    where
319
0
        Q: Equivalent<K> + Hash + ?Sized,
320
    {
321
        // Load the root table.
322
0
        let mut table = self.root(guard);
323
324
        // The table has not been initialized yet.
325
0
        if table.raw.is_null() {
326
0
            return None;
327
0
        }
328
329
0
        let (h1, h2) = self.hash(key);
330
331
        loop {
332
            // Initialize the probe state.
333
0
            let mut probe = Probe::start(h1, table.mask);
334
335
            // Probe until we reach the limit.
336
0
            'probe: while probe.len <= table.limit {
337
                // Load the entry metadata first for cheap searches.
338
                //
339
                // Safety: `probe.i` is always in-bounds for the table length.
340
0
                let meta = unsafe { table.meta(probe.i) }.load(Ordering::Acquire);
341
342
0
                if meta == h2 {
343
                    // Load the full entry.
344
                    //
345
                    // Safety: `probe.i` is always in-bounds for the table length.
346
0
                    let entry = guard
347
0
                        .protect(unsafe { table.entry(probe.i) }, Ordering::Acquire)
348
0
                        .unpack();
349
350
                    // The entry was deleted, keep probing.
351
0
                    if entry.ptr.is_null() {
352
0
                        probe.next(table.mask);
353
0
                        continue 'probe;
354
0
                    }
355
356
                    // Safety: We performed a protected load of the pointer using a verified guard with
357
                    // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
358
                    // as we hold the guard.
359
0
                    let entry_ref = unsafe { &(*entry.ptr) };
360
361
                    // Check for a full match.
362
0
                    if key.equivalent(&entry_ref.key) {
363
                        // The entry was copied to the new table.
364
                        //
365
                        // In blocking resize mode we do not need to perform self check as all writes block
366
                        // until any resizes are complete, making the root table the source of truth for readers.
367
0
                        if entry.tag() & Entry::COPIED != 0 {
368
0
                            break 'probe;
369
0
                        }
370
371
                        // Found the correct entry, return the key and value.
372
0
                        return Some((&entry_ref.key, &entry_ref.value));
373
0
                    }
374
0
                }
375
376
                // The key is not in the table.
377
                //
378
                // It also cannot be in the next table because we have not went over the probe limit.
379
0
                if meta == meta::EMPTY {
380
0
                    return None;
381
0
                }
382
383
0
                probe.next(table.mask);
384
            }
385
386
            // In incremental resize mode, we have to check the next table if we found
387
            // a copied entry or went over the probe limit.
388
0
            if self.is_incremental() {
389
0
                if let Some(next) = table.next_table() {
390
0
                    table = next;
391
0
                    continue;
392
0
                }
393
0
            }
394
395
            // Otherwise, the key is not in the table.
396
0
            return None;
397
        }
398
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::get::<[u8], papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::get::<bytes::bytes::Bytes, papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::get::<_, _>
399
400
    /// Inserts a key-value pair into the table.
401
    #[inline]
402
0
    pub fn insert<'g>(
403
0
        &self,
404
0
        key: K,
405
0
        value: V,
406
0
        replace: bool,
407
0
        guard: &'g impl VerifiedGuard,
408
0
    ) -> InsertResult<'g, V> {
409
        // Perform the insert.
410
0
        let raw_result = self.insert_inner(key, value, replace, guard);
411
412
0
        let result = match raw_result {
413
            // Updated an entry.
414
0
            RawInsertResult::Replaced(value) => InsertResult::Replaced(value),
415
416
            // Inserted a new entry.
417
0
            RawInsertResult::Inserted(value) => {
418
                // Increment the table length.
419
0
                self.count.get(guard).fetch_add(1, Ordering::Relaxed);
420
421
0
                InsertResult::Inserted(value)
422
            }
423
424
            // Failed to insert the entry.
425
            RawInsertResult::Error {
426
0
                current,
427
0
                not_inserted,
428
            } => {
429
                // Safety: We allocated this box above and it was not inserted into the table.
430
0
                let not_inserted = unsafe { Box::from_raw(not_inserted) };
431
432
0
                InsertResult::Error {
433
0
                    current,
434
0
                    not_inserted: not_inserted.value,
435
0
                }
436
            }
437
        };
438
439
0
        result
440
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::insert::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::insert::<_>
441
442
    /// Inserts an entry into the map.
443
    #[inline]
444
0
    fn insert_inner<'g>(
445
0
        &self,
446
0
        key: K,
447
0
        value: V,
448
0
        should_replace: bool,
449
0
        guard: &'g impl VerifiedGuard,
450
0
    ) -> RawInsertResult<'g, K, V> {
451
        // Allocate the entry to be inserted.
452
0
        let new_entry = untagged(Box::into_raw(Box::new(Entry { key, value })));
453
454
        // Safety: We just allocated the entry above.
455
0
        let new_ref = unsafe { &(*new_entry.ptr) };
456
457
        // Load the root table.
458
0
        let mut table = self.root(guard);
459
460
        // Allocate the table if it has not been initialized yet.
461
0
        if table.raw.is_null() {
462
0
            table = self.init(None);
463
0
        }
464
465
0
        let (h1, h2) = self.hash(&new_ref.key);
466
467
0
        let mut help_copy = true;
468
        loop {
469
            // Initialize the probe state.
470
0
            let mut probe = Probe::start(h1, table.mask);
471
472
            // Probe until we reach the limit.
473
0
            let copying = 'probe: loop {
474
0
                if probe.len > table.limit {
475
0
                    break None;
476
0
                }
477
478
                // Load the entry metadata first for cheap searches.
479
                //
480
                // Safety: `probe.i` is always in-bounds for the table length.
481
0
                let meta = unsafe { table.meta(probe.i) }.load(Ordering::Acquire);
482
483
                // The entry is empty, try to insert.
484
0
                let entry = if meta == meta::EMPTY {
485
                    // Perform the insertion.
486
                    //
487
                    // Safety: `probe.i` is always in-bounds for the table length. Additionally,
488
                    // `new_entry` was allocated above and never shared.
489
0
                    match unsafe { self.insert_at(probe.i, h2, new_entry.raw, table, guard) } {
490
                        // Successfully inserted.
491
0
                        InsertStatus::Inserted => return RawInsertResult::Inserted(&new_ref.value),
492
493
                        // Lost to a concurrent insert.
494
                        //
495
                        // If the key matches, we might be able to update the value.
496
0
                        InsertStatus::Found(EntryStatus::Value(found))
497
0
                        | InsertStatus::Found(EntryStatus::Copied(found)) => found,
498
499
                        // Otherwise, continue probing.
500
                        InsertStatus::Found(EntryStatus::Null) => {
501
0
                            probe.next(table.mask);
502
0
                            continue 'probe;
503
                        }
504
                    }
505
                }
506
                // Found a potential match.
507
0
                else if meta == h2 {
508
                    // Load the full entry.
509
                    //
510
                    // Safety: `probe.i` is always in-bounds for the table length.
511
0
                    let entry = guard
512
0
                        .protect(unsafe { table.entry(probe.i) }, Ordering::Acquire)
513
0
                        .unpack();
514
515
                    // The entry was deleted, keep probing.
516
0
                    if entry.ptr.is_null() {
517
0
                        probe.next(table.mask);
518
0
                        continue 'probe;
519
0
                    }
520
521
                    // If the key matches, we might be able to update the value.
522
0
                    entry
523
                }
524
                // Otherwise, continue probing.
525
                else {
526
0
                    probe.next(table.mask);
527
0
                    continue 'probe;
528
                };
529
530
                // Safety: We performed a protected load of the pointer using a verified guard with
531
                // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
532
                // as we hold the guard.
533
0
                let entry_ref = unsafe { &(*entry.ptr) };
534
535
                // Check for a full match.
536
0
                if entry_ref.key != new_ref.key {
537
0
                    probe.next(table.mask);
538
0
                    continue 'probe;
539
0
                }
540
541
                // The entry is being copied to the new table.
542
0
                if entry.tag() & Entry::COPYING != 0 {
543
0
                    break 'probe Some(probe.i);
544
0
                }
545
546
                // Return an error for calls to `try_insert`.
547
0
                if !should_replace {
548
0
                    return RawInsertResult::Error {
549
0
                        current: &entry_ref.value,
550
0
                        not_inserted: new_entry.ptr,
551
0
                    };
552
0
                }
553
554
                // Try to update the value.
555
                //
556
                // Safety:
557
                // - `probe.i` is always in-bounds for the table length
558
                // - `entry` is a valid non-null entry that was inserted into the map.
559
0
                match unsafe { self.insert_slow(probe.i, entry, new_entry.raw, table, guard) } {
560
                    // Successfully performed the update.
561
0
                    UpdateStatus::Replaced(entry) => {
562
                        // Safety: `entry` is a valid non-null entry that we found in the map
563
                        // before replacing it.
564
0
                        let value = unsafe { &(*entry.ptr).value };
565
0
                        return RawInsertResult::Replaced(value);
566
                    }
567
568
                    // The entry is being copied.
569
0
                    UpdateStatus::Found(EntryStatus::Copied(_)) => break 'probe Some(probe.i),
570
571
                    // The entry was deleted before we could update it, continue probing.
572
                    UpdateStatus::Found(EntryStatus::Null) => {
573
0
                        probe.next(table.mask);
574
0
                        continue 'probe;
575
                    }
576
577
0
                    UpdateStatus::Found(EntryStatus::Value(_)) => {}
578
                }
579
            };
580
581
            // Prepare to retry in the next table.
582
0
            table = self.prepare_retry_insert(copying, &mut help_copy, table, guard);
583
        }
584
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::insert_inner::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::insert_inner::<_>
585
586
    /// The slow-path for `insert`, updating the value.
587
    ///
588
    /// The returned pointer is guaranteed to be non-null and valid for reads.
589
    ///
590
    /// # Safety
591
    ///
592
    /// The safety requirements of `HashMap::update_at` apply.
593
    #[cold]
594
    #[inline(never)]
595
0
    unsafe fn insert_slow(
596
0
        &self,
597
0
        i: usize,
598
0
        mut entry: Tagged<Entry<K, V>>,
599
0
        new_entry: *mut Entry<K, V>,
600
0
        table: Table<Entry<K, V>>,
601
0
        guard: &impl VerifiedGuard,
602
0
    ) -> UpdateStatus<K, V> {
603
        loop {
604
            // Try to update the value.
605
            //
606
            // Safety: Guaranteed by caller.
607
0
            match unsafe { self.update_at(i, entry, new_entry, table, guard) } {
608
                // Someone else beat us to the update, retry.
609
                //
610
                // Note that the pointer we find here is a non-null entry that was inserted
611
                // into the map.
612
0
                UpdateStatus::Found(EntryStatus::Value(found)) => entry = found,
613
614
0
                status => return status,
615
            }
616
        }
617
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::insert_slow::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::insert_slow::<_>
618
619
    /// Prepare to retry an insert operation in the next table.
620
    #[cold]
621
    #[inline(never)]
622
0
    fn prepare_retry_insert(
623
0
        &self,
624
0
        copying: Option<usize>,
625
0
        help_copy: &mut bool,
626
0
        table: Table<Entry<K, V>>,
627
0
        guard: &impl VerifiedGuard,
628
0
    ) -> Table<Entry<K, V>> {
629
        // If went over the probe limit or found a copied entry, trigger a resize.
630
0
        let mut next_table = self.get_or_alloc_next(None, table);
631
632
0
        let next_table = match self.resize {
633
            // In blocking mode we must complete the resize before proceeding.
634
0
            ResizeMode::Blocking => self.help_copy(true, &table, guard),
635
636
            // In incremental mode we can perform more granular blocking.
637
            ResizeMode::Incremental(_) => {
638
                // Help out with the copy.
639
0
                if *help_copy {
640
0
                    next_table = self.help_copy(false, &table, guard);
641
0
                }
642
643
                // The entry we want to update is being copied.
644
0
                if let Some(i) = copying {
645
0
                    // Wait for the entry to be copied.
646
0
                    //
647
0
                    // We could race with the copy to insert into the table. However,
648
0
                    // this entire code path is very rare and likely to complete quickly,
649
0
                    // so blocking allows us to make copies faster.
650
0
                    self.wait_copied(i, &table);
651
0
                }
652
653
0
                next_table
654
            }
655
        };
656
657
        // Limit incremental copying to once per operation, for more consistent latency.
658
0
        *help_copy = false;
659
660
        // Continue in the new table.
661
0
        next_table
662
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::prepare_retry_insert::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::prepare_retry_insert::<_>
663
664
    /// Removes a key from the map, returning the entry for the key if the key was previously in the map.
665
    #[inline]
666
0
    pub fn remove<'g, Q>(&self, key: &Q, guard: &'g impl VerifiedGuard) -> Option<(&'g K, &'g V)>
667
0
    where
668
0
        Q: Equivalent<K> + Hash + ?Sized,
669
    {
670
        #[inline(always)]
671
0
        fn should_remove<K, V>(_key: &K, _value: &V) -> bool {
672
0
            true
673
0
        }
674
675
        // Safety: `should_remove` unconditionally returns `true`.
676
0
        unsafe { self.remove_if(key, should_remove, guard).unwrap_unchecked() }
677
0
    }
678
679
    /// Removes a key from the map, returning the entry for the key if the key was previously in the map
680
    /// and the provided closure returns `true`
681
    #[inline]
682
0
    pub fn remove_if<'g, Q, F>(
683
0
        &self,
684
0
        key: &Q,
685
0
        mut should_remove: F,
686
0
        guard: &'g impl VerifiedGuard,
687
0
    ) -> Result<Option<(&'g K, &'g V)>, (&'g K, &'g V)>
688
0
    where
689
0
        Q: Equivalent<K> + Hash + ?Sized,
690
0
        F: FnMut(&K, &V) -> bool,
691
    {
692
        // Load the root table.
693
0
        let mut table = self.root(guard);
694
695
        // The table has not been initialized yet.
696
0
        if table.raw.is_null() {
697
0
            return Ok(None);
698
0
        }
699
700
0
        let (h1, h2) = self.hash(key);
701
702
0
        let mut help_copy = true;
703
        loop {
704
            // Initialize the probe state.
705
0
            let mut probe = Probe::start(h1, table.mask);
706
707
            // Probe until we reach the limit.
708
0
            let copying = 'probe: loop {
709
0
                if probe.len > table.limit {
710
0
                    break None;
711
0
                }
712
713
                // Load the entry metadata first for cheap searches.
714
                //
715
                // Safety: `probe.i` is always in-bounds for the table length.
716
0
                let meta = unsafe { table.meta(probe.i).load(Ordering::Acquire) };
717
718
                // The key is not in the table.
719
                // It also cannot be in the next table because we have not went over the probe limit.
720
0
                if meta == meta::EMPTY {
721
0
                    return Ok(None);
722
0
                }
723
724
                // Check for a potential match.
725
0
                if meta != h2 {
726
0
                    probe.next(table.mask);
727
0
                    continue 'probe;
728
0
                }
729
730
                // Load the full entry.
731
                //
732
                // Safety: `probe.i` is always in-bounds for the table length.
733
0
                let mut entry = guard
734
0
                    .protect(unsafe { table.entry(probe.i) }, Ordering::Acquire)
735
0
                    .unpack();
736
737
                // The entry was deleted, keep probing.
738
0
                if entry.ptr.is_null() {
739
0
                    probe.next(table.mask);
740
0
                    continue 'probe;
741
0
                }
742
743
                // Check for a full match.
744
                //
745
                // Safety: We performed a protected load of the pointer using a verified guard with
746
                // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
747
                // as we hold the guard.
748
0
                if !key.equivalent(unsafe { &(*entry.ptr).key }) {
749
0
                    probe.next(table.mask);
750
0
                    continue 'probe;
751
0
                }
752
753
                // The entry is being copied to the new table, we have to complete the copy before
754
                // we can remove it.
755
0
                if entry.tag() & Entry::COPYING != 0 {
756
0
                    break 'probe Some(probe.i);
757
0
                }
758
759
                loop {
760
                    // Safety: `entry` is a valid, non-null, protected entry that we found in the map.
761
0
                    let entry_ref = unsafe { &(*entry.ptr) };
762
763
                    // Ensure that the entry should be removed.
764
0
                    if !should_remove(&entry_ref.key, &entry_ref.value) {
765
0
                        return Err((&entry_ref.key, &entry_ref.value));
766
0
                    }
767
768
                    // Safety:
769
                    // - `probe.i` is always in-bounds for the table length
770
                    // - `entry` is a valid non-null entry that we found in the map.
771
0
                    let status =
772
0
                        unsafe { self.update_at(probe.i, entry, Entry::TOMBSTONE, table, guard) };
773
774
0
                    match status {
775
                        // Successfully removed the entry.
776
0
                        UpdateStatus::Replaced(_entry) => {
777
                            // Mark the entry as a tombstone.
778
                            //
779
                            // Note that this might end up being overwritten by the metadata hash
780
                            // if the initial insertion is lagging behind, but we avoid the RMW
781
                            // and sacrifice reads in the extremely rare case.
782
                            //
783
                            // Safety: `probe.i` is always in-bounds for the table length.
784
                            unsafe {
785
0
                                table
786
0
                                    .meta(probe.i)
787
0
                                    .store(meta::TOMBSTONE, Ordering::Release)
788
                            };
789
790
                            // Decrement the table length.
791
0
                            self.count.get(guard).fetch_sub(1, Ordering::Relaxed);
792
793
                            // Note that `entry_ref` here is the entry that we just replaced.
794
0
                            return Ok(Some((&entry_ref.key, &entry_ref.value)));
795
                        }
796
797
                        // The entry is being copied to the new table, we have to complete the copy
798
                        // before we can remove.
799
0
                        UpdateStatus::Found(EntryStatus::Copied(_)) => break 'probe Some(probe.i),
800
801
                        // The entry was deleted.
802
                        //
803
                        // We know that at some point during our execution the key was not in the map.
804
0
                        UpdateStatus::Found(EntryStatus::Null) => return Ok(None),
805
806
                        // Lost to a concurrent update, retry.
807
0
                        UpdateStatus::Found(EntryStatus::Value(found)) => entry = found,
808
                    }
809
                }
810
            };
811
812
            // Prepare to retry in the next table.
813
0
            table = match self.prepare_retry(copying, &mut help_copy, table, guard) {
814
0
                Some(table) => table,
815
816
                // The search was exhausted.
817
0
                None => return Ok(None),
818
            }
819
        }
820
0
    }
821
822
    /// Prepare to retry an operation on an existing key in the next table.
823
    ///
824
    /// Returns `None` if the recursive search has been exhausted.
825
    #[cold]
826
0
    fn prepare_retry(
827
0
        &self,
828
0
        copying: Option<usize>,
829
0
        help_copy: &mut bool,
830
0
        table: Table<Entry<K, V>>,
831
0
        guard: &impl VerifiedGuard,
832
0
    ) -> Option<Table<Entry<K, V>>> {
833
0
        let next_table = match self.resize {
834
0
            ResizeMode::Blocking => match copying {
835
                // The entry we want to perform the operation on is being copied.
836
                //
837
                // In blocking mode we must complete the resize before proceeding.
838
0
                Some(_) => self.help_copy(true, &table, guard),
839
840
                // If we went over the probe limit, the key is not in the map.
841
0
                None => return None,
842
            },
843
844
            ResizeMode::Incremental(_) => {
845
                // In incremental resize mode, we always have to check the next table.
846
0
                let next_table = table.next_table()?;
847
848
                // Help out with the copy.
849
0
                if *help_copy {
850
0
                    self.help_copy(false, &table, guard);
851
0
                }
852
853
0
                if let Some(i) = copying {
854
0
                    // Wait for the entry to be copied.
855
0
                    //
856
0
                    // We could race with the copy to insert into the table. However,
857
0
                    // this entire code path is very rare and likely to complete quickly,
858
0
                    // so blocking allows us to make copies faster.
859
0
                    self.wait_copied(i, &table);
860
0
                }
861
862
0
                next_table
863
            }
864
        };
865
866
        // Limit incremental copying to once per operation, for more consistent latency.
867
0
        *help_copy = false;
868
869
        // Continue in the new table.
870
0
        Some(next_table)
871
0
    }
872
873
    /// Attempts to insert an entry at the given index.
874
    ///
875
    /// In the case of an error, the returned pointer is guaranteed to be
876
    /// protected and valid for reads as long as the guard is held.
877
    ///
878
    /// # Safety
879
    ///
880
    /// The index must be in-bounds for the table. Additionally, `new_entry` must be a
881
    /// valid owned pointer to insert into the map.
882
    #[inline]
883
0
    unsafe fn insert_at(
884
0
        &self,
885
0
        i: usize,
886
0
        meta: u8,
887
0
        new_entry: *mut Entry<K, V>,
888
0
        table: Table<Entry<K, V>>,
889
0
        guard: &impl VerifiedGuard,
890
0
    ) -> InsertStatus<K, V> {
891
        // Safety: The caller guarantees that `i` is in-bounds.
892
0
        let entry = unsafe { table.entry(i) };
893
0
        let meta_entry = unsafe { table.meta(i) };
894
895
        // Try to claim the empty entry.
896
0
        let found = match guard.compare_exchange(
897
0
            entry,
898
0
            ptr::null_mut(),
899
0
            new_entry,
900
0
            Ordering::Release,
901
0
            Ordering::Acquire,
902
0
        ) {
903
            // Successfully claimed the entry.
904
            Ok(_) => {
905
                // Update the metadata table.
906
0
                meta_entry.store(meta, Ordering::Release);
907
908
                // Return the value we inserted.
909
0
                return InsertStatus::Inserted;
910
            }
911
912
            // Lost to a concurrent update.
913
0
            Err(found) => found.unpack(),
914
        };
915
916
0
        let (meta, status) = match EntryStatus::from(found) {
917
            EntryStatus::Value(_) | EntryStatus::Copied(_) => {
918
                // Safety: We performed a protected load of the pointer using a verified guard
919
                // with `Acquire` and ensured that it is non-null, meaning it is valid for reads
920
                // as long as we hold the guard.
921
0
                let key = unsafe { &(*found.ptr).key };
922
923
                // An entry was inserted, we have to hash it to get the metadata.
924
                //
925
                // The logic is the same for copied entries here as we have to
926
                // check if the key matches and continue the update in the new table.
927
0
                let hash = self.hasher.hash_one(key);
928
0
                (meta::h2(hash), EntryStatus::Value(found))
929
            }
930
931
            // The entry was deleted or null copied.
932
0
            EntryStatus::Null => (meta::TOMBSTONE, EntryStatus::Null),
933
        };
934
935
        // Ensure the meta table is updated to keep the probe chain alive for readers.
936
0
        if meta_entry.load(Ordering::Relaxed) == meta::EMPTY {
937
0
            meta_entry.store(meta, Ordering::Release);
938
0
        }
939
940
0
        InsertStatus::Found(status)
941
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::insert_at::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::insert_at::<_>
942
943
    /// Attempts to replace the value of an existing entry at the given index.
944
    ///
945
    /// In the case of an error, the returned pointer is guaranteed to be
946
    /// protected and valid for reads.
947
    ///
948
    /// # Safety
949
    ///
950
    /// - The index must be in-bounds for the table.
951
    /// - `current` must be a valid non-null entry that was inserted into the map.
952
    /// - `new_entry` must be a valid sentinel or owned pointer to insert into the map.
953
    #[inline]
954
0
    unsafe fn update_at(
955
0
        &self,
956
0
        i: usize,
957
0
        current: Tagged<Entry<K, V>>,
958
0
        new_entry: *mut Entry<K, V>,
959
0
        table: Table<Entry<K, V>>,
960
0
        guard: &impl VerifiedGuard,
961
0
    ) -> UpdateStatus<K, V> {
962
        // Safety: The caller guarantees that `i` is in-bounds.
963
0
        let entry = unsafe { table.entry(i) };
964
965
        // Try to perform the update.
966
0
        let found = match guard.compare_exchange_weak(
967
0
            entry,
968
0
            current.raw,
969
0
            new_entry,
970
0
            Ordering::Release,
971
0
            Ordering::Acquire,
972
0
        ) {
973
            // Successfully updated.
974
            Ok(_) => unsafe {
975
                // Safety: The caller guarantees that `current` is a valid non-null entry that was
976
                // inserted into the map. Additionally, it is now unreachable from this table due
977
                // to the CAS above.
978
0
                self.defer_retire(current, &table, guard);
979
980
0
                return UpdateStatus::Replaced(current);
981
            },
982
983
            // Lost to a concurrent update.
984
0
            Err(found) => found.unpack(),
985
        };
986
987
0
        UpdateStatus::Found(EntryStatus::from(found))
988
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::update_at::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::update_at::<_>
989
990
    /// Reserve capacity for `additional` more elements.
991
    #[inline]
992
0
    pub fn reserve(&self, additional: usize, guard: &impl VerifiedGuard) {
993
0
        let mut table = self.root(guard);
994
995
        // The table has not yet been allocated, initialize it.
996
0
        if table.raw.is_null() {
997
0
            table = self.init(Some(probe::entries_for(additional)));
998
0
        }
999
1000
        loop {
1001
0
            let capacity = probe::entries_for(self.count.sum().checked_add(additional).unwrap());
1002
1003
            // We have enough capacity.
1004
0
            if table.len() >= capacity {
1005
0
                return;
1006
0
            }
1007
1008
            // Race to allocate the new table.
1009
0
            self.get_or_alloc_next(Some(capacity), table);
1010
1011
            // Force the copy to complete.
1012
            //
1013
            // Note that this is not strictly necessary for a `reserve` operation.
1014
0
            table = self.help_copy(true, &table, guard);
1015
        }
1016
0
    }
1017
1018
    /// Remove all entries from this table.
1019
    #[inline]
1020
538k
    pub fn clear(&self, guard: &impl VerifiedGuard) {
1021
        // Load the root table.
1022
538k
        let mut table = self.root(guard);
1023
1024
        // The table has not been initialized yet.
1025
538k
        if table.raw.is_null() {
1026
538k
            return;
1027
0
        }
1028
1029
        loop {
1030
            // Get a clean copy of the table to delete from.
1031
0
            table = self.linearize(table, guard);
1032
1033
            // Note that this method is not implemented in terms of `retain(|_, _| true)` to avoid
1034
            // loading entry metadata, as there is no need to provide consistency with `get`.
1035
0
            let mut copying = false;
1036
1037
0
            'probe: for i in 0..table.len() {
1038
                // Load the entry to delete.
1039
                //
1040
                // Safety: `i` is in bounds for the table length.
1041
0
                let mut entry = guard
1042
0
                    .protect(unsafe { table.entry(i) }, Ordering::Acquire)
1043
0
                    .unpack();
1044
1045
                loop {
1046
                    // The entry is empty or already deleted.
1047
0
                    if entry.ptr.is_null() {
1048
0
                        continue 'probe;
1049
0
                    }
1050
1051
                    // Found a non-empty entry being copied.
1052
0
                    if entry.tag() & Entry::COPYING != 0 {
1053
                        // Clear every entry in this table that we can, then deal with the copy.
1054
0
                        copying = true;
1055
0
                        continue 'probe;
1056
0
                    }
1057
1058
                    // Try to delete the entry.
1059
                    //
1060
                    // Safety: `i` is in bounds for the table length.
1061
0
                    let result = unsafe {
1062
0
                        table.entry(i).compare_exchange(
1063
0
                            entry.raw,
1064
                            Entry::TOMBSTONE,
1065
0
                            Ordering::Release,
1066
0
                            Ordering::Acquire,
1067
                        )
1068
                    };
1069
1070
0
                    match result {
1071
                        // Successfully deleted the entry.
1072
                        Ok(_) => {
1073
                            // Update the metadata table.
1074
                            //
1075
                            // Safety: `i` is in bounds for the table length.
1076
0
                            unsafe { table.meta(i).store(meta::TOMBSTONE, Ordering::Release) };
1077
1078
                            // Decrement the table length.
1079
0
                            self.count.get(guard).fetch_sub(1, Ordering::Relaxed);
1080
1081
                            // Safety: The caller guarantees that `current` is a valid non-null entry that was
1082
                            // inserted into the map. Additionally, it is now unreachable from this table due
1083
                            // to the CAS above.
1084
0
                            unsafe { self.defer_retire(entry, &table, guard) };
1085
0
                            continue 'probe;
1086
                        }
1087
1088
                        // Lost to a concurrent update, retry.
1089
0
                        Err(found) => entry = found.unpack(),
1090
                    }
1091
                }
1092
            }
1093
1094
            // We cleared every entry in this table.
1095
0
            if !copying {
1096
0
                break;
1097
0
            }
1098
1099
            // A resize prevented us from deleting all the entries in this table.
1100
            //
1101
            // Complete the resize and retry in the new table.
1102
0
            table = self.help_copy(true, &table, guard);
1103
        }
1104
538k
    }
<papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::clear::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Line
Count
Source
1020
538k
    pub fn clear(&self, guard: &impl VerifiedGuard) {
1021
        // Load the root table.
1022
538k
        let mut table = self.root(guard);
1023
1024
        // The table has not been initialized yet.
1025
538k
        if table.raw.is_null() {
1026
538k
            return;
1027
0
        }
1028
1029
        loop {
1030
            // Get a clean copy of the table to delete from.
1031
0
            table = self.linearize(table, guard);
1032
1033
            // Note that this method is not implemented in terms of `retain(|_, _| true)` to avoid
1034
            // loading entry metadata, as there is no need to provide consistency with `get`.
1035
0
            let mut copying = false;
1036
1037
0
            'probe: for i in 0..table.len() {
1038
                // Load the entry to delete.
1039
                //
1040
                // Safety: `i` is in bounds for the table length.
1041
0
                let mut entry = guard
1042
0
                    .protect(unsafe { table.entry(i) }, Ordering::Acquire)
1043
0
                    .unpack();
1044
1045
                loop {
1046
                    // The entry is empty or already deleted.
1047
0
                    if entry.ptr.is_null() {
1048
0
                        continue 'probe;
1049
0
                    }
1050
1051
                    // Found a non-empty entry being copied.
1052
0
                    if entry.tag() & Entry::COPYING != 0 {
1053
                        // Clear every entry in this table that we can, then deal with the copy.
1054
0
                        copying = true;
1055
0
                        continue 'probe;
1056
0
                    }
1057
1058
                    // Try to delete the entry.
1059
                    //
1060
                    // Safety: `i` is in bounds for the table length.
1061
0
                    let result = unsafe {
1062
0
                        table.entry(i).compare_exchange(
1063
0
                            entry.raw,
1064
                            Entry::TOMBSTONE,
1065
0
                            Ordering::Release,
1066
0
                            Ordering::Acquire,
1067
                        )
1068
                    };
1069
1070
0
                    match result {
1071
                        // Successfully deleted the entry.
1072
                        Ok(_) => {
1073
                            // Update the metadata table.
1074
                            //
1075
                            // Safety: `i` is in bounds for the table length.
1076
0
                            unsafe { table.meta(i).store(meta::TOMBSTONE, Ordering::Release) };
1077
1078
                            // Decrement the table length.
1079
0
                            self.count.get(guard).fetch_sub(1, Ordering::Relaxed);
1080
1081
                            // Safety: The caller guarantees that `current` is a valid non-null entry that was
1082
                            // inserted into the map. Additionally, it is now unreachable from this table due
1083
                            // to the CAS above.
1084
0
                            unsafe { self.defer_retire(entry, &table, guard) };
1085
0
                            continue 'probe;
1086
                        }
1087
1088
                        // Lost to a concurrent update, retry.
1089
0
                        Err(found) => entry = found.unpack(),
1090
                    }
1091
                }
1092
            }
1093
1094
            // We cleared every entry in this table.
1095
0
            if !copying {
1096
0
                break;
1097
0
            }
1098
1099
            // A resize prevented us from deleting all the entries in this table.
1100
            //
1101
            // Complete the resize and retry in the new table.
1102
0
            table = self.help_copy(true, &table, guard);
1103
        }
1104
538k
    }
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::clear::<_>
1105
1106
    /// Retains only the elements specified by the predicate.
1107
    #[inline]
1108
0
    pub fn retain<F>(&self, mut f: F, guard: &impl VerifiedGuard)
1109
0
    where
1110
0
        F: FnMut(&K, &V) -> bool,
1111
    {
1112
        // Load the root table.
1113
0
        let mut table = self.root(guard);
1114
1115
        // The table has not been initialized yet.
1116
0
        if table.raw.is_null() {
1117
0
            return;
1118
0
        }
1119
1120
        loop {
1121
            // Get a clean copy of the table to delete from.
1122
0
            table = self.linearize(table, guard);
1123
1124
0
            let mut copying = false;
1125
0
            'probe: for i in 0..table.len() {
1126
                // Load the entry metadata first to ensure consistency with calls to `get`
1127
                // for entries that are retained.
1128
                //
1129
                // Safety: `i` is in bounds for the table length.
1130
0
                let meta = unsafe { table.meta(i) }.load(Ordering::Acquire);
1131
1132
                // The entry is empty or deleted.
1133
0
                if matches!(meta, meta::EMPTY | meta::TOMBSTONE) {
1134
0
                    continue 'probe;
1135
0
                }
1136
1137
                // Load the entry to delete.
1138
                //
1139
                // Safety: `i` is in bounds for the table length.
1140
0
                let mut entry = guard
1141
0
                    .protect(unsafe { table.entry(i) }, Ordering::Acquire)
1142
0
                    .unpack();
1143
1144
                loop {
1145
                    // The entry is empty or already deleted.
1146
0
                    if entry.ptr.is_null() {
1147
0
                        continue 'probe;
1148
0
                    }
1149
1150
                    // Found a non-empty entry being copied.
1151
0
                    if entry.tag() & Entry::COPYING != 0 {
1152
                        // Clear every entry in this table that we can, then deal with the copy.
1153
0
                        copying = true;
1154
0
                        continue 'probe;
1155
0
                    }
1156
1157
                    // Safety: We performed a protected load of the pointer using a verified guard with
1158
                    // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
1159
                    // as we hold the guard.
1160
0
                    let entry_ref = unsafe { &*entry.ptr };
1161
1162
                    // Should we retain this entry?
1163
0
                    if f(&entry_ref.key, &entry_ref.value) {
1164
0
                        continue 'probe;
1165
0
                    }
1166
1167
                    // Try to delete the entry.
1168
                    //
1169
                    // Safety: `i` is in bounds for the table length.
1170
0
                    let result = unsafe {
1171
0
                        table.entry(i).compare_exchange(
1172
0
                            entry.raw,
1173
                            Entry::TOMBSTONE,
1174
0
                            Ordering::Release,
1175
0
                            Ordering::Acquire,
1176
                        )
1177
                    };
1178
1179
0
                    match result {
1180
                        // Successfully deleted the entry.
1181
                        Ok(_) => {
1182
                            // Update the metadata table.
1183
                            //
1184
                            // Safety: `i` is in bounds for the table length.
1185
0
                            unsafe { table.meta(i).store(meta::TOMBSTONE, Ordering::Release) };
1186
1187
                            // Decrement the table length.
1188
0
                            self.count.get(guard).fetch_sub(1, Ordering::Relaxed);
1189
1190
                            // Safety: The caller guarantees that `current` is a valid non-null entry that was
1191
                            // inserted into the map. Additionally, it is now unreachable from this table due
1192
                            // to the CAS above.
1193
0
                            unsafe { self.defer_retire(entry, &table, guard) };
1194
0
                            continue 'probe;
1195
                        }
1196
1197
                        // Lost to a concurrent update, retry.
1198
0
                        Err(found) => entry = found.unpack(),
1199
                    }
1200
                }
1201
            }
1202
1203
            // We cleared every entry in this table.
1204
0
            if !copying {
1205
0
                break;
1206
0
            }
1207
1208
            // A resize prevented us from deleting all the entries in this table.
1209
            //
1210
            // Complete the resize and retry in the new table.
1211
0
            table = self.help_copy(true, &table, guard);
1212
        }
1213
0
    }
1214
1215
    /// Returns an iterator over the keys and values of this table.
1216
    #[inline]
1217
162
    pub fn iter<'g, G>(&self, guard: &'g G) -> Iter<'g, K, V, G>
1218
162
    where
1219
162
        G: VerifiedGuard,
1220
    {
1221
        // Load the root table.
1222
162
        let root = self.root(guard);
1223
1224
        // The table has not been initialized yet, return a dummy iterator.
1225
162
        if root.raw.is_null() {
1226
162
            return Iter {
1227
162
                i: 0,
1228
162
                guard,
1229
162
                table: root,
1230
162
            };
1231
0
        }
1232
1233
        // Get a clean copy of the table to iterate over.
1234
0
        let table = self.linearize(root, guard);
1235
1236
0
        Iter { i: 0, guard, table }
1237
162
    }
<papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::iter::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Line
Count
Source
1217
162
    pub fn iter<'g, G>(&self, guard: &'g G) -> Iter<'g, K, V, G>
1218
162
    where
1219
162
        G: VerifiedGuard,
1220
    {
1221
        // Load the root table.
1222
162
        let root = self.root(guard);
1223
1224
        // The table has not been initialized yet, return a dummy iterator.
1225
162
        if root.raw.is_null() {
1226
162
            return Iter {
1227
162
                i: 0,
1228
162
                guard,
1229
162
                table: root,
1230
162
            };
1231
0
        }
1232
1233
        // Get a clean copy of the table to iterate over.
1234
0
        let table = self.linearize(root, guard);
1235
1236
0
        Iter { i: 0, guard, table }
1237
162
    }
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::iter::<_>
1238
1239
    /// Returns the h1 and h2 hash for the given key.
1240
    #[inline]
1241
0
    fn hash<Q>(&self, key: &Q) -> (usize, u8)
1242
0
    where
1243
0
        Q: Hash + ?Sized,
1244
    {
1245
0
        let hash = self.hasher.hash_one(key);
1246
0
        (meta::h1(hash), meta::h2(hash))
1247
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::hash::<[u8]>
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::hash::<bytes::bytes::Bytes>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::hash::<_>
1248
}
1249
1250
/// A wrapper around a CAS function that manages the computed state.
1251
struct ComputeState<F, K, V, T> {
1252
    /// The CAS function.
1253
    compute: F,
1254
1255
    /// A cached insert transition.
1256
    insert: Option<V>,
1257
1258
    /// A cached update transition.
1259
    update: Option<CachedUpdate<K, V, T>>,
1260
}
1261
1262
/// A cached update transition.
1263
struct CachedUpdate<K, V, T> {
1264
    /// The entry that the CAS function was called with.
1265
    input: *mut Entry<K, V>,
1266
1267
    /// The cached result.
1268
    output: Operation<V, T>,
1269
}
1270
1271
impl<'g, F, K, V, T> ComputeState<F, K, V, T>
1272
where
1273
    F: FnMut(Option<(&'g K, &'g V)>) -> Operation<V, T>,
1274
    K: 'g,
1275
    V: 'g,
1276
{
1277
    /// Create a new `ComputeState` for the given function.
1278
    #[inline]
1279
0
    fn new(compute: F) -> ComputeState<F, K, V, T> {
1280
0
        ComputeState {
1281
0
            compute,
1282
0
            insert: None,
1283
0
            update: None,
1284
0
        }
1285
0
    }
1286
1287
    /// Performs a state transition.
1288
    ///
1289
    /// # Safety
1290
    ///
1291
    /// The entry pointer must be valid for reads if provided.
1292
    #[inline]
1293
0
    unsafe fn next(&mut self, entry: Option<*mut Entry<K, V>>) -> Operation<V, T> {
1294
0
        let Some(entry) = entry else {
1295
            // If there is no current entry, perform a transition for the insert.
1296
0
            return match self.insert.take() {
1297
                // Use the cached insert.
1298
0
                Some(value) => Operation::Insert(value),
1299
1300
                // Otherwise, compute the value to insert.
1301
0
                None => (self.compute)(None),
1302
            };
1303
        };
1304
1305
        // Otherwise, perform an update transition.
1306
0
        match self.update.take() {
1307
            // Used the cached update if the entry has not changed.
1308
0
            Some(CachedUpdate { input, output }) if input == entry => output,
1309
1310
            // Otherwise, compute the value to update.
1311
            _ => {
1312
                // Safety: The caller guarantees that `entry` is valid for reads.
1313
0
                let entry_ref = unsafe { &*entry };
1314
0
                (self.compute)(Some((&entry_ref.key, &entry_ref.value)))
1315
            }
1316
        }
1317
0
    }
1318
1319
    /// Restores the state if an operation fails.
1320
    ///
1321
    /// This allows the result of the compute closure with a given input to be cached.
1322
    /// This is useful at it avoids calling the closure multiple times if an update needs
1323
    /// to be retried in a new table.
1324
    ///
1325
    /// Additionally, update and insert operations are cached separately, although this
1326
    /// is not guaranteed in the public API. This means that internal methods can rely on
1327
    /// `compute(None)` being called at most once.
1328
    #[inline]
1329
0
    fn restore(&mut self, input: Option<*mut Entry<K, V>>, output: Operation<V, T>) {
1330
0
        match input {
1331
0
            Some(input) => self.update = Some(CachedUpdate { input, output }),
1332
0
            None => match output {
1333
0
                Operation::Insert(value) => self.insert = Some(value),
1334
0
                _ => unreachable!(),
1335
            },
1336
        }
1337
0
    }
1338
}
1339
1340
/// A lazy initialized `Entry` allocation.
1341
enum LazyEntry<K, V> {
1342
    /// An uninitialized entry, containing just the owned key.
1343
    Uninit(K),
1344
1345
    /// An allocated entry.
1346
    Init(*mut Entry<K, MaybeUninit<V>>),
1347
}
1348
1349
impl<K, V> LazyEntry<K, V> {
1350
    /// Returns a reference to the entry's key.
1351
    #[inline]
1352
0
    fn key(&self) -> &K {
1353
0
        match self {
1354
0
            LazyEntry::Uninit(key) => key,
1355
0
            LazyEntry::Init(entry) => unsafe { &(**entry).key },
1356
        }
1357
0
    }
1358
1359
    /// Initializes the entry if it has not already been initialized, returning the pointer
1360
    /// to the entry allocation.
1361
    #[inline]
1362
0
    fn init(&mut self) -> *mut Entry<K, MaybeUninit<V>> {
1363
0
        match self {
1364
0
            LazyEntry::Init(entry) => *entry,
1365
0
            LazyEntry::Uninit(key) => {
1366
                // Safety: we read the current key with `ptr::read` and overwrite the
1367
                // state with `ptr::write`. We also make sure to abort if the allocator
1368
                // panics, ensuring the current value is not dropped twice.
1369
                unsafe {
1370
0
                    let key = ptr::read(key);
1371
0
                    let entry = panic::catch_unwind(panic::AssertUnwindSafe(|| {
1372
0
                        Box::into_raw(Box::new(Entry {
1373
0
                            value: MaybeUninit::uninit(),
1374
0
                            key,
1375
0
                        }))
1376
0
                    }))
1377
0
                    .unwrap_or_else(|_| std::process::abort());
1378
0
                    ptr::write(self, LazyEntry::Init(entry));
1379
0
                    entry
1380
                }
1381
            }
1382
        }
1383
0
    }
1384
}
1385
1386
/// RMW operations.
1387
impl<K, V, S> HashMap<K, V, S>
1388
where
1389
    K: Hash + Eq,
1390
    S: BuildHasher,
1391
{
1392
    /// Tries to insert a key and value computed from a closure into the map,
1393
    /// and returns a reference to the value that was inserted.
1394
    #[inline]
1395
0
    pub fn try_insert_with<'g, F>(
1396
0
        &self,
1397
0
        key: K,
1398
0
        f: F,
1399
0
        guard: &'g impl VerifiedGuard,
1400
0
    ) -> Result<&'g V, &'g V>
1401
0
    where
1402
0
        F: FnOnce() -> V,
1403
0
        K: 'g,
1404
    {
1405
0
        let mut f = Some(f);
1406
0
        let compute = |entry| match entry {
1407
            // There is already an existing value.
1408
0
            Some((_, current)) => Operation::Abort(current),
1409
1410
            // Insert the initial value.
1411
            //
1412
            // Note that this case is guaranteed to be executed at most
1413
            // once as insert values are cached, so this can never panic.
1414
0
            None => Operation::Insert((f.take().unwrap())()),
1415
0
        };
1416
1417
0
        match self.compute(key, compute, guard) {
1418
            // Failed to insert, return the existing value.
1419
0
            Compute::Aborted(current) => Err(current),
1420
1421
            // Successfully inserted.
1422
0
            Compute::Inserted(_, value) => Ok(value),
1423
1424
0
            _ => unreachable!(),
1425
        }
1426
0
    }
1427
1428
    /// Returns a reference to the value corresponding to the key, or inserts a default value
1429
    /// computed from a closure.
1430
    #[inline]
1431
0
    pub fn get_or_insert_with<'g, F>(&self, key: K, f: F, guard: &'g impl VerifiedGuard) -> &'g V
1432
0
    where
1433
0
        F: FnOnce() -> V,
1434
0
        K: 'g,
1435
    {
1436
0
        match self.try_insert_with(key, f, guard) {
1437
0
            Ok(value) => value,
1438
0
            Err(value) => value,
1439
        }
1440
0
    }
1441
1442
    /// Updates an existing entry atomically, returning the value that was inserted.
1443
    #[inline]
1444
0
    pub fn update<'g, F>(
1445
0
        &self,
1446
0
        key: K,
1447
0
        mut update: F,
1448
0
        guard: &'g impl VerifiedGuard,
1449
0
    ) -> Option<&'g V>
1450
0
    where
1451
0
        F: FnMut(&V) -> V,
1452
0
        K: 'g,
1453
    {
1454
0
        let compute = |entry| match entry {
1455
            // There is nothing to update.
1456
0
            None => Operation::Abort(()),
1457
            // Perform the update.
1458
0
            Some((_, value)) => Operation::Insert(update(value)),
1459
0
        };
1460
1461
0
        match self.compute(key, compute, guard) {
1462
            // Return the updated value.
1463
            Compute::Updated {
1464
0
                new: (_, value), ..
1465
0
            } => Some(value),
1466
1467
            // There was nothing to update.
1468
0
            Compute::Aborted(_) => None,
1469
1470
0
            _ => unreachable!(),
1471
        }
1472
0
    }
1473
1474
    /// Updates an existing entry or inserts a default value computed from a closure.
1475
    #[inline]
1476
0
    pub fn update_or_insert_with<'g, U, F>(
1477
0
        &self,
1478
0
        key: K,
1479
0
        update: U,
1480
0
        f: F,
1481
0
        guard: &'g impl VerifiedGuard,
1482
0
    ) -> &'g V
1483
0
    where
1484
0
        F: FnOnce() -> V,
1485
0
        U: Fn(&V) -> V,
1486
0
        K: 'g,
1487
    {
1488
0
        let mut f = Some(f);
1489
0
        let compute = |entry| match entry {
1490
            // Perform the update.
1491
0
            Some((_, value)) => Operation::Insert::<_, ()>(update(value)),
1492
1493
            // Insert the initial value.
1494
            //
1495
            // Note that this case is guaranteed to be executed at most
1496
            // once as insert values are cached, so this can never panic.
1497
0
            None => Operation::Insert((f.take().unwrap())()),
1498
0
        };
1499
1500
0
        match self.compute(key, compute, guard) {
1501
            // Return the updated value.
1502
            Compute::Updated {
1503
0
                new: (_, value), ..
1504
0
            } => value,
1505
1506
            // Return the value we inserted.
1507
0
            Compute::Inserted(_, value) => value,
1508
1509
0
            _ => unreachable!(),
1510
        }
1511
0
    }
1512
1513
    /// Update an entry with a CAS function.
1514
    ///
1515
    /// Note that `compute` closure is guaranteed to be called for a `None` input only once, allowing the
1516
    /// insertion of values that cannot be cloned or reconstructed.
1517
    #[inline]
1518
0
    pub fn compute<'g, F, T>(
1519
0
        &self,
1520
0
        key: K,
1521
0
        compute: F,
1522
0
        guard: &'g impl VerifiedGuard,
1523
0
    ) -> Compute<'g, K, V, T>
1524
0
    where
1525
0
        F: FnMut(Option<(&'g K, &'g V)>) -> Operation<V, T>,
1526
    {
1527
        // Lazy initialize the entry allocation.
1528
0
        let mut entry = LazyEntry::Uninit(key);
1529
1530
        // Perform the update.
1531
        //
1532
        // Safety: We just allocated the entry above.
1533
0
        let result = unsafe { self.compute_with(&mut entry, ComputeState::new(compute), guard) };
1534
1535
        // Deallocate the entry if it was not inserted.
1536
0
        if matches!(result, Compute::Removed(..) | Compute::Aborted(_)) {
1537
0
            if let LazyEntry::Init(entry) = entry {
1538
0
                // Safety: The entry was allocated but not inserted into the map.
1539
0
                let _ = unsafe { Box::from_raw(entry) };
1540
0
            }
1541
0
        }
1542
1543
0
        result
1544
0
    }
1545
1546
    /// Update an entry with a CAS function.
1547
    ///
1548
    /// # Safety
1549
    ///
1550
    /// The new entry must be a valid owned pointer to insert into the map.
1551
    #[inline]
1552
0
    unsafe fn compute_with<'g, F, T>(
1553
0
        &self,
1554
0
        new_entry: &mut LazyEntry<K, V>,
1555
0
        mut state: ComputeState<F, K, V, T>,
1556
0
        guard: &'g impl VerifiedGuard,
1557
0
    ) -> Compute<'g, K, V, T>
1558
0
    where
1559
0
        F: FnMut(Option<(&'g K, &'g V)>) -> Operation<V, T>,
1560
    {
1561
        // Load the root table.
1562
0
        let mut table = self.root(guard);
1563
1564
        // The table has not yet been allocated.
1565
0
        if table.raw.is_null() {
1566
            // Compute the value to insert.
1567
            //
1568
            // Safety: Insert transitions are always sound.
1569
0
            match unsafe { state.next(None) } {
1570
0
                op @ Operation::Insert(_) => state.restore(None, op),
1571
0
                Operation::Remove => panic!("Cannot remove `None` entry."),
1572
0
                Operation::Abort(value) => return Compute::Aborted(value),
1573
            }
1574
1575
            // Initialize the table.
1576
0
            table = self.init(None);
1577
0
        }
1578
1579
0
        let (h1, h2) = self.hash(new_entry.key());
1580
0
        let mut help_copy = false;
1581
1582
        loop {
1583
            // Initialize the probe state.
1584
0
            let mut probe = Probe::start(h1, table.mask);
1585
1586
            // Probe until we reach the limit.
1587
0
            let copying = 'probe: loop {
1588
0
                if probe.len > table.limit {
1589
0
                    break 'probe None;
1590
0
                }
1591
1592
                // Load the entry metadata first for cheap searches.
1593
                //
1594
                // Safety: `probe.i` is always in-bounds for the table length.
1595
0
                let meta = unsafe { table.meta(probe.i) }.load(Ordering::Acquire);
1596
1597
                // The entry is empty.
1598
0
                let mut entry = if meta == meta::EMPTY {
1599
                    // Compute the value to insert.
1600
                    //
1601
                    // Safety: Insert transitions are always sound.
1602
0
                    let value = match unsafe { state.next(None) } {
1603
0
                        Operation::Insert(value) => value,
1604
0
                        Operation::Remove => panic!("Cannot remove `None` entry."),
1605
0
                        Operation::Abort(value) => return Compute::Aborted(value),
1606
                    };
1607
1608
0
                    let new_entry = new_entry.init();
1609
                    // Safety: `new_entry` was just allocated above and is valid for writes.
1610
0
                    unsafe { (*new_entry).value = MaybeUninit::new(value) }
1611
1612
                    // Attempt to insert.
1613
                    //
1614
                    // Safety: `probe.i` is always in-bounds for the table length.Additionally,
1615
                    // `new_entry` was allocated above and never shared.
1616
0
                    match unsafe { self.insert_at(probe.i, h2, new_entry.cast(), table, guard) } {
1617
                        // Successfully inserted.
1618
                        InsertStatus::Inserted => {
1619
                            // Increment the table length.
1620
0
                            self.count.get(guard).fetch_add(1, Ordering::Relaxed);
1621
1622
                            // Safety: `new_entry` was initialized above.
1623
0
                            let new_ref = unsafe { &*new_entry.cast::<Entry<K, V>>() };
1624
0
                            return Compute::Inserted(&new_ref.key, &new_ref.value);
1625
                        }
1626
1627
                        // Lost to a concurrent insert.
1628
                        //
1629
                        // If the key matches, we might be able to update the value.
1630
0
                        InsertStatus::Found(EntryStatus::Value(found))
1631
0
                        | InsertStatus::Found(EntryStatus::Copied(found)) => {
1632
                            // Cache the previous value
1633
                            //
1634
                            // Safety: `new_entry` was initialized above and was not inserted
1635
                            // into the map.
1636
0
                            let value = unsafe { (*new_entry).value.assume_init_read() };
1637
0
                            state.restore(None, Operation::Insert(value));
1638
1639
0
                            found
1640
                        }
1641
1642
                        // The entry was removed or invalidated.
1643
                        InsertStatus::Found(EntryStatus::Null) => {
1644
                            // Cache the previous value.
1645
                            //
1646
                            // Safety: `new_entry` was initialized above and was not inserted
1647
                            // into the map.
1648
0
                            let value = unsafe { (*new_entry).value.assume_init_read() };
1649
0
                            state.restore(None, Operation::Insert(value));
1650
1651
                            // Continue probing.
1652
0
                            probe.next(table.mask);
1653
0
                            continue 'probe;
1654
                        }
1655
                    }
1656
                }
1657
                // Found a potential match.
1658
0
                else if meta == h2 {
1659
                    // Load the full entry.
1660
                    //
1661
                    // Safety: `probe.i` is always in-bounds for the table length.
1662
0
                    let found = guard
1663
0
                        .protect(unsafe { table.entry(probe.i) }, Ordering::Acquire)
1664
0
                        .unpack();
1665
1666
                    // The entry was deleted, keep probing.
1667
0
                    if found.ptr.is_null() {
1668
0
                        probe.next(table.mask);
1669
0
                        continue 'probe;
1670
0
                    }
1671
1672
                    // If the key matches, we might be able to update the value.
1673
0
                    found
1674
                }
1675
                // Otherwise, continue probing.
1676
                else {
1677
0
                    probe.next(table.mask);
1678
0
                    continue 'probe;
1679
                };
1680
1681
                // Check for a full match.
1682
                //
1683
                // Safety: We performed a protected load of the pointer using a verified guard with
1684
                // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
1685
                // as we hold the guard.
1686
0
                if unsafe { (*entry.ptr).key != *new_entry.key() } {
1687
0
                    probe.next(table.mask);
1688
0
                    continue 'probe;
1689
0
                }
1690
1691
                // The entry is being copied to the new table.
1692
0
                if entry.tag() & Entry::COPYING != 0 {
1693
0
                    break 'probe Some(probe.i);
1694
0
                }
1695
1696
                loop {
1697
                    // Compute the value to insert.
1698
                    //
1699
                    // Safety: `entry` is valid for reads.
1700
0
                    let failure = match unsafe { state.next(Some(entry.ptr)) } {
1701
                        // The operation was aborted.
1702
0
                        Operation::Abort(value) => return Compute::Aborted(value),
1703
1704
                        // Update the value.
1705
0
                        Operation::Insert(value) => {
1706
0
                            let new_entry = new_entry.init();
1707
1708
                            // Safety: `new_entry` was just allocated above and is valid for writes.
1709
0
                            unsafe { (*new_entry).value = MaybeUninit::new(value) }
1710
1711
                            // Try to perform the update.
1712
                            //
1713
                            // Safety:
1714
                            // - `probe.i` is always in-bounds for the table length
1715
                            // - `entry` is a valid non-null entry that we found in the map.
1716
                            // - `new_entry` was initialized above and never shared.
1717
0
                            let status = unsafe {
1718
0
                                self.update_at(probe.i, entry, new_entry.cast(), table, guard)
1719
                            };
1720
1721
0
                            match status {
1722
                                // Successfully updated.
1723
0
                                UpdateStatus::Replaced(entry) => {
1724
                                    // Safety: `entry` is a valid non-null entry that we found in the map
1725
                                    // before replacing it.
1726
0
                                    let entry_ref = unsafe { &(*entry.ptr) };
1727
1728
                                    // Safety: `new_entry` was initialized above.
1729
0
                                    let new_ref = unsafe { &*new_entry.cast::<Entry<K, V>>() };
1730
1731
0
                                    return Compute::Updated {
1732
0
                                        old: (&entry_ref.key, &entry_ref.value),
1733
0
                                        new: (&new_ref.key, &new_ref.value),
1734
0
                                    };
1735
                                }
1736
1737
                                // The update failed.
1738
0
                                failure => {
1739
                                    // Save the previous value.
1740
                                    //
1741
                                    // Safety: `new_entry` was initialized above and was not inserted
1742
                                    // into the map.
1743
0
                                    let value = unsafe { (*new_entry).value.assume_init_read() };
1744
0
                                    state.restore(Some(entry.ptr), Operation::Insert(value));
1745
1746
0
                                    failure
1747
                                }
1748
                            }
1749
                        }
1750
1751
                        // Remove the key from the map.
1752
                        Operation::Remove => {
1753
                            // Try to perform the removal.
1754
                            //
1755
                            // Safety:
1756
                            // - `probe.i` is always in-bounds for the table length
1757
                            // - `entry` is a valid non-null entry that we found in the map.
1758
0
                            let status = unsafe {
1759
0
                                self.update_at(probe.i, entry, Entry::TOMBSTONE, table, guard)
1760
                            };
1761
1762
0
                            match status {
1763
                                // Successfully removed the entry.
1764
0
                                UpdateStatus::Replaced(entry) => {
1765
                                    // Mark the entry as a tombstone.
1766
                                    //
1767
                                    // Note that this might end up being overwritten by the metadata hash
1768
                                    // if the initial insertion is lagging behind, but we avoid the RMW
1769
                                    // and sacrifice reads in the extremely rare case.
1770
                                    unsafe {
1771
0
                                        table
1772
0
                                            .meta(probe.i)
1773
0
                                            .store(meta::TOMBSTONE, Ordering::Release)
1774
                                    };
1775
1776
                                    // Decrement the table length.
1777
0
                                    self.count.get(guard).fetch_sub(1, Ordering::Relaxed);
1778
1779
                                    // Safety: `entry` is a valid non-null entry that we found in the map
1780
                                    // before replacing it.
1781
0
                                    let entry_ref = unsafe { &(*entry.ptr) };
1782
0
                                    return Compute::Removed(&entry_ref.key, &entry_ref.value);
1783
                                }
1784
1785
                                // The remove failed.
1786
0
                                failure => {
1787
                                    // Save the removal operation.
1788
0
                                    state.restore(Some(entry.ptr), Operation::Remove);
1789
1790
0
                                    failure
1791
                                }
1792
                            }
1793
                        }
1794
                    };
1795
1796
0
                    match failure {
1797
                        // The entry is being copied to the new table.
1798
0
                        UpdateStatus::Found(EntryStatus::Copied(_)) => break 'probe Some(probe.i),
1799
1800
                        // The entry was deleted before we could update it.
1801
                        //
1802
                        // We know that at some point during our execution the key was not in the map.
1803
                        UpdateStatus::Found(EntryStatus::Null) => {
1804
                            // Compute the next operation.
1805
                            //
1806
                            // Safety: Insert transitions are always sound.
1807
0
                            match unsafe { state.next(None) } {
1808
0
                                Operation::Insert(value) => {
1809
                                    // Save the computed value.
1810
0
                                    state.restore(None, Operation::Insert(value));
1811
1812
                                    // Continue probing to find an empty slot.
1813
0
                                    probe.next(table.mask);
1814
0
                                    continue 'probe;
1815
                                }
1816
0
                                Operation::Remove => panic!("Cannot remove `None` entry."),
1817
0
                                Operation::Abort(value) => return Compute::Aborted(value),
1818
                            }
1819
                        }
1820
1821
                        // Someone else beat us to the update, retry.
1822
0
                        UpdateStatus::Found(EntryStatus::Value(found)) => entry = found,
1823
1824
0
                        _ => unreachable!(),
1825
                    }
1826
                }
1827
            };
1828
1829
            // Prepare to retry in the next table.
1830
0
            if let Some(next_table) = self.prepare_retry(copying, &mut help_copy, table, guard) {
1831
0
                table = next_table;
1832
0
                continue;
1833
0
            }
1834
1835
            // Otherwise, the key is not in the map.
1836
            //
1837
            // Safety: Insert transitions are always sound.
1838
0
            match unsafe { state.next(None) } {
1839
                // Need to insert into the new table.
1840
0
                op @ Operation::Insert(_) => {
1841
0
                    table = self.prepare_retry_insert(None, &mut help_copy, table, guard);
1842
0
                    state.restore(None, op);
1843
0
                }
1844
                // The operation was aborted.
1845
0
                Operation::Abort(value) => return Compute::Aborted(value),
1846
0
                Operation::Remove => panic!("Cannot remove `None` entry."),
1847
            }
1848
        }
1849
0
    }
1850
}
1851
1852
/// Resize operations.
1853
impl<K, V, S> HashMap<K, V, S>
1854
where
1855
    K: Hash + Eq,
1856
    S: BuildHasher,
1857
{
1858
    /// Allocate the initial table.
1859
    #[cold]
1860
    #[inline(never)]
1861
0
    fn init(&self, capacity: Option<usize>) -> Table<Entry<K, V>> {
1862
        const CAPACITY: usize = 32;
1863
1864
        // Allocate the table and mark it as the root.
1865
0
        let mut new = Table::alloc(capacity.unwrap_or(CAPACITY));
1866
0
        *new.state_mut().status.get_mut() = State::PROMOTED;
1867
1868
        // Race to write the initial table.
1869
0
        match self.table.compare_exchange(
1870
0
            ptr::null_mut(),
1871
0
            new.raw,
1872
0
            Ordering::Release,
1873
0
            Ordering::Acquire,
1874
0
        ) {
1875
            // Successfully initialized the table.
1876
0
            Ok(_) => new,
1877
1878
            // Someone beat us, deallocate our table and use the table that was written.
1879
0
            Err(found) => {
1880
                // Safety: We allocated the table above and never shared it.
1881
0
                unsafe { Table::dealloc(new) }
1882
1883
                // Safety: The table was just initialized.
1884
0
                unsafe { Table::from_raw(found) }
1885
            }
1886
        }
1887
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::init
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::init
1888
1889
    /// Returns the next table, allocating it has not already been created.
1890
    #[cold]
1891
    #[inline(never)]
1892
0
    fn get_or_alloc_next(
1893
0
        &self,
1894
0
        capacity: Option<usize>,
1895
0
        table: Table<Entry<K, V>>,
1896
0
    ) -> Table<Entry<K, V>> {
1897
        // Avoid spinning in tests, which can hide race conditions.
1898
        const SPIN_ALLOC: usize = if cfg!(any(test, debug_assertions)) {
1899
            1
1900
        } else {
1901
            7
1902
        };
1903
1904
        // The next table is already allocated.
1905
0
        if let Some(next) = table.next_table() {
1906
0
            return next;
1907
0
        }
1908
1909
0
        let state = table.state();
1910
1911
        // Otherwise, try to acquire the allocation lock.
1912
        //
1913
        // Unlike in `init`, we do not race here to prevent unnecessary allocator pressure.
1914
0
        let _allocating = match state.allocating.try_lock() {
1915
0
            Ok(lock) => lock,
1916
            // Someone else is currently allocating.
1917
            Err(_) => {
1918
0
                let mut spun = 0;
1919
1920
                // Spin for a bit, waiting for the table to be initialized.
1921
0
                while spun <= SPIN_ALLOC {
1922
0
                    for _ in 0..(spun * spun) {
1923
0
                        hint::spin_loop();
1924
0
                    }
1925
1926
                    // The table was initialized.
1927
0
                    if let Some(next) = table.next_table() {
1928
0
                        return next;
1929
0
                    }
1930
1931
0
                    spun += 1;
1932
                }
1933
1934
                // Otherwise, we have to block.
1935
0
                state.allocating.lock().unwrap()
1936
            }
1937
        };
1938
1939
        // The table was allocated while we were waiting for the lock.
1940
0
        if let Some(next) = table.next_table() {
1941
0
            return next;
1942
0
        }
1943
1944
0
        let current_capacity = table.len();
1945
1946
        // Loading the length here is quite expensive, we may want to consider
1947
        // a probabilistic counter to detect high-deletion workloads.
1948
0
        let active_entries = self.len();
1949
1950
0
        let next_capacity = match cfg!(papaya_stress) {
1951
            // Never grow the table to stress the incremental resizing algorithm.
1952
0
            true => current_capacity,
1953
1954
            // Double the table capacity if we are at least 50% full.
1955
0
            false if active_entries >= (current_capacity >> 1) => current_capacity << 1,
1956
1957
            // Halve the table if we are at most 12.5% full.
1958
            //
1959
            // This heuristic is intentionally pessimistic as unnecessarily shrinking
1960
            // is an expensive operation, but it may change in the future. We also respect
1961
            // the initial capacity to give the user a way to retain a strict minimum table
1962
            // size.
1963
0
            false if active_entries <= (current_capacity >> 3) => {
1964
0
                self.initial_capacity.max(current_capacity >> 1)
1965
            }
1966
1967
            // Otherwise keep the capacity the same.
1968
            //
1969
            // This can occur due to poor hash distribution or frequent cycling of
1970
            // insertions and deletions, in which case we want to avoid continuously
1971
            // growing the table.
1972
0
            false => current_capacity,
1973
        };
1974
1975
0
        let next_capacity = capacity.unwrap_or(next_capacity);
1976
0
        assert!(
1977
0
            next_capacity <= isize::MAX as usize,
1978
            "`HashMap` exceeded maximum capacity"
1979
        );
1980
1981
        // Allocate the new table while holding the lock.
1982
0
        let next = Table::alloc(next_capacity);
1983
0
        state.next.store(next.raw, Ordering::Release);
1984
0
        drop(_allocating);
1985
1986
0
        next
1987
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::get_or_alloc_next
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::get_or_alloc_next
1988
1989
    /// Help along with an existing resize operation, returning the new root table.
1990
    ///
1991
    /// If `copy_all` is `false` in incremental resize mode, this returns the current reference's next
1992
    /// table, not necessarily the new root.
1993
    #[cold]
1994
    #[inline(never)]
1995
0
    fn help_copy(
1996
0
        &self,
1997
0
        copy_all: bool,
1998
0
        table: &Table<Entry<K, V>>,
1999
0
        guard: &impl VerifiedGuard,
2000
0
    ) -> Table<Entry<K, V>> {
2001
0
        match self.resize {
2002
0
            ResizeMode::Blocking => self.help_copy_blocking(table, guard),
2003
0
            ResizeMode::Incremental(chunk) => {
2004
0
                let copied_to = self.help_copy_incremental(chunk, copy_all, guard);
2005
2006
0
                if !copy_all {
2007
                    // If we weren't trying to linearize, we have to write to the next table
2008
                    // even if the copy hasn't completed yet.
2009
0
                    return table.next_table().unwrap();
2010
0
                }
2011
2012
0
                copied_to
2013
            }
2014
        }
2015
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::help_copy::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::help_copy::<_>
2016
2017
    /// Help along the resize operation until it completes and the next table is promoted.
2018
    ///
2019
    /// Should only be called on the root table.
2020
0
    fn help_copy_blocking(
2021
0
        &self,
2022
0
        table: &Table<Entry<K, V>>,
2023
0
        guard: &impl VerifiedGuard,
2024
0
    ) -> Table<Entry<K, V>> {
2025
        // Load the next table.
2026
0
        let mut next = table.next_table().unwrap();
2027
2028
        'copy: loop {
2029
            // Make sure we are copying to the correct table.
2030
0
            while next.state().status.load(Ordering::Relaxed) == State::ABORTED {
2031
0
                next = self.get_or_alloc_next(None, next);
2032
0
            }
2033
2034
            // The copy already completed
2035
0
            if self.try_promote(table, &next, 0, guard) {
2036
0
                return next;
2037
0
            }
2038
2039
0
            let copy_chunk = table.len().min(4096);
2040
2041
            loop {
2042
                // Every entry has already been claimed.
2043
0
                if next.state().claim.load(Ordering::Relaxed) >= table.len() {
2044
0
                    break;
2045
0
                }
2046
2047
                // Claim a chunk to copy.
2048
0
                let copy_start = next.state().claim.fetch_add(copy_chunk, Ordering::Relaxed);
2049
2050
                // Copy our chunk of entries.
2051
0
                let mut copied = 0;
2052
0
                for i in 0..copy_chunk {
2053
0
                    let i = copy_start + i;
2054
2055
0
                    if i >= table.len() {
2056
0
                        break;
2057
0
                    }
2058
2059
                    // Copy the entry.
2060
                    //
2061
                    // Safety: We verified that `i` is in-bounds above.
2062
0
                    if unsafe { !self.copy_at_blocking(i, table, &next, guard) } {
2063
                        // This table doesn't have space for the next entry.
2064
                        //
2065
                        // Abort the current resize.
2066
                        //
2067
                        // Note that the `SeqCst` is necessary to make the store visible
2068
                        // to threads that are unparked.
2069
0
                        next.state().status.store(State::ABORTED, Ordering::SeqCst);
2070
2071
                        // Allocate the next table.
2072
0
                        let allocated = self.get_or_alloc_next(None, next);
2073
2074
                        // Wake anyone waiting for us to finish.
2075
0
                        let state = table.state();
2076
0
                        state.parker.unpark(&state.status);
2077
2078
                        // Retry in a new table.
2079
0
                        next = allocated;
2080
0
                        continue 'copy;
2081
0
                    }
2082
2083
0
                    copied += 1;
2084
                }
2085
2086
                // Are we done?
2087
0
                if self.try_promote(table, &next, copied, guard) {
2088
0
                    return next;
2089
0
                }
2090
2091
                // If the resize was aborted while we were copying, continue in the new table.
2092
0
                if next.state().status.load(Ordering::Relaxed) == State::ABORTED {
2093
0
                    continue 'copy;
2094
0
                }
2095
            }
2096
2097
0
            let state = next.state();
2098
            // We copied all that we can, wait for the table to be promoted.
2099
0
            for spun in 0.. {
2100
                // Avoid spinning in tests, which can hide race conditions.
2101
                const SPIN_WAIT: usize = if cfg!(any(test, debug_assertions)) {
2102
                    1
2103
                } else {
2104
                    7
2105
                };
2106
2107
                // Note that `Acquire` is necessary here to ensure we see the
2108
                // relevant modifications to the root table if see the updated
2109
                // state before parking.
2110
                //
2111
                // Otherwise, `Parker::park` will ensure the necessary synchronization
2112
                // when we are unparked.
2113
0
                let status = state.status.load(Ordering::Acquire);
2114
2115
                // If this copy was aborted, we have to retry in the new table.
2116
0
                if status == State::ABORTED {
2117
0
                    continue 'copy;
2118
0
                }
2119
2120
                // The copy has completed.
2121
0
                if status == State::PROMOTED {
2122
0
                    return next;
2123
0
                }
2124
2125
                // Copy chunks are relatively small and we expect to finish quickly,
2126
                // so spin for a bit before resorting to parking.
2127
0
                if spun <= SPIN_WAIT {
2128
0
                    for _ in 0..(spun * spun) {
2129
0
                        hint::spin_loop();
2130
0
                    }
2131
2132
0
                    continue;
2133
0
                }
2134
2135
                // Park until the table is promoted.
2136
0
                state
2137
0
                    .parker
2138
0
                    .park(&state.status, |status| status == State::PENDING);
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::help_copy_blocking::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>::{closure#0}
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::help_copy_blocking::<_>::{closure#0}
2139
            }
2140
        }
2141
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::help_copy_blocking::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::help_copy_blocking::<_>
2142
2143
    /// Copy the entry at the given index to the new table.
2144
    ///
2145
    /// Returns `true` if the entry was copied into the table or `false` if the table was full.
2146
    ///
2147
    /// # Safety
2148
    ///
2149
    /// The index must be in-bounds for the table.
2150
0
    unsafe fn copy_at_blocking(
2151
0
        &self,
2152
0
        i: usize,
2153
0
        table: &Table<Entry<K, V>>,
2154
0
        next_table: &Table<Entry<K, V>>,
2155
0
        guard: &impl VerifiedGuard,
2156
0
    ) -> bool {
2157
        // Mark the entry as copying.
2158
        //
2159
        // Safety: The caller guarantees that the index is in-bounds.
2160
        //
2161
        // Note that we don't need to protect the returned entry here, because
2162
        // no one is allowed to retire the entry once we put the `COPYING` bit
2163
        // down until it is inserted into the new table.
2164
0
        let entry = unsafe { table.entry(i) }
2165
0
            .fetch_or(Entry::COPYING, Ordering::AcqRel)
2166
0
            .unpack();
2167
2168
        // The entry is a tombstone.
2169
0
        if entry.raw == Entry::TOMBSTONE {
2170
0
            return true;
2171
0
        }
2172
2173
        // There is nothing to copy, we're done.
2174
0
        if entry.ptr.is_null() {
2175
            // Mark as a tombstone so readers avoid having to load the entry.
2176
            //
2177
            // Safety: The caller guarantees that the index is in-bounds.
2178
0
            unsafe { table.meta(i) }.store(meta::TOMBSTONE, Ordering::Release);
2179
0
            return true;
2180
0
        }
2181
2182
        // Copy the value to the new table.
2183
        //
2184
        // Safety: We marked the entry as `COPYING`, ensuring that any updates
2185
        // or removals wait until we complete the copy, and allowing us to get
2186
        // away without a protected load. Additionally, we verified that the
2187
        // entry is non-null, meaning that it is valid for reads.
2188
        unsafe {
2189
0
            self.insert_copy(entry.ptr.unpack(), false, next_table, guard)
2190
0
                .is_some()
2191
        }
2192
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::copy_at_blocking::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::copy_at_blocking::<_>
2193
2194
    /// Help along an in-progress resize incrementally by copying a chunk of entries.
2195
    ///
2196
    /// Returns the table that was copied to.
2197
0
    fn help_copy_incremental(
2198
0
        &self,
2199
0
        chunk: usize,
2200
0
        block: bool,
2201
0
        guard: &impl VerifiedGuard,
2202
0
    ) -> Table<Entry<K, V>> {
2203
        // Always help the highest priority root resize.
2204
0
        let table = self.root(guard);
2205
2206
        // Load the next table.
2207
0
        let Some(next) = table.next_table() else {
2208
            // The copy we tried to help was already promoted.
2209
0
            return table;
2210
        };
2211
2212
        loop {
2213
            // The copy already completed.
2214
0
            if self.try_promote(&table, &next, 0, guard) {
2215
0
                return next;
2216
0
            }
2217
2218
            loop {
2219
                // Every entry has already been claimed.
2220
0
                if next.state().claim.load(Ordering::Relaxed) >= table.len() {
2221
0
                    break;
2222
0
                }
2223
2224
                // Claim a chunk to copy.
2225
0
                let copy_start = next.state().claim.fetch_add(chunk, Ordering::Relaxed);
2226
2227
                // Copy our chunk of entries.
2228
0
                let mut copied = 0;
2229
0
                for i in 0..chunk {
2230
0
                    let i = copy_start + i;
2231
2232
0
                    if i >= table.len() {
2233
0
                        break;
2234
0
                    }
2235
2236
                    // Copy the entry.
2237
                    //
2238
                    // Safety: We verified that `i` is in-bounds above.
2239
0
                    unsafe { self.copy_at_incremental(i, &table, &next, guard) };
2240
0
                    copied += 1;
2241
                }
2242
2243
                // Update the copy state, and try to promote the table.
2244
                //
2245
                // Only copy a single chunk if promotion fails, unless we are forced
2246
                // to complete the resize.
2247
0
                if self.try_promote(&table, &next, copied, guard) || !block {
2248
0
                    return next;
2249
0
                }
2250
            }
2251
2252
            // There are no entries that we can copy, block if necessary.
2253
0
            if !block {
2254
0
                return next;
2255
0
            }
2256
2257
0
            let state = next.state();
2258
0
            for spun in 0.. {
2259
                // Avoid spinning in tests, which can hide race conditions.
2260
                const SPIN_WAIT: usize = if cfg!(any(test, debug_assertions)) {
2261
                    1
2262
                } else {
2263
                    7
2264
                };
2265
2266
                // The copy has completed.
2267
                //
2268
                // Note that `Acquire` is necessary here to ensure we see the
2269
                // relevant modifications to the root table if see the updated
2270
                // state before parking.
2271
                //
2272
                // Otherwise, `Parker::park` will ensure the necessary synchronization
2273
                // when we are unparked.
2274
0
                let status = state.status.load(Ordering::Acquire);
2275
0
                if status == State::PROMOTED {
2276
0
                    return next;
2277
0
                }
2278
2279
                // Copy chunks are relatively small and we expect to finish quickly,
2280
                // so spin for a bit before resorting to parking.
2281
0
                if spun <= SPIN_WAIT {
2282
0
                    for _ in 0..(spun * spun) {
2283
0
                        hint::spin_loop();
2284
0
                    }
2285
2286
0
                    continue;
2287
0
                }
2288
2289
                // Park until the table is promoted.
2290
0
                state
2291
0
                    .parker
2292
0
                    .park(&state.status, |status| status == State::PENDING);
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::help_copy_incremental::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>::{closure#0}
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::help_copy_incremental::<_>::{closure#0}
2293
            }
2294
        }
2295
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::help_copy_incremental::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::help_copy_incremental::<_>
2296
2297
    /// Copy the entry at the given index to the new table.
2298
    ///
2299
    /// # Safety
2300
    ///
2301
    /// The index must be in-bounds for the table.
2302
0
    unsafe fn copy_at_incremental(
2303
0
        &self,
2304
0
        i: usize,
2305
0
        table: &Table<Entry<K, V>>,
2306
0
        next_table: &Table<Entry<K, V>>,
2307
0
        guard: &impl VerifiedGuard,
2308
0
    ) {
2309
        // Safety: The caller guarantees that the index is in-bounds.
2310
0
        let entry = unsafe { table.entry(i) };
2311
2312
        // Mark the entry as copying.
2313
0
        let found = entry.fetch_or(Entry::COPYING, Ordering::AcqRel).unpack();
2314
2315
        // The entry is a tombstone.
2316
0
        if found.raw == Entry::TOMBSTONE {
2317
0
            return;
2318
0
        }
2319
2320
        // There is nothing to copy, we're done.
2321
0
        if found.ptr.is_null() {
2322
            // Mark as a tombstone so readers avoid having to load the entry.
2323
            //
2324
            // Safety: The caller guarantees that the index is in-bounds.
2325
0
            unsafe { table.meta(i) }.store(meta::TOMBSTONE, Ordering::Release);
2326
0
            return;
2327
0
        }
2328
2329
        // Mark the entry as borrowed so writers in the new table know it was copied.
2330
0
        let new_entry = found.map_tag(|addr| addr | Entry::BORROWED);
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::copy_at_incremental::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>::{closure#0}
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::copy_at_incremental::<_>::{closure#0}
2331
2332
        // Copy the value to the new table.
2333
        //
2334
        // Safety: We marked the entry as `COPYING`, ensuring that any updates
2335
        // or removals wait until we complete the copy, and allowing us to get
2336
        // away without a protected load. Additionally, we verified that the
2337
        // entry is non-null, meaning that it is valid for reads.
2338
0
        unsafe {
2339
0
            self.insert_copy(new_entry, true, next_table, guard)
2340
0
                .unwrap();
2341
0
        }
2342
2343
        // Mark the entry as copied.
2344
0
        let copied = found
2345
0
            .raw
2346
0
            .map_addr(|addr| addr | Entry::COPYING | Entry::COPIED);
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::copy_at_incremental::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>::{closure#1}
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::copy_at_incremental::<_>::{closure#1}
2347
2348
        // Note that we already wrote the COPYING bit, so no one is writing to the old
2349
        // entry except us.
2350
        //
2351
        // Note that the `SeqCst` is necessary to make the store visible to threads
2352
        // that are unparked.
2353
0
        entry.store(copied, Ordering::SeqCst);
2354
2355
        // Notify any writers that the copy has completed.
2356
0
        table.state().parker.unpark(entry);
2357
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::copy_at_incremental::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::copy_at_incremental::<_>
2358
2359
    // Copy an entry into the table, returning the index it was inserted into.
2360
    //
2361
    // This is an optimized version of `insert_entry` where the caller is the only writer
2362
    // inserting the given key into the new table, as it has already been marked as copying.
2363
    //
2364
    // # Safety
2365
    //
2366
    // The new entry must be valid for reads.
2367
0
    unsafe fn insert_copy(
2368
0
        &self,
2369
0
        new_entry: Tagged<Entry<K, V>>,
2370
0
        resize: bool,
2371
0
        table: &Table<Entry<K, V>>,
2372
0
        guard: &impl VerifiedGuard,
2373
0
    ) -> Option<(Table<Entry<K, V>>, usize)> {
2374
        // Safety: The new entry is guaranteed to be valid for reads.
2375
0
        let key = unsafe { &(*new_entry.ptr).key };
2376
2377
0
        let mut table = *table;
2378
0
        let (h1, h2) = self.hash(key);
2379
2380
        loop {
2381
            // Initialize the probe state.
2382
0
            let mut probe = Probe::start(h1, table.mask);
2383
2384
            // Probe until we reach the limit.
2385
0
            while probe.len <= table.limit {
2386
                // Safety: `probe.i` is always in-bounds for the table length.
2387
0
                let meta_entry = unsafe { table.meta(probe.i) };
2388
2389
                // Load the entry metadata first for cheap searches.
2390
0
                let meta = meta_entry.load(Ordering::Acquire);
2391
2392
                // The entry is empty, try to insert.
2393
0
                if meta == meta::EMPTY {
2394
                    // Safety: `probe.i` is always in-bounds for the table length.
2395
0
                    let entry = unsafe { table.entry(probe.i) };
2396
2397
                    // Try to claim the entry.
2398
0
                    match guard.compare_exchange(
2399
0
                        entry,
2400
0
                        ptr::null_mut(),
2401
0
                        new_entry.raw,
2402
0
                        Ordering::Release,
2403
0
                        Ordering::Acquire,
2404
0
                    ) {
2405
                        // Successfully inserted.
2406
                        Ok(_) => {
2407
                            // Update the metadata table.
2408
0
                            meta_entry.store(h2, Ordering::Release);
2409
0
                            return Some((table, probe.i));
2410
                        }
2411
0
                        Err(found) => {
2412
0
                            let found = found.unpack();
2413
2414
                            // The entry was deleted or copied.
2415
0
                            let meta = if found.ptr.is_null() {
2416
0
                                meta::TOMBSTONE
2417
                            } else {
2418
                                // Safety: We performed a protected load of the pointer using a verified guard with
2419
                                // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
2420
                                // as we hold the guard.
2421
0
                                let found_ref = unsafe { &(*found.ptr) };
2422
2423
                                // Ensure the meta table is updated to avoid breaking the probe chain.
2424
0
                                let hash = self.hasher.hash_one(&found_ref.key);
2425
0
                                meta::h2(hash)
2426
                            };
2427
2428
0
                            if meta_entry.load(Ordering::Relaxed) == meta::EMPTY {
2429
0
                                meta_entry.store(meta, Ordering::Release);
2430
0
                            }
2431
                        }
2432
                    }
2433
0
                }
2434
2435
                // Continue probing.
2436
0
                probe.next(table.mask);
2437
            }
2438
2439
0
            if !resize {
2440
0
                return None;
2441
0
            }
2442
2443
            // Insert into the next table.
2444
0
            table = self.get_or_alloc_next(None, table);
2445
        }
2446
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::insert_copy::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::insert_copy::<_>
2447
2448
    // Update the copy state and attempt to promote a table to the root.
2449
    //
2450
    // Returns `true` if the table was promoted.
2451
0
    fn try_promote(
2452
0
        &self,
2453
0
        table: &Table<Entry<K, V>>,
2454
0
        next: &Table<Entry<K, V>>,
2455
0
        copied: usize,
2456
0
        guard: &impl VerifiedGuard,
2457
0
    ) -> bool {
2458
0
        let state = next.state();
2459
2460
        // Update the copy count.
2461
0
        let copied = if copied > 0 {
2462
0
            state.copied.fetch_add(copied, Ordering::AcqRel) + copied
2463
        } else {
2464
0
            state.copied.load(Ordering::Acquire)
2465
        };
2466
2467
        // If we copied all the entries in the table, we can try to promote.
2468
0
        if copied == table.len() {
2469
0
            let root = self.table.load(Ordering::Relaxed);
2470
2471
            // Only promote root copies.
2472
            //
2473
            // We can't promote a nested copy before it's parent has finished, as
2474
            // it may not contain all the entries in the table.
2475
0
            if table.raw == root {
2476
                // Try to update the root.
2477
0
                if self
2478
0
                    .table
2479
0
                    .compare_exchange(table.raw, next.raw, Ordering::Release, Ordering::Acquire)
2480
0
                    .is_ok()
2481
                {
2482
                    // Successfully promoted the table.
2483
                    //
2484
                    // Note that the `SeqCst` is necessary to make the store visible to threads
2485
                    // that are unparked.
2486
0
                    state.status.store(State::PROMOTED, Ordering::SeqCst);
2487
2488
                    // Retire the old table.
2489
                    //
2490
                    // Safety: `table.raw` is a valid pointer to the table we just copied from.
2491
                    // Additionally, the CAS above made the previous table unreachable from the
2492
                    // root pointer, allowing it to be safely retired.
2493
                    unsafe {
2494
0
                        guard.defer_retire(table.raw, |table, collector| {
2495
                            // Note that we do not drop entries because they have been copied to
2496
                            // the new root.
2497
0
                            drop_table(Table::from_raw(table), collector);
2498
0
                        });
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::try_promote::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>::{closure#0}
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::try_promote::<_>::{closure#0}
2499
                    }
2500
0
                }
2501
2502
                // Wake up any writers waiting for the resize to complete.
2503
0
                state.parker.unpark(&state.status);
2504
0
                return true;
2505
0
            }
2506
0
        }
2507
2508
        // Not ready to promote yet.
2509
0
        false
2510
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::try_promote::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::try_promote::<_>
2511
2512
    // Completes all pending copies in incremental mode to get a clean copy of the table.
2513
    //
2514
    // This is necessary for operations like `iter` or `clear`, where entries in multiple tables
2515
    // can cause lead to incomplete results.
2516
    #[inline]
2517
0
    fn linearize(
2518
0
        &self,
2519
0
        mut table: Table<Entry<K, V>>,
2520
0
        guard: &impl VerifiedGuard,
2521
0
    ) -> Table<Entry<K, V>> {
2522
0
        if self.is_incremental() {
2523
            // If we're in incremental resize mode, we need to complete any in-progress resizes to
2524
            // ensure we don't miss any entries in the next table. We can't iterate over both because
2525
            // we risk returning the same entry twice.
2526
0
            while table.next_table().is_some() {
2527
0
                table = self.help_copy(true, &table, guard);
2528
0
            }
2529
0
        }
2530
2531
0
        table
2532
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::linearize::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::linearize::<_>
2533
2534
    // Wait for an incremental copy of a given entry to complete.
2535
    #[cold]
2536
    #[inline(never)]
2537
0
    fn wait_copied(&self, i: usize, table: &Table<Entry<K, V>>) {
2538
        // Avoid spinning in tests, which can hide race conditions.
2539
        const SPIN_WAIT: usize = if cfg!(any(test, debug_assertions)) {
2540
            1
2541
        } else {
2542
            5
2543
        };
2544
2545
0
        let entry = unsafe { table.entry(i) };
2546
2547
        // Spin for a short while, waiting for the entry to be copied.
2548
0
        for spun in 0..SPIN_WAIT {
2549
            // The entry was copied.
2550
0
            let entry = entry.load(Ordering::Acquire).unpack();
2551
0
            if entry.tag() & Entry::COPIED != 0 {
2552
0
                return;
2553
0
            }
2554
2555
0
            for _ in 0..(spun * spun) {
2556
0
                hint::spin_loop();
2557
0
            }
2558
        }
2559
2560
        // Park until the copy completes.
2561
0
        let parker = &table.state().parker;
2562
0
        parker.park(entry, |entry| entry.addr() & Entry::COPIED == 0);
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::wait_copied::{closure#0}
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::wait_copied::{closure#0}
2563
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::wait_copied
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::wait_copied
2564
2565
    /// Retire an entry that was removed from the current table, but may still be reachable from
2566
    /// previous tables.
2567
    ///
2568
    /// # Safety
2569
    ///
2570
    /// The entry must be a valid pointer that is unreachable from the current table. Additionally,
2571
    /// it is *undefined behavior* to call this method multiple times for the same entry.
2572
    #[inline]
2573
0
    unsafe fn defer_retire(
2574
0
        &self,
2575
0
        entry: Tagged<Entry<K, V>>,
2576
0
        table: &Table<Entry<K, V>>,
2577
0
        guard: &impl VerifiedGuard,
2578
0
    ) {
2579
0
        match self.resize {
2580
            // Safety: In blocking resize mode, we only ever write to the root table, so the entry
2581
            // is inaccessible from all tables.
2582
0
            ResizeMode::Blocking => unsafe {
2583
0
                guard.defer_retire(entry.ptr, seize::reclaim::boxed);
2584
0
            },
2585
            // In incremental resize mode, the entry may be accessible in previous tables.
2586
            ResizeMode::Incremental(_) => {
2587
0
                if entry.tag() & Entry::BORROWED == 0 {
2588
                    // Safety: If the entry is not borrowed, meaning it is not in any previous tables,
2589
                    // it is inaccessible even if the current table is not root. Thus we can safely retire.
2590
0
                    unsafe { guard.defer_retire(entry.ptr, seize::reclaim::boxed) };
2591
0
                    return;
2592
0
                }
2593
2594
0
                let root = self.root(guard);
2595
2596
                // Check if our table, or any subsequent table, is the root.
2597
0
                let mut next = Some(*table);
2598
0
                while let Some(table) = next {
2599
0
                    if table.raw == root.raw {
2600
                        // Safety: The root table is our table or a table that succeeds ours.
2601
                        // Thus any previous tables are unreachable from the root, so we can safely retire.
2602
0
                        unsafe { guard.defer_retire(entry.ptr, seize::reclaim::boxed) };
2603
0
                        return;
2604
0
                    }
2605
2606
0
                    next = table.next_table();
2607
                }
2608
2609
                // Otherwise, we have to wait for the table we are copying from to be reclaimed.
2610
                //
2611
                // Find the table we are copying from, searching from the root.
2612
0
                let mut prev = root;
2613
2614
                loop {
2615
0
                    let next = prev.next_table().unwrap();
2616
2617
                    // Defer the entry to be retired by the table we are copying from.
2618
0
                    if next.raw == table.raw {
2619
0
                        prev.state().deferred.push(entry.ptr);
2620
0
                        return;
2621
0
                    }
2622
2623
0
                    prev = next;
2624
                }
2625
            }
2626
        }
2627
0
    }
Unexecuted instantiation: <papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState>>::defer_retire::<papaya::raw::utils::MapGuard<seize::guard::LocalGuard>>
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _>>::defer_retire::<_>
2628
}
2629
2630
// An iterator over the keys and values of this table.
2631
pub struct Iter<'g, K, V, G> {
2632
    i: usize,
2633
    table: Table<Entry<K, V>>,
2634
    guard: &'g G,
2635
}
2636
2637
impl<'g, K: 'g, V: 'g, G> Iterator for Iter<'g, K, V, G>
2638
where
2639
    G: VerifiedGuard,
2640
{
2641
    type Item = (&'g K, &'g V);
2642
2643
    #[inline]
2644
162
    fn next(&mut self) -> Option<Self::Item> {
2645
        // The table has not yet been allocated.
2646
162
        if self.table.raw.is_null() {
2647
162
            return None;
2648
0
        }
2649
2650
        loop {
2651
            // Iterated over every entry in the table, we're done.
2652
0
            if self.i >= self.table.len() {
2653
0
                return None;
2654
0
            }
2655
2656
            // Load the entry metadata first to ensure consistency with calls to `get`.
2657
            //
2658
            // Safety: We verified that `self.i` is in-bounds above.
2659
0
            let meta = unsafe { self.table.meta(self.i) }.load(Ordering::Acquire);
2660
2661
            // The entry is empty or deleted.
2662
0
            if matches!(meta, meta::EMPTY | meta::TOMBSTONE) {
2663
0
                self.i += 1;
2664
0
                continue;
2665
0
            }
2666
2667
            // Load the entry.
2668
            //
2669
            // Safety: We verified that `self.i` is in-bounds above.
2670
0
            let entry = self
2671
0
                .guard
2672
0
                .protect(unsafe { self.table.entry(self.i) }, Ordering::Acquire)
2673
0
                .unpack();
2674
2675
            // The entry was deleted.
2676
0
            if entry.ptr.is_null() {
2677
0
                self.i += 1;
2678
0
                continue;
2679
0
            }
2680
2681
            // Safety: We performed a protected load of the pointer using a verified guard with
2682
            // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
2683
            // as we hold the guard.
2684
0
            let entry_ref = unsafe { &(*entry.ptr) };
2685
2686
0
            self.i += 1;
2687
0
            return Some((&entry_ref.key, &entry_ref.value));
2688
        }
2689
162
    }
<papaya::raw::Iter<bytes::bytes::Bytes, (), papaya::raw::utils::MapGuard<seize::guard::LocalGuard>> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
2644
162
    fn next(&mut self) -> Option<Self::Item> {
2645
        // The table has not yet been allocated.
2646
162
        if self.table.raw.is_null() {
2647
162
            return None;
2648
0
        }
2649
2650
        loop {
2651
            // Iterated over every entry in the table, we're done.
2652
0
            if self.i >= self.table.len() {
2653
0
                return None;
2654
0
            }
2655
2656
            // Load the entry metadata first to ensure consistency with calls to `get`.
2657
            //
2658
            // Safety: We verified that `self.i` is in-bounds above.
2659
0
            let meta = unsafe { self.table.meta(self.i) }.load(Ordering::Acquire);
2660
2661
            // The entry is empty or deleted.
2662
0
            if matches!(meta, meta::EMPTY | meta::TOMBSTONE) {
2663
0
                self.i += 1;
2664
0
                continue;
2665
0
            }
2666
2667
            // Load the entry.
2668
            //
2669
            // Safety: We verified that `self.i` is in-bounds above.
2670
0
            let entry = self
2671
0
                .guard
2672
0
                .protect(unsafe { self.table.entry(self.i) }, Ordering::Acquire)
2673
0
                .unpack();
2674
2675
            // The entry was deleted.
2676
0
            if entry.ptr.is_null() {
2677
0
                self.i += 1;
2678
0
                continue;
2679
0
            }
2680
2681
            // Safety: We performed a protected load of the pointer using a verified guard with
2682
            // `Acquire` and ensured that it is non-null, meaning it is valid for reads as long
2683
            // as we hold the guard.
2684
0
            let entry_ref = unsafe { &(*entry.ptr) };
2685
2686
0
            self.i += 1;
2687
0
            return Some((&entry_ref.key, &entry_ref.value));
2688
        }
2689
162
    }
Unexecuted instantiation: <papaya::raw::Iter<_, _, _> as core::iter::traits::iterator::Iterator>::next
2690
}
2691
2692
// Safety: An iterator holds a shared reference to the HashMap
2693
// and Guard, and outputs shared references to keys and values.
2694
// Thus everything must be `Sync` for the iterator to be `Send`
2695
// or `Sync`.
2696
//
2697
// It is not possible to obtain an owned key, value, or guard
2698
// from an iterator, so `Send` is not a required bound.
2699
unsafe impl<K, V, G> Send for Iter<'_, K, V, G>
2700
where
2701
    K: Sync,
2702
    V: Sync,
2703
    G: Sync,
2704
{
2705
}
2706
2707
unsafe impl<K, V, G> Sync for Iter<'_, K, V, G>
2708
where
2709
    K: Sync,
2710
    V: Sync,
2711
    G: Sync,
2712
{
2713
}
2714
2715
impl<K, V, G> Clone for Iter<'_, K, V, G> {
2716
    #[inline]
2717
0
    fn clone(&self) -> Self {
2718
0
        Iter {
2719
0
            i: self.i,
2720
0
            table: self.table,
2721
0
            guard: self.guard,
2722
0
        }
2723
0
    }
2724
}
2725
2726
impl<K, V, S> Drop for HashMap<K, V, S> {
2727
24.9k
    fn drop(&mut self) {
2728
24.9k
        let mut raw = *self.table.get_mut();
2729
2730
        // Make sure all objects are reclaimed before the collector is dropped.
2731
        //
2732
        // Dropping a table depends on accessing the collector for deferred retirement,
2733
        // using the shared collector pointer that is invalidated by drop.
2734
        //
2735
        // Safety: We have a unique reference to the collector.
2736
24.9k
        unsafe { self.collector.reclaim_all() };
2737
2738
        // Drop all nested tables and entries.
2739
24.9k
        while !raw.is_null() {
2740
0
            // Safety: The root and next tables are always valid pointers to a
2741
0
            // table allocation, or null.
2742
0
            let mut table = unsafe { Table::from_raw(raw) };
2743
0
2744
0
            // Read the next table pointer before dropping the current one.
2745
0
            let next = *table.state_mut().next.get_mut();
2746
0
2747
0
            // Safety: We have unique access to the table and do
2748
0
            // not access the entries after this call.
2749
0
            unsafe { drop_entries(table) };
2750
0
2751
0
            // Safety: We have unique access to the table and do
2752
0
            // not access it after this call.
2753
0
            unsafe { drop_table(table, &self.collector) };
2754
0
2755
0
            // Continue for all nested tables.
2756
0
            raw = next;
2757
0
        }
2758
24.9k
    }
<papaya::raw::HashMap<bytes::bytes::Bytes, (), std::hash::random::RandomState> as core::ops::drop::Drop>::drop
Line
Count
Source
2727
24.9k
    fn drop(&mut self) {
2728
24.9k
        let mut raw = *self.table.get_mut();
2729
2730
        // Make sure all objects are reclaimed before the collector is dropped.
2731
        //
2732
        // Dropping a table depends on accessing the collector for deferred retirement,
2733
        // using the shared collector pointer that is invalidated by drop.
2734
        //
2735
        // Safety: We have a unique reference to the collector.
2736
24.9k
        unsafe { self.collector.reclaim_all() };
2737
2738
        // Drop all nested tables and entries.
2739
24.9k
        while !raw.is_null() {
2740
0
            // Safety: The root and next tables are always valid pointers to a
2741
0
            // table allocation, or null.
2742
0
            let mut table = unsafe { Table::from_raw(raw) };
2743
0
2744
0
            // Read the next table pointer before dropping the current one.
2745
0
            let next = *table.state_mut().next.get_mut();
2746
0
2747
0
            // Safety: We have unique access to the table and do
2748
0
            // not access the entries after this call.
2749
0
            unsafe { drop_entries(table) };
2750
0
2751
0
            // Safety: We have unique access to the table and do
2752
0
            // not access it after this call.
2753
0
            unsafe { drop_table(table, &self.collector) };
2754
0
2755
0
            // Continue for all nested tables.
2756
0
            raw = next;
2757
0
        }
2758
24.9k
    }
Unexecuted instantiation: <papaya::raw::HashMap<_, _, _> as core::ops::drop::Drop>::drop
2759
}
2760
2761
// Drop all entries in this table.
2762
//
2763
// # Safety
2764
//
2765
// The table entries must not be accessed after this call.
2766
0
unsafe fn drop_entries<K, V>(table: Table<Entry<K, V>>) {
2767
0
    for i in 0..table.len() {
2768
        // Safety: `i` is in-bounds and we have unique access to the table.
2769
0
        let entry = unsafe { (*table.entry(i).as_ptr()).unpack() };
2770
2771
        // The entry was copied, or there is nothing to deallocate.
2772
0
        if entry.ptr.is_null() || entry.tag() & Entry::COPYING != 0 {
2773
0
            continue;
2774
0
        }
2775
2776
        // Drop the entry.
2777
        //
2778
        // Safety: We verified that the table is non-null and will
2779
        // not be accessed after this call. Additionally, we ensured
2780
        // that the entry is not copied to avoid double freeing entries
2781
        // that may exist in multiple tables.
2782
0
        unsafe { drop(Box::from_raw(entry.ptr)) }
2783
    }
2784
0
}
Unexecuted instantiation: papaya::raw::drop_entries::<bytes::bytes::Bytes, ()>
Unexecuted instantiation: papaya::raw::drop_entries::<_, _>
2785
2786
// Drop the table allocation.
2787
//
2788
// # Safety
2789
//
2790
// The table must not be accessed after this call.
2791
0
unsafe fn drop_table<K, V>(mut table: Table<Entry<K, V>>, collector: &Collector) {
2792
    // Drop any entries that were deferred during an incremental resize.
2793
    //
2794
    // Safety: Entries are deferred after they are made unreachable from the
2795
    // next table during a resize from this table. This table must have been accessible
2796
    // from the root for any entry to have been deferred. Thus it is being retired now,
2797
    // *after* the entry was made inaccessible from the next table. Additionally, for
2798
    // this table to have been retired, it also must no longer be accessible from the root,
2799
    // meaning that the entry has been totally removed from the map, and can be safely
2800
    // retired.
2801
0
    table
2802
0
        .state_mut()
2803
0
        .deferred
2804
0
        .drain(|entry| unsafe { collector.retire(entry, seize::reclaim::boxed) });
Unexecuted instantiation: papaya::raw::drop_table::<bytes::bytes::Bytes, ()>::{closure#0}
Unexecuted instantiation: papaya::raw::drop_table::<_, _>::{closure#0}
2805
2806
    // Deallocate the table.
2807
    //
2808
    // Safety: The caller guarantees that the table will not be accessed after this call.
2809
0
    unsafe { Table::dealloc(table) };
2810
0
}
Unexecuted instantiation: papaya::raw::drop_table::<bytes::bytes::Bytes, ()>
Unexecuted instantiation: papaya::raw::drop_table::<_, _>
2811
2812
// Entry metadata, inspired by `hashbrown`.
2813
mod meta {
2814
    use std::mem;
2815
2816
    // Indicates an empty entry.
2817
    pub const EMPTY: u8 = 0x80;
2818
2819
    // Indicates an entry that has been deleted.
2820
    pub const TOMBSTONE: u8 = u8::MAX;
2821
2822
    // Returns the primary hash for an entry.
2823
    #[inline]
2824
0
    pub fn h1(hash: u64) -> usize {
2825
0
        hash as usize
2826
0
    }
Unexecuted instantiation: papaya::raw::meta::h1
Unexecuted instantiation: papaya::raw::meta::h1
Unexecuted instantiation: papaya::raw::meta::h1
2827
2828
    /// Return a byte of hash metadata, used for cheap searches.
2829
    #[inline]
2830
0
    pub fn h2(hash: u64) -> u8 {
2831
        const MIN_HASH_LEN: usize = if mem::size_of::<usize>() < mem::size_of::<u64>() {
2832
            mem::size_of::<usize>()
2833
        } else {
2834
            mem::size_of::<u64>()
2835
        };
2836
2837
        // Grab the top 7 bits of the hash.
2838
        //
2839
        // While the hash is normally a full 64-bit value, some hash functions
2840
        // (such as fxhash) produce a usize result instead, which means that the
2841
        // top 32 bits are 0 on 32-bit platforms.
2842
0
        let top7 = hash >> (MIN_HASH_LEN * 8 - 7);
2843
0
        (top7 & 0x7f) as u8
2844
0
    }
Unexecuted instantiation: papaya::raw::meta::h2
Unexecuted instantiation: papaya::raw::meta::h2
Unexecuted instantiation: papaya::raw::meta::h2
2845
}