1
use std::alloc::handle_alloc_error;
2
use std::collections::hash_map::RandomState;
3
use std::fmt;
4
use std::hash::BuildHasher;
5
use std::hash::Hash;
6
use std::hash::Hasher;
7
use std::ops::Deref;
8
use std::ptr::NonNull;
9
use std::ptr::addr_eq;
10
#[cfg(debug_assertions)]
11
use std::sync::Arc;
12

            
13
use allocator_api2::alloc::Allocator;
14
use allocator_api2::alloc::Global;
15
use allocator_api2::alloc::Layout;
16
use dashmap::DashSet;
17
use equivalent::Equivalent;
18

            
19
use crate::AllocatorDst;
20
use crate::SliceDst;
21

            
22
/// A handle to an element stored in a [`StablePointerSet`].
23
///
24
/// The handle itself is inert: holding, comparing, hashing and copying it is
25
/// always sound. Reading the pointee, however, is only valid while the element
26
/// is still in its owning set, which the borrow checker does not track — so
27
/// dereferencing goes through the unsafe [`StablePointer::deref`].
28
///
29
/// Comparisons are based on the pointer's address, not the value it points to.
30
///
31
/// Deliberately not `Clone`: duplicating a handle extends the set of pointers
32
/// that must be kept valid, so duplication goes through the unsafe
33
/// [`StablePointer::copy`].
34
#[repr(C)]
35
pub struct StablePointer<T: ?Sized> {
36
    /// The raw pointer to the element.
37
    /// This is a NonNull pointer, which means it is guaranteed to be non-null.
38
    ptr: NonNull<T>,
39

            
40
    /// Keep track of reference counts in debug mode.
41
    #[cfg(debug_assertions)]
42
    reference_counter: Arc<()>,
43
}
44

            
45
/// Check that the Option<StablePointer> is the same size as a usize for release builds.
46
#[cfg(not(debug_assertions))]
47
const _: () = assert!(std::mem::size_of::<Option<StablePointer<usize>>>() == std::mem::size_of::<usize>());
48

            
49
impl<T: ?Sized> StablePointer<T> {
50
    /// Returns true if this is the last reference to the pointer.
51
4
    fn is_last_reference(&self) -> bool {
52
        #[cfg(debug_assertions)]
53
        {
54
            // There is a reference in the table, and the one of `self.ptr`.
55
4
            Arc::strong_count(&self.reference_counter) == 2
56
        }
57
        #[cfg(not(debug_assertions))]
58
        {
59
            true
60
        }
61
4
    }
62

            
63
    /// Creates a new StablePointer from a raw pointer.
64
    ///
65
    /// # Safety
66
    ///
67
    /// The caller must ensure that the pointer is valid and points to a valid T that outlives the StablePointer.
68
3160
    pub unsafe fn from_ptr(ptr: NonNull<T>) -> Self {
69
3160
        Self {
70
3160
            ptr,
71
3160
            #[cfg(debug_assertions)]
72
3160
            reference_counter: Arc::new(()),
73
3160
        }
74
3160
    }
75

            
76
    /// Creates a new StablePointer from a raw pointer while preserving the
77
    /// debug reference counter from another StablePointer.
78
    ///
79
    /// # Safety
80
    ///
81
    /// The caller must ensure that `ptr` points to the same allocation as
82
    /// `source` (potentially with a different pointee type/metadata) and
83
    /// remains valid for at least as long as any derived StablePointer.
84
163476716
    pub unsafe fn from_related_ptr<U: ?Sized>(ptr: NonNull<U>, #[allow(unused)] source: &Self) -> StablePointer<U> {
85
163476716
        StablePointer {
86
163476716
            ptr,
87
163476716
            #[cfg(debug_assertions)]
88
163476716
            reference_counter: source.reference_counter.clone(),
89
163476716
        }
90
163476716
    }
91

            
92
    /// Returns public access to the underlying pointer.
93
172777844
    pub fn ptr(&self) -> NonNull<T> {
94
172777844
        self.ptr
95
172777844
    }
96
}
97

            
98
impl<T: ?Sized> PartialEq for StablePointer<T> {
99
30222678802
    fn eq(&self, other: &Self) -> bool {
100
        // Identity is the pointer address; the pointee is never read here.
101
30222678802
        addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr())
102
30222678802
    }
103
}
104

            
105
impl<T: ?Sized> Eq for StablePointer<T> {}
106

            
107
impl<T: ?Sized> Ord for StablePointer<T> {
108
372506206
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
109
372506206
        self.ptr.as_ptr().cast::<()>().cmp(&(other.ptr.as_ptr().cast::<()>()))
110
372506206
    }
111
}
112

            
113
impl<T: ?Sized> PartialOrd for StablePointer<T> {
114
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
115
        Some(self.cmp(other))
116
    }
