indexmap_amortized/map/core/
raw.rs

1#![allow(unsafe_code)]
2//! This module encapsulates the `unsafe` access to `hashbrown::raw::RawTable`,
3//! mostly in dealing with its bucket "pointers".
4
5use super::{equivalent, Entry, HashValue, IndexMapCore, VacantEntry};
6use core::fmt;
7use core::mem::replace;
8use griddle::raw::RawTable;
9
10type RawBucket = griddle::raw::Bucket<usize>;
11
12pub(super) struct DebugIndices<'a>(pub &'a RawTable<usize>);
13impl fmt::Debug for DebugIndices<'_> {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        // SAFETY: we're not letting any of the buckets escape this function
16        let indices = unsafe { self.0.iter().map(|raw_bucket| raw_bucket.read()) };
17        f.debug_list().entries(indices).finish()
18    }
19}
20
21impl<K, V> IndexMapCore<K, V> {
22    /// Sweep the whole table to erase indices start..end
23    pub(super) fn erase_indices_sweep(&mut self, start: usize, end: usize) {
24        // SAFETY: we're not letting any of the buckets escape this function
25        unsafe {
26            let offset = end - start;
27            for bucket in self.indices.iter() {
28                let i = bucket.read();
29                if i >= end {
30                    bucket.write(i - offset);
31                } else if i >= start {
32                    self.indices.erase(bucket);
33                }
34            }
35        }
36    }
37
38    pub(crate) fn entry(&mut self, hash: HashValue, key: K) -> Entry<'_, K, V>
39    where
40        K: Eq,
41    {
42        let eq = equivalent(&key, &self.entries);
43        match self.indices.find(hash.get(), eq) {
44            // SAFETY: The entry is created with a live raw bucket, at the same time
45            // we have a &mut reference to the map, so it can not be modified further.
46            Some(raw_bucket) => Entry::Occupied(OccupiedEntry {
47                map: self,
48                raw_bucket,
49                key,
50            }),
51            None => Entry::Vacant(VacantEntry {
52                map: self,
53                hash,
54                key,
55            }),
56        }
57    }
58
59    pub(super) fn indices_mut(&mut self) -> impl Iterator<Item = &mut usize> {
60        // SAFETY: we're not letting any of the buckets escape this function,
61        // only the item references that are appropriately bound to `&mut self`.
62        unsafe { self.indices.iter().map(|bucket| bucket.as_mut()) }
63    }
64
65    /// Return the raw bucket for the given index
66    fn find_index(&self, index: usize) -> RawBucket {
67        // We'll get a "nice" bounds-check from indexing `self.entries`,
68        // and then we expect to find it in the table as well.
69        let hash = self.entries[index].hash.get();
70        self.indices
71            .find(hash, move |&i| i == index)
72            .expect("index not found")
73    }
74
75    pub(crate) fn swap_indices(&mut self, a: usize, b: usize) {
76        // SAFETY: Can't take two `get_mut` references from one table, so we
77        // must use raw buckets to do the swap. This is still safe because we
78        // are locally sure they won't dangle, and we write them individually.
79        unsafe {
80            let raw_bucket_a = self.find_index(a);
81            let raw_bucket_b = self.find_index(b);
82            raw_bucket_a.write(b);
83            raw_bucket_b.write(a);
84        }
85        self.entries.swap(a, b);
86    }
87}
88
89/// A view into an occupied entry in a `IndexMap`.
90/// It is part of the [`Entry`] enum.
91///
92/// [`Entry`]: enum.Entry.html
93// SAFETY: The lifetime of the map reference also constrains the raw bucket,
94// which is essentially a raw pointer into the map indices.
95pub struct OccupiedEntry<'a, K, V> {
96    map: &'a mut IndexMapCore<K, V>,
97    raw_bucket: RawBucket,
98    key: K,
99}
100
101// `hashbrown::raw::Bucket` is only `Send`, not `Sync`.
102// SAFETY: `&self` only accesses the bucket to read it.
103unsafe impl<K: Sync, V: Sync> Sync for OccupiedEntry<'_, K, V> {}
104
105// The parent module also adds methods that don't threaten the unsafe encapsulation.
106impl<'a, K, V> OccupiedEntry<'a, K, V> {
107    pub fn key(&self) -> &K {
108        &self.key
109    }
110
111    pub fn get(&self) -> &V {
112        &self.map.entries[self.index()].value
113    }
114
115    pub fn get_mut(&mut self) -> &mut V {
116        let index = self.index();
117        &mut self.map.entries[index].value
118    }
119
120    /// Put the new key in the occupied entry's key slot
121    pub(crate) fn replace_key(self) -> K {
122        let index = self.index();
123        let old_key = &mut self.map.entries[index].key;
124        replace(old_key, self.key)
125    }
126
127    /// Return the index of the key-value pair
128    #[inline]
129    pub fn index(&self) -> usize {
130        // SAFETY: we have &mut map keep keeping the bucket stable
131        unsafe { self.raw_bucket.read() }
132    }
133
134    pub fn into_mut(self) -> &'a mut V {
135        let index = self.index();
136        &mut self.map.entries[index].value
137    }
138
139    /// Remove and return the key, value pair stored in the map for this entry
140    ///
141    /// Like `Vec::swap_remove`, the pair is removed by swapping it with the
142    /// last element of the map and popping it off. **This perturbs
143    /// the postion of what used to be the last element!**
144    ///
145    /// Computes in **O(1)** time (average).
146    pub fn swap_remove_entry(self) -> (K, V) {
147        // SAFETY: This is safe because it can only happen once (self is consumed)
148        // and map.indices have not been modified since entry construction
149        let index = unsafe { self.map.indices.remove(self.raw_bucket) };
150        self.map.swap_remove_finish(index)
151    }
152
153    /// Remove and return the key, value pair stored in the map for this entry
154    ///
155    /// Like `Vec::remove`, the pair is removed by shifting all of the
156    /// elements that follow it, preserving their relative order.
157    /// **This perturbs the index of all of those elements!**
158    ///
159    /// Computes in **O(n)** time (average).
160    pub fn shift_remove_entry(self) -> (K, V) {
161        // SAFETY: This is safe because it can only happen once (self is consumed)
162        // and map.indices have not been modified since entry construction
163        let index = unsafe { self.map.indices.remove(self.raw_bucket) };
164        self.map.shift_remove_finish(index)
165    }
166}