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 safe wrapper around a raw pointer that allows immutable dereferencing. This remains valid as long as the `StablePointerSet` remains
23
/// valid, which is not managed by the borrow checker.
24
///
25
/// Comparisons are based on the pointer's address, not the value it points to.
26
#[repr(C)]
27
#[derive(Clone)]
28
pub struct StablePointer<T: ?Sized> {
29
    /// The raw pointer to the element.
30
    /// This is a NonNull pointer, which means it is guaranteed to be non-null.
31
    ptr: NonNull<T>,
32

            
33
    /// Keep track of reference counts in debug mode.
34
    #[cfg(debug_assertions)]
35
    reference_counter: Arc<()>,
36
}
37

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

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

            
56
    /// Creates a new StablePointer from a raw pointer.
57
    ///
58
    /// # Safety
59
    ///
60
    /// The caller must ensure that the pointer is valid and points to a valid T that outlives the StablePointer.
61
    pub unsafe fn from_ptr(ptr: NonNull<T>) -> Self {
62
        Self {
63
            ptr,
64
            #[cfg(debug_assertions)]
65
            reference_counter: Arc::new(()),
66
        }
67
    }
68

            
69
    /// Returns public access to the underlying pointer.
70
    pub fn ptr(&self) -> NonNull<T> {
71
        self.ptr
72
    }
73
}
74

            
75
impl<T: ?Sized> PartialEq for StablePointer<T> {
76
13170737650
    fn eq(&self, other: &Self) -> bool {
77
        // SAFETY: This is safe because we are comparing pointers, which is a valid operation.
78
13170737650
        addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr())
79
13170737650
    }
80
}
81

            
82
impl<T: ?Sized> Eq for StablePointer<T> {}
83

            
84
impl<T: ?Sized> Ord for StablePointer<T> {
85
160821570
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
86
        // SAFETY: This is safe because we are comparing pointers, which is a valid operation.
87
160821570
        self.ptr.as_ptr().cast::<()>().cmp(&(other.ptr.as_ptr().cast::<()>()))
88
160821570
    }
89
}
90

            
91
impl<T: ?Sized> PartialOrd for StablePointer<T> {
92
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
93
        // SAFETY: This is safe because we are comparing pointers, which is a valid operation.
94
        Some(self.cmp(other))
95
    }
96
}
97

            
98
impl<T: ?Sized> Hash for StablePointer<T> {
99
343728472
    fn hash<H: Hasher>(&self, state: &mut H) {
100
        // SAFETY: This is safe because we are hashing pointers, which is a valid operation.
101
343728472
        self.ptr.hash(state);
102
343728472
    }
103
}
104

            
105
unsafe impl<T: ?Sized + Send> Send for StablePointer<T> {}
106
unsafe impl<T: ?Sized + Sync> Sync for StablePointer<T> {}
107

            
108
impl<T: ?Sized> StablePointer<T> {
109
    /// Returns a copy of the StablePointer.
110
    ///
111
    /// # Safety
112
    /// The caller must ensure the pointer points to a valid T that outlives the returned StablePointer.
113
10675965375
    pub fn copy(&self) -> Self {
114
10675965375
        Self {
115
10675965375
            ptr: self.ptr,
116
10675965375
            #[cfg(debug_assertions)]
117
10675965375
            reference_counter: self.reference_counter.clone(),
118
10675965375
        }
119
10675965375
    }
120

            
121
    /// Creates a new StablePointer from a boxed element.
122
68575047
    fn from_entry(entry: &Entry<T>) -> Self {
123
68575047
        Self {
124
68575047
            ptr: entry.ptr,
125
68575047
            #[cfg(debug_assertions)]
126
68575047
            reference_counter: entry.reference_counter.clone(),
127
68575047
        }
128
68575047
    }
129
}
130

            
131
impl<T: ?Sized> Deref for StablePointer<T> {
132
    type Target = T;
133

            
134
9682736388
    fn deref(&self) -> &Self::Target {
135
        // The caller must ensure the pointer points to a valid T that outlives this StablePointer.
136
9682736388
        unsafe { self.ptr.as_ref() }
137
9682736388
    }
138
}
139

            
140
impl<T: fmt::Debug + ?Sized> fmt::Debug for StablePointer<T> {
141
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142
        f.debug_tuple("StablePointer").field(&self.ptr).finish()
143
    }