117
}
118

            
119
impl<T: ?Sized> Hash for StablePointer<T> {
120
863161946
    fn hash<H: Hasher>(&self, state: &mut H) {
121
863161946
        self.ptr.hash(state);
122
863161946
    }
123
}
124

            
125
unsafe impl<T: ?Sized + Send> Send for StablePointer<T> {}
126
unsafe impl<T: ?Sized + Sync> Sync for StablePointer<T> {}
127

            
128
impl<T: ?Sized> StablePointer<T> {
129
    /// Returns a copy of the StablePointer.
130
    ///
131
    /// # Safety
132
    /// The caller must ensure the pointer points to a valid T that outlives the returned StablePointer.
133
    /// In particular the element must not be removed from the owning [`StablePointerSet`] (nor the set
134
    /// dropped) while the copy is alive, since [`Deref`] dereferences the pointer without any check.
135
33912245575
    pub unsafe fn copy(&self) -> Self {
136
33912245575
        Self {
137
33912245575
            ptr: self.ptr,
138
33912245575
            #[cfg(debug_assertions)]
139
33912245575
            reference_counter: self.reference_counter.clone(),
140
33912245575
        }
141
33912245575
    }
142

            
143
    /// Creates a new StablePointer from a boxed element.
144
188742074
    fn from_entry(entry: &Entry<T>) -> Self {
145
188742074
        Self {
146
188742074
            ptr: entry.ptr,
147
188742074
            #[cfg(debug_assertions)]
148
188742074
            reference_counter: entry.reference_counter.clone(),
149
188742074
        }
150
188742074
    }
151

            
152
    /// Borrows the pointee.
153
    ///
154
    /// # Safety
155
    ///
156
    /// The element must still be present in its owning [`StablePointerSet`] (the
157
    /// set must not have been dropped, nor the element removed) for the duration
158
    /// of the returned borrow. This is not tracked by the borrow checker.
159
22376299651
    pub unsafe fn deref(&self) -> &T {
160
        // SAFETY: the caller guarantees the pointee outlives the returned borrow.
161
22376299651
        unsafe { self.ptr.as_ref() }
162
22376299651
    }
163
}
164

            
165
impl<T: fmt::Debug + ?Sized> fmt::Debug for StablePointer<T> {
166
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167
        f.debug_tuple("StablePointer").field(&self.ptr).finish()
168
    }
169
}
170

            
171
/// A set that provides stable pointers to its elements.
172
///
173
/// Similar to `IndexedSet` but uses pointers instead of indices for direct access to elements.
174
/// Elements are stored in stable memory locations using a custom allocator, with the hash set maintaining references.
175
///
176
/// The set can use a custom hasher type for potentially better performance based on workload characteristics.
177
/// Uses an allocator for memory management, defaulting to the global allocator.
178
pub struct StablePointerSet<T: ?Sized, S = RandomState, A = Global>
179
where
180
    T: Hash + Eq + SliceDst,
181
    S: BuildHasher + Clone,
182
    A: Allocator + AllocatorDst,
183
{
184
    index: DashSet<Entry<T>, S>,
185

            
186
    allocator: A,
187
}
188

            
189
impl<T: ?Sized> Default for StablePointerSet<T, RandomState, Global>
190
where
191
    T: Hash + Eq + SliceDst,
192
{
193
    fn default() -> Self {
194
        Self::new()
195
    }
196
}
197

            
198
impl<T: ?Sized> StablePointerSet<T, RandomState, Global>
199
where
200
    T: Hash + Eq + SliceDst,
201
{
202
    /// Creates an empty StablePointerSet with the default hasher and global allocator.
203
8
    pub fn new() -> Self {
204
8
        Self {
205
8
            index: DashSet::default(),
206
8
            allocator: Global,
207
8
        }
208
8
    }
209

            
210
    /// Creates an empty StablePointerSet with the specified capacity, default hasher, and global allocator.
211
    pub fn with_capacity(capacity: usize) -> Self {
212
        Self {
213
            index: DashSet::with_capacity_and_hasher(capacity, RandomState::new()),
214
            allocator: Global,
215
        }
216
    }
217
}
218

            
219
impl<T: ?Sized, S> StablePointerSet<T, S, Global>
220
where
221
    T: Hash + Eq + SliceDst,
222
    S: BuildHasher + Clone,
223
{
224
    /// Creates an empty StablePointerSet with the specified hasher and global allocator.
225
    pub fn with_hasher(hasher: S) -> Self {
226
        Self {
227
            index: DashSet::with_hasher(hasher),
228
            allocator: Global,
229
        }
230
    }
231

            
232
    /// Creates an empty StablePointerSet with the specified capacity, hasher, and global allocator.
233
1764
    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
234
1764
        Self {
235
1764
            index: DashSet::with_capacity_and_hasher(capacity, hasher),
236
1764
            allocator: Global,
237
1764
        }
238
1764
    }
