/rust/registry/src/index.crates.io-1949cf8c6b5b557f/papaya-0.2.4/src/raw/alloc.rs
Line | Count | Source |
1 | | use std::alloc::Layout; |
2 | | use std::marker::PhantomData; |
3 | | use std::sync::atomic::{AtomicPtr, AtomicU8, Ordering}; |
4 | | use std::{alloc, mem, ptr}; |
5 | | |
6 | | use super::{probe, State}; |
7 | | |
8 | | // A hash-table laid out in a single allocation. |
9 | | // |
10 | | // Note that the `PhantomData<T>` ensures that the hash-table is invariant |
11 | | // with respect to `T`, as this struct is stored behind an `AtomicPtr`. |
12 | | #[repr(transparent)] |
13 | | pub struct RawTable<T>(u8, PhantomData<T>); |
14 | | |
15 | | // The layout of the table allocation. |
16 | | #[repr(C)] |
17 | | struct TableLayout<T> { |
18 | | /// A mask to get an index into the table from a hash. |
19 | | mask: usize, |
20 | | |
21 | | /// The maximum probe limit for this table. |
22 | | limit: usize, |
23 | | |
24 | | /// State for the table resize. |
25 | | state: State<T>, |
26 | | |
27 | | /// An array of metadata for each entry. |
28 | | meta: [AtomicU8; 0], |
29 | | |
30 | | /// An array of entries. |
31 | | entries: [AtomicPtr<T>; 0], |
32 | | } |
33 | | |
34 | | // Manages a table allocation. |
35 | | #[repr(C)] |
36 | | pub struct Table<T> { |
37 | | /// A mask to get an index into the table from a hash. |
38 | | pub mask: usize, |
39 | | |
40 | | /// The maximum probe limit for this table. |
41 | | pub limit: usize, |
42 | | |
43 | | // The raw table allocation. |
44 | | // |
45 | | // Invariant: This pointer is initialized and valid for reads and writes. |
46 | | pub raw: *mut RawTable<T>, |
47 | | } |
48 | | |
49 | | impl<T> Copy for Table<T> {} |
50 | | |
51 | | impl<T> Clone for Table<T> { |
52 | 0 | fn clone(&self) -> Self { |
53 | 0 | *self |
54 | 0 | } |
55 | | } |
56 | | |
57 | | impl<T> Table<T> { |
58 | | // Allocate a table with the provided length and collector. |
59 | 0 | pub fn alloc(len: usize) -> Table<T> { |
60 | 0 | assert!(len.is_power_of_two()); |
61 | | |
62 | | // Pad the meta table to fulfill the alignment requirement of an entry. |
63 | 0 | let len = len.max(mem::align_of::<AtomicPtr<T>>()); |
64 | 0 | let mask = len - 1; |
65 | 0 | let limit = probe::limit(len); |
66 | | |
67 | 0 | let layout = Table::<T>::layout(len); |
68 | | |
69 | | // Allocate the table, zeroing the entries. |
70 | | // |
71 | | // Safety: The layout for is guaranteed to be non-zero. |
72 | 0 | let ptr = unsafe { alloc::alloc_zeroed(layout) }; |
73 | 0 | if ptr.is_null() { |
74 | 0 | alloc::handle_alloc_error(layout); |
75 | 0 | } |
76 | | |
77 | | // Safety: We just allocated the pointer and ensured it is non-null above. |
78 | 0 | unsafe { |
79 | 0 | // Write the table state. |
80 | 0 | ptr.cast::<TableLayout<T>>().write(TableLayout { |
81 | 0 | mask, |
82 | 0 | limit, |
83 | 0 | meta: [], |
84 | 0 | entries: [], |
85 | 0 | state: State::default(), |
86 | 0 | }); |
87 | 0 |
|
88 | 0 | // Initialize the meta table. |
89 | 0 | ptr.add(mem::size_of::<TableLayout<T>>()) |
90 | 0 | .cast::<u8>() |
91 | 0 | .write_bytes(super::meta::EMPTY, len); |
92 | 0 | } |
93 | | |
94 | 0 | Table { |
95 | 0 | mask, |
96 | 0 | limit, |
97 | 0 | // Invariant: We allocated and initialized the allocation above. |
98 | 0 | raw: ptr.cast::<RawTable<T>>(), |
99 | 0 | } |
100 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::alloc Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::alloc |
101 | | |
102 | | // Creates a `Table` from a raw pointer. |
103 | | // |
104 | | // # Safety |
105 | | // |
106 | | // The pointer must either be null, or a valid pointer created with `Table::alloc`. |
107 | | #[inline] |
108 | 380k | pub unsafe fn from_raw(raw: *mut RawTable<T>) -> Table<T> { |
109 | 380k | if raw.is_null() { |
110 | 380k | return Table { |
111 | 380k | raw, |
112 | 380k | mask: 0, |
113 | 380k | limit: 0, |
114 | 380k | }; |
115 | 0 | } |
116 | | |
117 | | // Safety: The caller guarantees that the pointer is valid. |
118 | 0 | let layout = unsafe { &*raw.cast::<TableLayout<T>>() }; |
119 | | |
120 | 0 | Table { |
121 | 0 | raw, |
122 | 0 | mask: layout.mask, |
123 | 0 | limit: layout.limit, |
124 | 0 | } |
125 | 380k | } <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::from_raw Line | Count | Source | 108 | 380k | pub unsafe fn from_raw(raw: *mut RawTable<T>) -> Table<T> { | 109 | 380k | if raw.is_null() { | 110 | 380k | return Table { | 111 | 380k | raw, | 112 | 380k | mask: 0, | 113 | 380k | limit: 0, | 114 | 380k | }; | 115 | 0 | } | 116 | | | 117 | | // Safety: The caller guarantees that the pointer is valid. | 118 | 0 | let layout = unsafe { &*raw.cast::<TableLayout<T>>() }; | 119 | | | 120 | 0 | Table { | 121 | 0 | raw, | 122 | 0 | mask: layout.mask, | 123 | 0 | limit: layout.limit, | 124 | 0 | } | 125 | 380k | } |
Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::from_raw |
126 | | |
127 | | // Returns the metadata entry at the given index. |
128 | | // |
129 | | // # Safety |
130 | | // |
131 | | // The index must be in-bounds for the length of the table. |
132 | | #[inline] |
133 | 0 | pub unsafe fn meta(&self, i: usize) -> &AtomicU8 { |
134 | 0 | debug_assert!(i < self.len()); |
135 | | |
136 | | // Safety: The caller guarantees the index is in-bounds. |
137 | | unsafe { |
138 | 0 | let meta = self.raw.add(mem::size_of::<TableLayout<T>>()); |
139 | 0 | &*meta.cast::<AtomicU8>().add(i) |
140 | | } |
141 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::meta Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::meta |
142 | | |
143 | | // Returns the entry at the given index. |
144 | | // |
145 | | // # Safety |
146 | | // |
147 | | // The index must be in-bounds for the length of the table. |
148 | | #[inline] |
149 | 0 | pub unsafe fn entry(&self, i: usize) -> &AtomicPtr<T> { |
150 | 0 | debug_assert!(i < self.len()); |
151 | | |
152 | | // Safety: The caller guarantees the index is in-bounds. |
153 | | unsafe { |
154 | 0 | let meta = self.raw.add(mem::size_of::<TableLayout<T>>()); |
155 | 0 | let entries = meta.add(self.len()).cast::<AtomicPtr<T>>(); |
156 | 0 | &*entries.add(i) |
157 | | } |
158 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::entry Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::entry |
159 | | |
160 | | /// Returns the length of the table. |
161 | | #[inline] |
162 | 0 | pub fn len(&self) -> usize { |
163 | 0 | self.mask + 1 |
164 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::len Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::len |
165 | | |
166 | | // Returns a reference to the table state. |
167 | | #[inline] |
168 | 0 | pub fn state(&self) -> &State<T> { |
169 | | // Safety: The raw table pointer is always valid for reads and writes. |
170 | 0 | unsafe { &(*self.raw.cast::<TableLayout<T>>()).state } |
171 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::state Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::state |
172 | | |
173 | | // Returns a mutable reference to the table state. |
174 | | #[inline] |
175 | 0 | pub fn state_mut(&mut self) -> &mut State<T> { |
176 | | // Safety: The raw table pointer is always valid for reads and writes. |
177 | 0 | unsafe { &mut (*self.raw.cast::<TableLayout<T>>()).state } |
178 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::state_mut Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::state_mut |
179 | | |
180 | | // Returns a pointer to the next table, if it has already been created. |
181 | | #[inline] |
182 | 0 | pub fn next_table(&self) -> Option<Self> { |
183 | 0 | let next = self.state().next.load(Ordering::Acquire); |
184 | | |
185 | 0 | if !next.is_null() { |
186 | | // Safety: We verified that the pointer is non-null, and the |
187 | | // next pointer is otherwise a valid pointer to a table allocation. |
188 | 0 | return unsafe { Some(Table::from_raw(next)) }; |
189 | 0 | } |
190 | | |
191 | 0 | None |
192 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::next_table Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::next_table |
193 | | |
194 | | // Deallocate the table. |
195 | | // |
196 | | // # Safety |
197 | | // |
198 | | // The table may not be accessed in any way after this method is |
199 | | // called. |
200 | 0 | pub unsafe fn dealloc(table: Table<T>) { |
201 | 0 | let layout = Self::layout(table.len()); |
202 | | |
203 | | // Safety: The raw table pointer is valid and allocated with `alloc::alloc_zeroed`. |
204 | | // Additionally, the caller guarantees that the allocation will not be accessed after |
205 | | // this point. |
206 | 0 | unsafe { |
207 | 0 | ptr::drop_in_place(table.raw.cast::<TableLayout<T>>()); |
208 | 0 | alloc::dealloc(table.raw.cast::<u8>(), layout); |
209 | 0 | }; |
210 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::dealloc Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::dealloc |
211 | | |
212 | | // Returns the non-zero layout for a table allocation. |
213 | 0 | fn layout(len: usize) -> Layout { |
214 | 0 | let size = mem::size_of::<TableLayout<T>>() |
215 | 0 | + (mem::size_of::<u8>() * len) // Metadata table. |
216 | 0 | + (mem::size_of::<AtomicPtr<T>>() * len); // Entry pointers. |
217 | | // |
218 | 0 | Layout::from_size_align(size, mem::align_of::<TableLayout<T>>()).unwrap() |
219 | 0 | } Unexecuted instantiation: <papaya::raw::alloc::Table<papaya::raw::Entry<bytes::bytes::Bytes, ()>>>::layout Unexecuted instantiation: <papaya::raw::alloc::Table<_>>::layout |
220 | | } |
221 | | |
222 | | #[test] |
223 | | fn layout() { |
224 | | unsafe { |
225 | | let table: Table<u8> = Table::alloc(4); |
226 | | let table: Table<u8> = Table::from_raw(table.raw); |
227 | | |
228 | | // The capacity is padded for pointer alignment. |
229 | | assert_eq!(table.mask, 7); |
230 | | assert_eq!(table.len(), 8); |
231 | | Table::dealloc(table); |
232 | | } |
233 | | } |