144
}
145

            
146
/// A set that provides stable pointers to its elements.
147
///
148
/// Similar to `IndexedSet` but uses pointers instead of indices for direct access to elements.
149
/// Elements are stored in stable memory locations using a custom allocator, with the hash set maintaining references.
150
///
151
/// The set can use a custom hasher type for potentially better performance based on workload characteristics.
152
/// Uses an allocator for memory management, defaulting to the global allocator.
153
pub struct StablePointerSet<T: ?Sized, S = RandomState, A = Global>
154
where
155
    T: Hash + Eq + SliceDst,
156
    S: BuildHasher + Clone,
157
    A: Allocator + AllocatorDst,
158
{
159
    index: DashSet<Entry<T>, S>,
160

            
161
    allocator: A,
162
}
163

            
164
impl<T: ?Sized> Default for StablePointerSet<T, RandomState, Global>
165
where
166
    T: Hash + Eq + SliceDst,
167
{
168
    fn default() -> Self {
169
        Self::new()
170
    }
171
}
172

            
173
impl<T: ?Sized> StablePointerSet<T, RandomState, Global>
174
where
175
    T: Hash + Eq + SliceDst,
176
{
177
    /// Creates an empty StablePointerSet with the default hasher and global allocator.
178
601
    pub fn new() -> Self {
179
601
        Self {
180
601
            index: DashSet::default(),
181
601
            allocator: Global,
182
601
        }
183
601
    }
184

            
185
    /// Creates an empty StablePointerSet with the specified capacity, default hasher, and global allocator.
186
    pub fn with_capacity(capacity: usize) -> Self {
187
        Self {
188
            index: DashSet::with_capacity_and_hasher(capacity, RandomState::new()),
189
            allocator: Global,
190
        }
191
    }
192
}
193

            
194
impl<T: ?Sized, S> StablePointerSet<T, S, Global>
195
where
196
    T: Hash + Eq + SliceDst,
197
    S: BuildHasher + Clone,
198
{
199
    /// Creates an empty StablePointerSet with the specified hasher and global allocator.
200
593
    pub fn with_hasher(hasher: S) -> Self {
201
593
        Self {
202
593
            index: DashSet::with_hasher(hasher),
203
593
            allocator: Global,
204
593
        }
205
593
    }
206

            
207
    /// Creates an empty StablePointerSet with the specified capacity, hasher, and global allocator.
208
    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
209
        Self {
210
            index: DashSet::with_capacity_and_hasher(capacity, hasher),
211
            allocator: Global,
212
        }
213
    }
214
}
215

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

            
233
    /// Creates an empty StablePointerSet with the specified capacity, allocator, and default hasher.
234
593
    pub fn with_capacity_in(capacity: usize, allocator: A) -> Self
235
593
    where
236
593
        S: Default,
237
    {
238
593
        Self {
239
593
            index: DashSet::with_capacity_and_hasher(capacity, S::default()),
240
593
            allocator,
241
593
        }
242
593
    }
243

            
244
    /// Creates an empty StablePointerSet with the specified hasher and allocator.
245
1
    pub fn with_hasher_in(hasher: S, allocator: A) -> Self {
246
1
        Self {
247
1
            index: DashSet::with_hasher(hasher),
248
1
            allocator,
249
1
        }
250
1
    }
251

            
252
    /// Creates an empty StablePointerSet with the specified capacity, hasher, and allocator.
253
    pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, allocator: A) -> Self {
254
        Self {
255
            index: DashSet::with_capacity_and_hasher(capacity, hasher),
256
            allocator,
257
        }
258
    }