239
}
240

            
241
impl<T: ?Sized, S, A> StablePointerSet<T, S, A>
242
where
243
    T: Hash + Eq + SliceDst,
244
    S: BuildHasher + Clone,
245
    A: Allocator + AllocatorDst,
246
{
247
    /// Creates an empty StablePointerSet with the specified allocator and default hasher.
248
1
    pub fn new_in(allocator: A) -> Self
249
1
    where
250
1
        S: Default,
251
    {
252
1
        Self {
253
1
            index: DashSet::with_hasher(S::default()),
254
1
            allocator,
255
1
        }
256
1
    }
257

            
258
    /// Creates an empty StablePointerSet with the specified capacity, allocator, and default hasher.
259
    pub fn with_capacity_in(capacity: usize, allocator: A) -> Self
260
    where
261
        S: Default,
262
    {
263
        Self {
264
            index: DashSet::with_capacity_and_hasher(capacity, S::default()),
265
            allocator,
266
        }
267
    }
268

            
269
    /// Creates an empty StablePointerSet with the specified hasher and allocator.
270
1765
    pub fn with_hasher_in(hasher: S, allocator: A) -> Self {
271
1765
        Self {
272
1765
            index: DashSet::with_hasher(hasher),
273
1765
            allocator,
274
1765
        }
275
1765
    }
276

            
277
    /// Creates an empty StablePointerSet with the specified capacity, hasher, and allocator.
278
15876
    pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, allocator: A) -> Self {
279
15876
        Self {
280
15876
            index: DashSet::with_capacity_and_hasher(capacity, hasher),
281
15876
            allocator,
282
15876
        }
283
15876
    }
284

            
285
    /// Returns the number of elements in the set.
286
11722129
    pub fn len(&self) -> usize {
287
11722129
        self.index.len()
288
11722129
    }
289

            
290
    /// Returns true if the set is empty.
291
    pub fn is_empty(&self) -> bool {
292
        self.len() == 0
293
    }
294

            
295
    /// Returns the capacity of the set.
296
    pub fn capacity(&self) -> usize {
297
        self.index.capacity()
298
    }
299

            
300
    /// Inserts an element into the set using an equivalent value.
301
    ///
302
    /// This version takes a reference to an equivalent value and creates the value to insert
303
    /// only if it doesn't already exist in the set. Returns a stable pointer to the element
304
    /// and a boolean indicating whether the element was inserted.
305
6614761
    pub fn insert_equiv<'a, Q>(&self, value: &'a Q) -> (StablePointer<T>, bool)
306
6614761
    where
307
6614761
        Q: Hash + Equivalent<T>,
308
6614761
        T: From<&'a Q>,
309
    {
310
6614761
        debug_assert!(std::mem::size_of::<T>() > 0, "Zero-sized types not supported");
311

            
312
        // Check if we already have this value
313
6614761
        let raw_ptr = self.get(value);
314

            
315
6614761
        if let Some(ptr) = raw_ptr {
316
            // We already have this value, return pointer to existing element
317
6503765
            return (ptr, false);
318
110996
        }
319

            
320
        // Allocate memory for the value
321
110996
        let layout = Layout::new::<T>();
322
110996
        let ptr = self.allocator.allocate(layout).expect("Allocation failed").cast::<T>();
323

            
324
        // Write the value to the allocated memory
325
110996
        unsafe {
326
110996
            ptr.as_ptr().write(value.into());
327
110996
        }
328

            
329
        // Insert new value using allocator
330
110996
        let entry = Entry::new(ptr);
331
110996
        let result = StablePointer::from_entry(&entry);
332

            
333
        // First add to storage, then to index
334
110996
        let inserted = self.index.insert(entry);
335
110996
        if !inserted {
336
            let entry = Entry::new(ptr);
337
            let element = self
338
                .index
339
                .get(&entry)
340
                .expect("Insertion failed, so entry must be in the set");
341

            
342
            // Call the drop function
343
            unsafe { std::ptr::drop_in_place(ptr.as_ptr()) };
344

            
345
            // Remove the entry we just created since it was not inserted
346
            unsafe {
347
                self.allocator.deallocate(ptr.cast(), layout);
348
            }
349

            
350
            return (StablePointer::from_entry(&element), false);
351
110996
        }
352

            
353
        // Insertion succeeded.
354
110996
        (result, true)
355
6614761
    }
356

            
357
    /// Returns `true` if the set contains a value.
358
13
    pub fn contains<Q>(&self, value: &Q) -> bool
359
13
    where
360
13
        T: Eq + Hash,
361
13
        Q: ?Sized + Hash + Equivalent<T>,
362
    {
363
13
        self.get(value).is_some()
364
13
    }
365

            
366
    /// Returns a stable pointer to a value in the set, if present.
367
    ///
368
    /// Searches for a value equal to the provided reference and returns a pointer to the stored element.
369
    /// The returned pointer remains valid until the element is removed from the set.
370
130863182
    pub fn get<Q>(&self, value: &Q) -> Option<StablePointer<T>>
371
130863182
    where
372
130863182
        T: Eq + Hash,
373
130863182
        Q: ?Sized + Hash + Equivalent<T>,
374
    {
375
        // Find the boxed element that contains an equivalent value
376
130863182
        let boxed = self.index.get(&LookUp(value))?;
377

            
378
        // SAFETY: The pointer is valid as long as the set is valid.
379
110759310
        let ptr = StablePointer::from_entry(boxed.key());
380
110759310
        Some(ptr)
381
130863182
    }
382

            
383
    /// Returns an iterator over the elements of the set.
384
    ///
385
    /// # Safety
386
    ///
387
    /// The yielded references borrow into the stable allocations. The caller
388
    /// must ensure no element is removed while a yielded reference is live.
389
2
    pub unsafe fn iter(&self) -> impl Iterator<Item = &T> {
390
        // SAFETY: each pointer is valid while its element remains in the set,
391
        // which the caller upholds per the contract above.
392
8
        self.index.iter().map(|boxed| unsafe { boxed.ptr.as_ref() })
393
2
    }
394

            
395
    /// Removes an element from the set using its stable pointer.
396
    ///
397
    /// Returns true if the element was found and removed.
398
    ///
399
    /// # Safety
400
    ///
401
    /// `pointer` must be the last [`StablePointer`] to the element; removal invalidates every
402
    /// remaining pointer to it, and dereferencing such a pointer afterwards is undefined
403
    /// behaviour. This is only checked in debug builds.
404
4
    pub unsafe fn remove(&self, pointer: StablePointer<T>) -> bool {
405
4
        debug_assert!(
406
4
            pointer.is_last_reference(),
407
            "Pointer must be the last reference to the element"
408
        );
409

            
410
        // SAFETY: This is the last reference to the element, so it is still
411
        // present in the set and safe to dereference.
412
4
        let t = unsafe { pointer.deref() };
413
4
        let result = self.index.remove(&LookUp(t));
414

            
415
4
        if let Some(ptr) = result {
416
            // SAFETY: We have exclusive access during drop and the pointer is valid
417
4
            unsafe {
418
4
                self.drop_and_deallocate_entry(ptr.ptr);
419
4
            }
420
4
            true
421
        } else {
422
            false
423
        }
424
4
    }
425

            
426
    /// Retains only the elements specified by the predicate, modifying the set in-place.
427
    ///
428
    /// The predicate closure is called with a mutable reference to each element and must
429
    /// return true if the element should remain in the set.
430
    ///
431
    /// # Safety
432
    ///
433
    /// It invalidates any StablePointers to removed elements; the caller must guarantee that no
434
    /// such pointer is dereferenced afterwards.
435
6140531
    pub unsafe fn retain<F>(&self, mut predicate: F)
436
6140531
    where
437
6140531
        F: FnMut(&StablePointer<T>) -> bool,
438
    {
439
        // First pass: determine what to keep/remove without modifying the collection
440
57700252
        self.index.retain(|element| {
441
57700252
            let ptr = StablePointer::from_entry(element);
442

            
443
57700252
            if !predicate(&ptr) {
444
                // Note that retain can remove disconnect graphs of elements in
445
                // one go, so it is not necessarily the case that there is only
446
                // one reference to the element.
447

            
448
                // SAFETY: We have exclusive access during drop and the pointer
449
                // is valid
450
19755822
                unsafe {
451
19755822
                    self.drop_and_deallocate_entry(ptr.ptr);
452
19755822
                }
453
19755822
                return false;
454
37944430
            }
455

            
456
37944430
            true
457
57700252
        });
458
6140531
    }
459

            
460
    /// Returns mutable access to the underlying allocator.
461
5582300
    pub fn allocator_mut(&mut self) -> &mut A {
462
5582300
        &mut self.allocator
463
5582300
    }
464

            
465
    /// Drops the element at the given pointer and deallocates its memory.
466
    ///
467
    /// # Safety
468
    ///
469
    /// This requires that ptr can be dereferenced, so it must point to a valid element.
470
19755841
    unsafe fn drop_and_deallocate_entry(&self, ptr: NonNull<T>) {
471
        // SAFETY: We have exclusive access during drop and the pointer is valid
472
19755841
        let length = unsafe { T::length(ptr.as_ref()) };
473
19755841
        unsafe {
474
19755841
            // Drop the value in place before deallocating
475
19755841
            std::ptr::drop_in_place(ptr.as_ptr());
476
19755841
        }
477
19755841
        self.allocator.deallocate_slice_dst(ptr, length);
478
19755841
    }