259

            
260
    /// Returns the number of elements in the set.
261
140109
    pub fn len(&self) -> usize {
262
140109
        self.index.len()
263
140109
    }
264

            
265
    /// Returns true if the set is empty.
266
    pub fn is_empty(&self) -> bool {
267
        self.len() == 0
268
    }
269

            
270
    /// Returns the capacity of the set.
271
    pub fn capacity(&self) -> usize {
272
        self.index.capacity()
273
    }
274

            
275
    /// Inserts an element into the set using an equivalent value.
276
    ///
277
    /// This version takes a reference to an equivalent value and creates the value to insert
278
    /// only if it doesn't already exist in the set. Returns a stable pointer to the element
279
    /// and a boolean indicating whether the element was inserted.
280
3331646
    pub fn insert_equiv<'a, Q>(&self, value: &'a Q) -> (StablePointer<T>, bool)
281
3331646
    where
282
3331646
        Q: Hash + Equivalent<T>,
283
3331646
        T: From<&'a Q>,
284
    {
285
3331646
        debug_assert!(std::mem::size_of::<T>() > 0, "Zero-sized types not supported");
286

            
287
        // Check if we already have this value
288
3331646
        let raw_ptr = self.get(value);
289

            
290
3331646
        if let Some(ptr) = raw_ptr {
291
            // We already have this value, return pointer to existing element
292
3310148
            return (ptr, false);
293
21498
        }
294

            
295
        // Allocate memory for the value
296
21498
        let layout = Layout::new::<T>();
297
21498
        let ptr = self.allocator.allocate(layout).expect("Allocation failed").cast::<T>();
298

            
299
        // Write the value to the allocated memory
300
21498
        unsafe {
301
21498
            ptr.as_ptr().write(value.into());
302
21498
        }
303

            
304
        // Insert new value using allocator
305
21498
        let entry = Entry::new(ptr);
306
21498
        let result = StablePointer::from_entry(&entry);
307

            
308
        // First add to storage, then to index
309
21498
        let inserted = self.index.insert(entry);
310
21498
        if !inserted {
311
1
            let entry = Entry::new(ptr);
312
1
            let element = self
313
1
                .index
314
1
                .get(&entry)
315
1
                .expect("Insertion failed, so entry must be in the set");
316

            
317
            // Call the drop function
318
1
            unsafe { std::ptr::drop_in_place(ptr.as_ptr()) };
319

            
320
            // Remove the entry we just created since it was not inserted            
321
1
            unsafe { self.allocator.deallocate(ptr.cast(), layout); }
322

            
323

            
324
1
            return (StablePointer::from_entry(&element), false);
325
21497
        }
326

            
327
        // Insertion succeeded.
328
21497
        (result, true)
329
3331646
    }
330

            
331
    /// Returns `true` if the set contains a value.
332
13
    pub fn contains<Q>(&self, value: &Q) -> bool
333
13
    where
334
13
        T: Eq + Hash,
335
13
        Q: ?Sized + Hash + Equivalent<T>,
336
    {
337
13
        self.get(value).is_some()
338
13
    }
339

            
340
    /// Returns a stable pointer to a value in the set, if present.
341
    ///
342
    /// Searches for a value equal to the provided reference and returns a pointer to the stored element.
343
    /// The returned pointer remains valid until the element is removed from the set.
344
57247008
    pub fn get<Q>(&self, value: &Q) -> Option<StablePointer<T>>
345
57247008
    where
346
57247008
        T: Eq + Hash,
347
57247008
        Q: ?Sized + Hash + Equivalent<T>,
348
    {
349
        // Find the boxed element that contains an equivalent value
350
57247008
        let boxed = self.index.get(&LookUp(value))?;
351

            
352
        // SAFETY: The pointer is valid as long as the set is valid.
353
52045093
        let ptr = StablePointer::from_entry(boxed.key());
354
52045093
        Some(ptr)
355
57247008
    }
356

            
357
    /// Returns an iterator over the elements of the set.
358
2
    pub fn iter(&self) -> impl Iterator<Item = &T> {
359
8
        self.index.iter().map(|boxed| unsafe { boxed.ptr.as_ref() })
360
2
    }
361

            
362
    /// Removes an element from the set using its stable pointer.
363
    ///
364
    /// Returns true if the element was found and removed.
365
4
    pub fn remove(&self, pointer: StablePointer<T>) -> bool {
366
4
        debug_assert!(
367
4
            pointer.is_last_reference(),
368
            "Pointer must be the last reference to the element"
369
        );
370

            
371
        // SAFETY: This is the last reference to the element, so it is safe to remove it.
372
4
        let t = pointer.deref();
373
4
        let result = self.index.remove(&LookUp(t));
374

            
375
4
        if let Some(ptr) = result {
376
            // SAFETY: We have exclusive access during drop and the pointer is valid
377
4
            unsafe {
378
4
                self.drop_and_deallocate_entry(ptr.ptr);
379
4
            }
380
4
            true
381
        } else {
382
            false
383
        }
384
4
    }
385

            
386
    /// Retains only the elements specified by the predicate, modifying the set in-place.
387
    ///
388
    /// The predicate closure is called with a mutable reference to each element and must
389
    /// return true if the element should remain in the set.
390
    ///
391
    /// # Safety
392
    ///
393
    /// It invalidates any StablePointers to removed elements
394
56041
    pub fn retain<F>(&self, mut predicate: F)
395
56041
    where
396
56041
        F: FnMut(&StablePointer<T>) -> bool,
397
    {
398
        // First pass: determine what to keep/remove without modifying the collection
399
11252174
        self.index.retain(|element| {
400
11252174
            let ptr = StablePointer::from_entry(element);
401

            
402
11252174
            if !predicate(&ptr) {
403
                // Note that retain can remove disconnect graphs of elements in
404
                // one go, so it is not necessarily the case that there is only
405
                // one reference to the element.
406

            
407
                // SAFETY: We have exclusive access during drop and the pointer
408
                // is valid
409
5005352
                unsafe {
410
5005352
                    self.drop_and_deallocate_entry(ptr.ptr);
411
5005352
                }
412
5005352
                return false;
413
6246822
            }
414

            
415
6246822
            true
416
11252174
        });
417
56041
    }
418

            
419
    /// Drops the element at the given pointer and deallocates its memory.
420
    ///
421
    /// # Safety
422
    ///
423
    /// This requires that ptr can be dereferenced, so it must point to a valid element.
424
5005372
    unsafe fn drop_and_deallocate_entry(&self, ptr: NonNull<T>) {
425
        // SAFETY: We have exclusive access during drop and the pointer is valid
426
5005372
        let length = unsafe { T::length(ptr.as_ref()) };
427
5005372
        unsafe {
428
5005372
            // Drop the value in place before deallocating
429
5005372
            std::ptr::drop_in_place(ptr.as_ptr());
430
5005372
        }
431
5005372
        self.allocator.deallocate_slice_dst(ptr, length);
432
5005372
    }
433
}
434

            
435
impl<T: ?Sized + SliceDst, S, A> StablePointerSet<T, S, A>
436
where
437
    T: Hash + Eq,
438
    S: BuildHasher + Clone,
439
    A: Allocator + AllocatorDst + Sync,