479
}
480

            
481
impl<T: ?Sized + SliceDst, S, A> StablePointerSet<T, S, A>
482
where
483
    T: Hash + Eq,
484
    S: BuildHasher + Clone,
485
    A: Allocator + AllocatorDst + Sync,
486
{
487
    /// Clears the set, removing all values and invalidating all pointers.
488
    ///
489
    /// # Safety
490
    ///
491
    /// This is unsafe because it invalidates all pointers to the elements in the set; the caller
492
    /// must guarantee that none of them is dereferenced afterwards.
493
    pub unsafe fn clear(&self) {
494
        #[cfg(debug_assertions)]
495
        debug_assert!(
496
            self.index.iter().all(|x| Arc::strong_count(&x.reference_counter) == 1),
497
            "All pointers must be the last reference to the element"
498
        );
499

            
500
        // Manually deallocate all entries before clearing
501
        for entry in self.index.iter() {
502
            // SAFETY: We have exclusive access during drop and the pointer is valid
503
            unsafe {
504
                self.drop_and_deallocate_entry(entry.ptr);
505
            }
506
        }
507

            
508
        self.index.clear();
509
        debug_assert!(self.index.is_empty(), "Index should be empty after clearing");
510
    }
511

            
512
    /// Inserts an element into the set using an equivalent value.
513
    ///
514
    /// This version takes a reference to an equivalent value and creates the
515
    /// value to insert only if it doesn't already exist in the set. Returns a
516
    /// stable pointer to the element and a boolean indicating whether the
517
    /// element was inserted.
518
    ///
519
    /// # Safety
520
    ///
521
    /// construct must fully initialize the value at the given pointer,
522
    /// otherwise it may lead to undefined behavior.
523
    pub unsafe fn insert_equiv_dst<'a, Q, C>(
524
        &self,
525
        value: &'a Q,
526
        length: usize,
527
        construct: C,
528
    ) -> (StablePointer<T>, bool)
529
    where
530
        Q: Hash + Equivalent<T>,
531
        C: Fn(*mut T, &'a Q),
532
    {
533
        // Check if we already have this value
534
        let raw_ptr = self.get(value);
535

            
536
        if let Some(ptr) = raw_ptr {
537
            // We already have this value, return pointer to existing element
538
            return (ptr, false);
539
        }
540

            
541
        // Allocate space for the entry and construct it
542
        let mut ptr = self
543
            .allocator
544
            .allocate_slice_dst::<T>(length)
545
            .unwrap_or_else(|_| handle_alloc_error(Layout::new::<()>()));
546

            
547
        unsafe {
548
            construct(ptr.as_mut(), value);
549
        }
550

            
551
        loop {
552
            let entry = Entry::new(ptr);
553
            let ptr = StablePointer::from_entry(&entry);
554

            
555
            let inserted = self.index.insert(entry);
556
            if !inserted {
557
                // Add the result to the storage, it could be at this point that the entry was inserted by another thread. So
558
                // this insertion might actually fail, in which case we should clean up the created entry and return the old pointer.
559

            
560
                // TODO: I suppose this can go wrong with begin_insert(x); insert(x); remove(x); end_insert(x) chain.
561
                if let Some(existing_ptr) = self.get(value) {
562
                    // SAFETY: We have exclusive access during drop and the pointer is valid
563
                    unsafe {
564
                        self.drop_and_deallocate_entry(ptr.ptr);
565
                    }
566

            
567
                    return (existing_ptr, false);
568
                }
569
            } else {
570
                // Value was successfully inserted
571
                return (ptr, true);
572
            }
573
        }
574
    }
575
}
576

            
577
impl<T, S, A> StablePointerSet<T, S, A>
578
where
579
    T: Hash + Eq + SliceDst,
580
    S: BuildHasher + Clone,
581
    A: Allocator + AllocatorDst,