440
{
441
    /// Clears the set, removing all values and invalidating all pointers.
442
    ///
443
    /// # Safety
444
    /// This is unsafe because it invalidates all pointers to the elements in the set.
445
    pub fn clear(&self) {
446
        #[cfg(debug_assertions)]
447
        debug_assert!(
448
            self.index.iter().all(|x| Arc::strong_count(&x.reference_counter) == 1),
449
            "All pointers must be the last reference to the element"
450
        );
451

            
452
        // Manually deallocate all entries before clearing
453
        for entry in self.index.iter() {
454
            // SAFETY: We have exclusive access during drop and the pointer is valid
455
            unsafe {
456
                self.drop_and_deallocate_entry(entry.ptr);
457
            }
458
        }
459

            
460
        self.index.clear();
461
        debug_assert!(self.index.is_empty(), "Index should be empty after clearing");
462
    }
463

            
464
    /// Inserts an element into the set using an equivalent value.
465
    ///
466
    /// This version takes a reference to an equivalent value and creates the
467
    /// value to insert only if it doesn't already exist in the set. Returns a
468
    /// stable pointer to the element and a boolean indicating whether the
469
    /// element was inserted.
470
    ///
471
    /// # Safety
472
    ///
473
    /// construct must fully initialize the value at the given pointer,
474
    /// otherwise it may lead to undefined behavior.
475
53915325
    pub unsafe fn insert_equiv_dst<'a, Q, C>(
476
53915325
        &self,
477
53915325
        value: &'a Q,
478
53915325
        length: usize,
479
53915325
        construct: C,
480
53915325
    ) -> (StablePointer<T>, bool)
481
53915325
    where
482
53915325
        Q: Hash + Equivalent<T>,
483
53915325
        C: Fn(*mut T, &'a Q),
484
    {
485
        // Check if we already have this value
486
53915325
        let raw_ptr = self.get(value);
487

            
488
53915325
        if let Some(ptr) = raw_ptr {
489
            // We already have this value, return pointer to existing element
490
48734933
            return (ptr, false);
491
5180392
        }
492

            
493
        // Allocate space for the entry and construct it
494
5180392
        let mut ptr = self
495
5180392
            .allocator
496
5180392
            .allocate_slice_dst::<T>(length)
497
5180392
            .unwrap_or_else(|_| handle_alloc_error(Layout::new::<()>()));
498

            
499
5180392
        unsafe {
500
5180392
            construct(ptr.as_mut(), value);
501
5180392
        }
502

            
503
        loop {
504
5180392
            let entry = Entry::new(ptr);
505
5180392
            let ptr = StablePointer::from_entry(&entry);
506

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

            
512
                // TODO: I suppose this can go wrong with begin_insert(x); insert(x); remove(x); end_insert(x) chain.
513
1
                if let Some(existing_ptr) = self.get(value) {
514
                    // SAFETY: We have exclusive access during drop and the pointer is valid
515
1
                    unsafe {
516
1
                        self.drop_and_deallocate_entry(ptr.ptr);
517
1
                    }
518

            
519
1
                    return (existing_ptr, false);
520
                }
521
            } else {
522
                // Value was successfully inserted
523
5180391
                return (ptr, true);
524
            }
525
        }
526
53915325
    }
527
}
528

            
529
impl<T, S, A> StablePointerSet<T, S, A>
530
where
531
    T: Hash + Eq + SliceDst,
532
    S: BuildHasher + Clone,
533
    A: Allocator + AllocatorDst,
534
{
535
    /// Inserts an element into the set.
536
    ///
537
    /// If the set did not have this value present, `true` is returned along
538
    /// with a stable pointer to the inserted element.
539
    ///
540
    /// If the set already had this value present, `false` is returned along
541
    /// with a stable pointer to the existing element.
542
20
    pub fn insert(&self, value: T) -> (StablePointer<T>, bool) {
543
20
        debug_assert!(std::mem::size_of::<T>() > 0, "Zero-sized types not supported");
544

            
545
20
        if let Some(ptr) = self.get(&value) {
546
            // We already have this value, return pointer to existing element
547
1
            return (ptr, false);
548
19
        }
549

            
550
19
        let ptr = self
551
19
            .allocator
552
19
            .allocate(Layout::new::<T>())
553
19
            .unwrap_or_else(|_| handle_alloc_error(Layout::new::<T>()))
554
19
            .cast::<T>();
555

            
556
19
        unsafe {
557
19
            ptr.write(value);
558
19
        }
559

            
560
        // Insert new value using allocator
561
19
        let entry = Entry::new(ptr);
562
19
        let ptr = StablePointer::from_entry(&entry);
563

            
564
        // First add to storage, then to index
565
19
        let inserted = self.index.insert(entry);
566

            
567
19
        debug_assert!(inserted, "Value should not already exist in the index");
568

            
569
19
        (ptr, true)
570
20
    }
571
}
572

            
573
impl<T: ?Sized, S, A> Drop for StablePointerSet<T, S, A>
574
where
575
    T: Hash + Eq + SliceDst,