582
{
583
    /// Inserts an element into the set.
584
    ///
585
    /// If the set did not have this value present, `true` is returned along
586
    /// with a stable pointer to the inserted element.
587
    ///
588
    /// If the set already had this value present, `false` is returned along
589
    /// with a stable pointer to the existing element.
590
124248405
    pub fn insert(&self, value: T) -> (StablePointer<T>, bool) {
591
124248405
        debug_assert!(std::mem::size_of::<T>() > 0, "Zero-sized types not supported");
592

            
593
124248405
        if let Some(ptr) = self.get(&value) {
594
            // We already have this value, return pointer to existing element
595
104255535
            return (ptr, false);
596
19992870
        }
597

            
598
19992870
        let ptr = self
599
19992870
            .allocator
600
19992870
            .allocate(Layout::new::<T>())
601
19992870
            .unwrap_or_else(|_| handle_alloc_error(Layout::new::<T>()))
602
19992870
            .cast::<T>();
603

            
604
19992870
        unsafe {
605
19992870
            ptr.write(value);
606
19992870
        }
607

            
608
        // Insert new value using allocator
609
19992870
        let entry = Entry::new(ptr);
610
19992870
        let ptr = StablePointer::from_entry(&entry);
611

            
612
        // First add to storage, then to index
613
19992870
        let inserted = self.index.insert(entry);
614
19992870
        if !inserted {
615
            let entry = Entry::new(ptr.ptr());
616
            let element = self
617
                .index
618
                .get(&entry)
619
                .expect("Insertion failed, so entry must be in the set");
620

            
621
            // Drop and deallocate the allocation we created since it was not inserted.
622
            unsafe { std::ptr::drop_in_place(ptr.ptr().as_ptr()) };
623
            unsafe { self.allocator.deallocate(ptr.ptr().cast(), Layout::new::<T>()) };
624

            
625
            return (StablePointer::from_entry(&element), false);
626
19992870
        }
627

            
628
19992870
        (ptr, true)
629
124248405
    }
630
}
631

            
632
impl<T: ?Sized, S, A> Drop for StablePointerSet<T, S, A>
633
where
634
    T: Hash + Eq + SliceDst,
635
    S: BuildHasher + Clone,
636
    A: Allocator + AllocatorDst,
637
{
638
10
    fn drop(&mut self) {
639
        #[cfg(debug_assertions)]
640
10
        debug_assert!(
641
15
            self.index.iter().all(|x| Arc::strong_count(&x.reference_counter) == 1),
642
            "All pointers must be the last reference to the element"
643
        );
644

            
645
        // Manually drop and deallocate all entries
646
15
        for entry in self.index.iter() {
647
15
            unsafe {
648
15
                self.drop_and_deallocate_entry(entry.ptr);
649
15
            }
650
        }
651
10
    }
652
}
653

            
654
/// A helper struct to store the allocated element in the set.
655
///
656
/// Uses manual allocation instead of Box for custom allocator support.
657
/// Optionally stores a reference counter for debugging purposes in debug builds.
658
struct Entry<T: ?Sized> {
659
    /// Pointer to the allocated value
660
    ptr: NonNull<T>,
661

            
662
    #[cfg(debug_assertions)]
663
    reference_counter: Arc<()>,
664
}
665

            
666
unsafe impl<T: ?Sized + Send> Send for Entry<T> {}
667
unsafe impl<T: ?Sized + Sync> Sync for Entry<T> {}
668

            
669
impl<T: ?Sized> Entry<T> {
670
    /// Creates a new entry by allocating memory for the value using the provided allocator.
671
20126710
    fn new(ptr: NonNull<T>) -> Self {
672
20126710
        Self {
673
20126710
            ptr,
674
20126710
            #[cfg(debug_assertions)]
675
20126710
            reference_counter: Arc::new(()),
676
20126710
        }
677
20126710
    }
678
}
679

            
680
impl<T: ?Sized> Deref for Entry<T> {
681
    type Target = T;
682

            
683
131305675
    fn deref(&self) -> &Self::Target {
684
        // SAFETY: The pointer is valid as long as the Entry exists
685
131305675
        unsafe { self.ptr.as_ref() }
686
131305675
    }
687
}
688

            
689
impl<T: PartialEq + ?Sized> PartialEq for Entry<T> {
690
70629
    fn eq(&self, other: &Self) -> bool {
691
70629
        **self == **other
692
70629
    }
693
}
694

            
695
impl<T: Hash + ?Sized> Hash for Entry<T> {
696
20166651
    fn hash<H: Hasher>(&self, state: &mut H) {
697
20166651
        (**self).hash(state);
698
20166651
    }
699
}
700

            
701
impl<T: Eq + ?Sized> Eq for Entry<T> {}
702

            
703
/// A helper struct to look up elements in the set using a reference.
704
#[derive(Hash, PartialEq, Eq)]
705
struct LookUp<'a, T: ?Sized>(&'a T);
706

            
707
impl<T: ?Sized, Q: ?Sized> Equivalent<Entry<T>> for LookUp<'_, Q>
708
where
709
    Q: Equivalent<T>,
710
{
711
110839701
    fn equivalent(&self, other: &Entry<T>) -> bool {
712
110839701
        self.0.equivalent(&**other)
713
110839701
    }
714
}
715

            
716
#[cfg(test)]
717
mod tests {
718
    use std::hash::BuildHasherDefault;
719
    use std::hash::Hash;
720
    use std::hash::Hasher;
721
    use std::hash::RandomState;
722

            
723
    use allocator_api2::alloc::System;
724
    use dashmap::Equivalent;
725
    use rustc_hash::FxHasher;
726

            
727
    use crate::StablePointerSet;
728

            
729
    #[test]
730
1
    fn test_insert_and_get() {
731
1
        let set = StablePointerSet::new();
732

            
733
        // Insert a value and ensure we get it back
734
1
        let (ptr1, inserted) = set.insert(42);
735
1
        assert!(inserted);
736
        // SAFETY: the elements live in `set` for the duration of the test.
737
1
        assert_eq!(unsafe { *ptr1.deref() }, 42);
738

            
739
        // Insert the same value and ensure we get the same pointer
740
1
        let (ptr2, inserted) = set.insert(42);
741
1
        assert!(!inserted);
742
1
        assert_eq!(unsafe { *ptr2.deref() }, 42);
743

            
744
        // Pointers to the same value should be identical
745
1
        assert_eq!(ptr1, ptr2);
746

            
747
        // Verify that we have only one element
748
1
        assert_eq!(set.len(), 1);
749
1
    }
750

            
751
    #[test]
752
1
    fn test_contains() {
753
1
        let set = StablePointerSet::new();
754
1
        set.insert(42);
755
1
        set.insert(100);
756

            
757
1
        assert!(set.contains(&42));
758
1
        assert!(set.contains(&100));
759
1
        assert!(!set.contains(&200));
760
1
    }
761

            
762
    #[test]
763
1
    fn test_get() {
764
1
        let set = StablePointerSet::new();
765
1
        set.insert(42);
766
1
        set.insert(100);
767

            
768
1
        let ptr = set.get(&42).expect("Value should exist");
769
        // SAFETY: the elements live in `set` for the duration of the test.
770
1
        assert_eq!(unsafe { *ptr.deref() }, 42);
771

            
772
1
        let ptr = set.get(&100).expect("Value should exist");
773
1
        assert_eq!(unsafe { *ptr.deref() }, 100);
774

            
775
1
        assert!(set.get(&200).is_none(), "Value should not exist");
776
1
    }
777

            
778
    #[test]
779
1
    fn test_iteration() {
780
1
        let set = StablePointerSet::new();
781
1
        set.insert(1);
782
1
        set.insert(2);
783
1
        set.insert(3);
784

            
785
        // SAFETY: no element is removed while the iterator references are live.
786
1
        let mut values: Vec<i32> = unsafe { set.iter() }.copied().collect();
787
1
        values.sort();
788

            
789
1
        assert_eq!(values, vec![1, 2, 3]);
790
1
    }
791

            
792
    #[test]
793
1
    fn test_stable_pointer_set_insert_equiv_ref() {
794
        #[derive(PartialEq, Eq, Debug)]
795
        struct TestValue {
796
            id: i32,
797
            name: String,
798
        }
799

            
800
        impl From<&i32> for TestValue {
801
2
            fn from(id: &i32) -> Self {
802
2
                TestValue {
803
2
                    id: *id,
804
2
                    name: format!("Value-{}", id),
805
2
                }
806
2
            }
807
        }
808

            
809
        impl Hash for TestValue {
810
2
            fn hash<H: Hasher>(&self, state: &mut H) {
811
2
                self.id.hash(state);
812
2
            }
813
        }
814

            
815
        impl Equivalent<TestValue> for i32 {
816
1
            fn equivalent(&self, key: &TestValue) -> bool {
817
1
                *self == key.id
818
1
            }
819
        }
820

            
821
1
        let set: StablePointerSet<TestValue> = StablePointerSet::new();
822

            
823
        // Insert using equivalent reference (i32 -> TestValue)
824
1
        let (ptr1, inserted) = set.insert_equiv(&42);
825
1
        assert!(inserted, "Value should be inserted");
826
        // SAFETY: the elements live in `set` for the duration of the test.
827
1
        assert_eq!(unsafe { ptr1.deref() }.id, 42);
828
1
        assert_eq!(unsafe { ptr1.deref() }.name, "Value-42");
829

            
830
        // Try inserting the same value again via equivalent
831
1
        let (ptr2, inserted) = set.insert_equiv(&42);
832
1
        assert!(!inserted, "Value should not be inserted again");
833
1
        assert_eq!(ptr1, ptr2, "Should return the same pointer");
834

            
835
        // Insert a different value
836
1
        let (ptr3, inserted) = set.insert_equiv(&100);
837
1
        assert!(inserted, "New value should be inserted");
838
1
        assert_eq!(unsafe { ptr3.deref() }.id, 100);
839
1
        assert_eq!(unsafe { ptr3.deref() }.name, "Value-100");
840

            
841
        // Ensure we have exactly two elements
842
1
        assert_eq!(set.len(), 2);
843
1
    }
844

            
845
    #[test]
846
1
    fn test_stable_pointer_deref() {
847
1
        let set = StablePointerSet::new();
848
1
        let (ptr, _) = set.insert(42);
849

            
850
        // Test dereferencing
851
        // SAFETY: the element lives in `set` for the duration of the test.
852
1
        let value: &i32 = unsafe { ptr.deref() };
853
1
        assert_eq!(*value, 42);
854

            
855
        // Test methods on the dereferenced value
856
1
        assert_eq!(unsafe { ptr.deref() }.checked_add(10), Some(52));
857
1
    }
858

            
859
    #[test]
860
1
    fn test_stable_pointer_set_remove() {
861
1
        let set = StablePointerSet::new();
862

            
863
        // Insert values
864
1
        let (ptr1, _) = set.insert(42);
865
1
        let (ptr2, _) = set.insert(100);
866
1
        assert_eq!(set.len(), 2);
867

            
868
        // SAFETY: `ptr1` and `ptr2` are the last pointers to their elements.
869
        unsafe {
870
            // Remove one value
871
1
            assert!(set.remove(ptr1));
872
1
            assert_eq!(set.len(), 1);
873

            
874
            // Remove other value
875
1
            assert!(set.remove(ptr2));
876
1
            assert_eq!(set.len(), 0);
877
        }
878
1
    }
879

            
880
    #[test]
881
1
    fn test_stable_pointer_set_retain() {
882
1
        let set = StablePointerSet::new();
883

            
884
        // Insert values
885
1
        set.insert(1);
886
1
        let (ptr2, _) = set.insert(2);
887
1
        set.insert(3);
888
1
        let (ptr4, _) = set.insert(4);
889
1
        assert_eq!(set.len(), 4);
890

            
891
        // SAFETY: No pointers to the removed (odd) elements are used afterwards,
892
        // and each predicate borrow is only read while the element is present.
893
        unsafe {
894
            // Retain only even numbers
895
4
            set.retain(|x| *x.deref() % 2 == 0);
896
        }
897

            
898
        // Verify results
899
1
        assert_eq!(set.len(), 2);
900
1
        assert!(!set.contains(&1));
901
1
        assert!(set.contains(&2));
902
1
        assert!(!set.contains(&3));
903
1
        assert!(set.contains(&4));
904

            
905
        // SAFETY: `ptr2` and `ptr4` are the last pointers to their elements.
906
        unsafe {
907
            // Verify that removed pointers are invalid and remaining are valid
908
1
            assert!(set.remove(ptr2));
909
1
            assert!(set.remove(ptr4));
910
        }
911
1
    }
912

            
913
    #[test]
914
1
    fn test_stable_pointer_set_custom_allocator() {
915
        // Test with System allocator
916
1
        let set: StablePointerSet<i32, RandomState, System> = StablePointerSet::new_in(System);
917

            
918
        // Insert some values
919
1
        let (ptr1, inserted) = set.insert(42);
920
1
        assert!(inserted);
921
1
        let (ptr2, inserted) = set.insert(100);
922
1
        assert!(inserted);
923

            
924
        // Check that everything works as expected
925
1
        assert_eq!(set.len(), 2);
926
        // SAFETY: the elements live in `set` for the duration of the test.
927
1
        assert_eq!(unsafe { *ptr1.deref() }, 42);
928
1
        assert_eq!(unsafe { *ptr2.deref() }, 100);
929

            
930
        // Test contains
931
1
        assert!(set.contains(&42));
932
1
        assert!(set.contains(&100));
933
1
        assert!(!set.contains(&200));
934
1
    }
935

            
936
    #[test]
937
1
    fn test_stable_pointer_set_custom_hasher_and_allocator() {
938
        // Use both custom hasher and allocator
939
1
        let set: StablePointerSet<i32, BuildHasherDefault<FxHasher>, System> =
940
1
            StablePointerSet::with_hasher_in(BuildHasherDefault::<FxHasher>::default(), System);
941

            
942
        // Insert some values
943
1
        let (ptr1, inserted) = set.insert(42);
944
1
        assert!(inserted);
945
1
        let (ptr2, inserted) = set.insert(100);
946
1
        assert!(inserted);
947

            
948
        // Check that everything works as expected
949
1
        assert_eq!(set.len(), 2);
950
        // SAFETY: the elements live in `set` for the duration of the test.
951
1
        assert_eq!(unsafe { *ptr1.deref() }, 42);
952
1
        assert_eq!(unsafe { *ptr2.deref() }, 100);
953

            
954
        // Test contains
955
1
        assert!(set.contains(&42));
956
1
        assert!(set.contains(&100));
957
1
        assert!(!set.contains(&200));
958
1
    }
959
}