576
    S: BuildHasher + Clone,
577
    A: Allocator + AllocatorDst,
578
{
579
10
    fn drop(&mut self) {
580
        #[cfg(debug_assertions)]
581
10
        debug_assert!(
582
15
            self.index.iter().all(|x| Arc::strong_count(&x.reference_counter) == 1),
583
            "All pointers must be the last reference to the element"
584
        );
585

            
586
        // Manually drop and deallocate all entries
587
15
        for entry in self.index.iter() {
588
15
            unsafe {
589
15
                self.drop_and_deallocate_entry(entry.ptr);
590
15
            }
591
        }
592
10
    }
593
}
594

            
595
/// A helper struct to store the allocated element in the set.
596
///
597
/// Uses manual allocation instead of Box for custom allocator support.
598
/// Optionally stores a reference counter for debugging purposes in debug builds.
599
struct Entry<T: ?Sized> {
600
    /// Pointer to the allocated value
601
    ptr: NonNull<T>,
602

            
603
    #[cfg(debug_assertions)]
604
    reference_counter: Arc<()>,
605
}
606

            
607
unsafe impl<T: ?Sized + Send> Send for Entry<T> {}
608
unsafe impl<T: ?Sized + Sync> Sync for Entry<T> {}
609

            
610
impl<T: ?Sized> Entry<T> {
611
    /// Creates a new entry by allocating memory for the value using the provided allocator.
612
5209740
    fn new(ptr: NonNull<T>) -> Self {
613
5209740
        Self {
614
5209740
            ptr,
615
5209740
            #[cfg(debug_assertions)]
616
5209740
            reference_counter: Arc::new(()),
617
5209740
        }
618
5209740
    }
619
}
620

            
621
impl<T: ?Sized> Deref for Entry<T> {
622
    type Target = T;
623

            
624
58001627
    fn deref(&self) -> &Self::Target {
625
        // SAFETY: The pointer is valid as long as the Entry exists
626
58001627
        unsafe { self.ptr.as_ref() }
627
58001627
    }
628
}
629

            
630
impl<T: PartialEq + ?Sized> PartialEq for Entry<T> {
631
105633
    fn eq(&self, other: &Self) -> bool {
632
105633
        **self == **other
633
105633
    }
634
}
635

            
636
impl<T: Hash + ?Sized> Hash for Entry<T> {
637
5535986
    fn hash<H: Hasher>(&self, state: &mut H) {
638
5535986
        (**self).hash(state);
639
5535986
    }
640
}
641

            
642
impl<T: Eq + ?Sized> Eq for Entry<T> {}
643

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

            
648
impl<T: ?Sized, Q: ?Sized> Equivalent<Entry<T>> for LookUp<'_, Q>
649
where
650
    Q: Equivalent<T>,
651
{
652
52186299
    fn equivalent(&self, other: &Entry<T>) -> bool {
653
52186299
        self.0.equivalent(&**other)
654
52186299
    }
655
}
656

            
657
#[cfg(test)]
658
mod tests {
659
    use super::*;
660
    use allocator_api2::alloc::System;
661
    use rustc_hash::FxHasher;
662
    use std::hash::BuildHasherDefault;
663

            
664
    #[test]
665
1
    fn test_insert_and_get() {
666
1
        let set = StablePointerSet::new();
667

            
668
        // Insert a value and ensure we get it back
669
1
        let (ptr1, inserted) = set.insert(42);
670
1
        assert!(inserted);
671
1
        assert_eq!(*ptr1, 42);
672

            
673
        // Insert the same value and ensure we get the same pointer
674
1
        let (ptr2, inserted) = set.insert(42);
675
1
        assert!(!inserted);
676
1
        assert_eq!(*ptr2, 42);
677

            
678
        // Pointers to the same value should be identical
679
1
        assert_eq!(ptr1, ptr2);
680

            
681
        // Verify that we have only one element
682
1
        assert_eq!(set.len(), 1);
683
1
    }
684

            
685
    #[test]
686
1
    fn test_contains() {
687
1
        let set = StablePointerSet::new();
688
1
        set.insert(42);
689
1
        set.insert(100);
690

            
691
1
        assert!(set.contains(&42));
692
1
        assert!(set.contains(&100));
693
1
        assert!(!set.contains(&200));
694
1
    }
695

            
696
    #[test]
697
1
    fn test_get() {
698
1
        let set = StablePointerSet::new();
699
1
        set.insert(42);
700
1
        set.insert(100);
701

            
702
1
        let ptr = set.get(&42).expect("Value should exist");
703
1
        assert_eq!(*ptr, 42);
704

            
705
1
        let ptr = set.get(&100).expect("Value should exist");
706
1
        assert_eq!(*ptr, 100);
707

            
708
1
        assert!(set.get(&200).is_none(), "Value should not exist");
709
1
    }
710

            
711
    #[test]
712
1
    fn test_iteration() {
713
1
        let set = StablePointerSet::new();
714
1
        set.insert(1);
715
1
        set.insert(2);
716
1
        set.insert(3);
717

            
718
1
        let mut values: Vec<i32> = set.iter().copied().collect();
719
1
        values.sort();
720

            
721
1
        assert_eq!(values, vec![1, 2, 3]);
722
1
    }
723

            
724
    #[test]
725
1
    fn test_stable_pointer_set_insert_equiv_ref() {
726
        #[derive(PartialEq, Eq, Debug)]
727
        struct TestValue {
728
            id: i32,
729
            name: String,
730
        }
731

            
732
        impl From<&i32> for TestValue {
733
2
            fn from(id: &i32) -> Self {
734
2
                TestValue {
735
2
                    id: *id,
736
2
                    name: format!("Value-{}", id),
737
2
                }
738
2
            }
739
        }
740

            
741
        impl Hash for TestValue {
742
2
            fn hash<H: Hasher>(&self, state: &mut H) {
743
2
                self.id.hash(state);
744
2
            }
745
        }
746

            
747
        impl Equivalent<TestValue> for i32 {
748
1
            fn equivalent(&self, key: &TestValue) -> bool {
749
1
                *self == key.id
750
1
            }
751
        }
752

            
753
1
        let set: StablePointerSet<TestValue> = StablePointerSet::new();
754

            
755
        // Insert using equivalent reference (i32 -> TestValue)
756
1
        let (ptr1, inserted) = set.insert_equiv(&42);
757
1
        assert!(inserted, "Value should be inserted");
758
1
        assert_eq!(ptr1.id, 42);
759
1
        assert_eq!(ptr1.name, "Value-42");
760

            
761
        // Try inserting the same value again via equivalent
762
1
        let (ptr2, inserted) = set.insert_equiv(&42);
763
1
        assert!(!inserted, "Value should not be inserted again");
764
1
        assert_eq!(ptr1, ptr2, "Should return the same pointer");
765

            
766
        // Insert a different value
767
1
        let (ptr3, inserted) = set.insert_equiv(&100);
768
1
        assert!(inserted, "New value should be inserted");
769
1
        assert_eq!(ptr3.id, 100);
770
1
        assert_eq!(ptr3.name, "Value-100");
771

            
772
        // Ensure we have exactly two elements
773
1
        assert_eq!(set.len(), 2);
774
1
    }
775

            
776
    #[test]
777
1
    fn test_stable_pointer_deref() {
778
1
        let set = StablePointerSet::new();
779
1
        let (ptr, _) = set.insert(42);
780

            
781
        // Test dereferencing
782
1
        let value: &i32 = &ptr;
783
1
        assert_eq!(*value, 42);
784

            
785
        // Test methods on the dereferenced value
786
1
        assert_eq!((*ptr).checked_add(10), Some(52));
787
1
    }
788

            
789
    #[test]
790
1
    fn test_stable_pointer_set_remove() {
791
1
        let set = StablePointerSet::new();
792

            
793
        // Insert values
794
1
        let (ptr1, _) = set.insert(42);
795
1
        let (ptr2, _) = set.insert(100);
796
1
        assert_eq!(set.len(), 2);
797

            
798
        // Remove one value
799
1
        assert!(set.remove(ptr1));
800
1
        assert_eq!(set.len(), 1);
801

            
802
        // Remove other value
803
1
        assert!(set.remove(ptr2));
804
1
        assert_eq!(set.len(), 0);
805
1
    }
806

            
807
    #[test]
808
1
    fn test_stable_pointer_set_retain() {
809
1
        let set = StablePointerSet::new();
810

            
811
        // Insert values
812
1
        set.insert(1);
813
1
        let (ptr2, _) = set.insert(2);
814
1
        set.insert(3);
815
1
        let (ptr4, _) = set.insert(4);
816
1
        assert_eq!(set.len(), 4);
817

            
818
        // Retain only even numbers
819
4
        set.retain(|x| **x % 2 == 0);
820

            
821
        // Verify results
822
1
        assert_eq!(set.len(), 2);
823
1
        assert!(!set.contains(&1));
824
1
        assert!(set.contains(&2));
825
1
        assert!(!set.contains(&3));
826
1
        assert!(set.contains(&4));
827

            
828
        // Verify that removed pointers are invalid and remaining are valid
829
1
        assert!(set.remove(ptr2));
830
1
        assert!(set.remove(ptr4));
831
1
    }
832

            
833
    #[test]
834
1
    fn test_stable_pointer_set_custom_allocator() {
835
        // Test with System allocator
836
1
        let set: StablePointerSet<i32, RandomState, System> = StablePointerSet::new_in(System);
837

            
838
        // Insert some values
839
1
        let (ptr1, inserted) = set.insert(42);
840
1
        assert!(inserted);
841
1
        let (ptr2, inserted) = set.insert(100);
842
1
        assert!(inserted);
843

            
844
        // Check that everything works as expected
845
1
        assert_eq!(set.len(), 2);
846
1
        assert_eq!(*ptr1, 42);
847
1
        assert_eq!(*ptr2, 100);
848

            
849
        // Test contains
850
1
        assert!(set.contains(&42));
851
1
        assert!(set.contains(&100));
852
1
        assert!(!set.contains(&200));
853
1
    }
854

            
855
    #[test]
856
1
    fn test_stable_pointer_set_custom_hasher_and_allocator() {
857
        // Use both custom hasher and allocator
858
1
        let set: StablePointerSet<i32, BuildHasherDefault<FxHasher>, System> =
859
1
            StablePointerSet::with_hasher_in(BuildHasherDefault::<FxHasher>::default(), System);
860

            
861
        // Insert some values
862
1
        let (ptr1, inserted) = set.insert(42);
863
1
        assert!(inserted);
864
1
        let (ptr2, inserted) = set.insert(100);
865
1
        assert!(inserted);
866

            
867
        // Check that everything works as expected
868
1
        assert_eq!(set.len(), 2);
869
1
        assert_eq!(*ptr1, 42);
870
1
        assert_eq!(*ptr2, 100);
871

            
872
        // Test contains
873
1
        assert!(set.contains(&42));
874
1
        assert!(set.contains(&100));
875
1
        assert!(!set.contains(&200));
876
1
    }
877
}