gen_map/key_layout.rs
1use crate::key_piece::KeyPiece;
2use core::hash::Hash;
3use core::marker::PhantomData;
4
5/// How a [`Key`](crate::Key) stores its index and generation. A
6/// [`Config`](crate::Config) picks one through its `Layout` type.
7///
8/// # Safety
9///
10/// The map trusts what a layout hands back. [`idx`](Self::idx) and
11/// [`generation`](Self::generation) must return exactly what
12/// [`pack_unchecked`](Self::pack_unchecked) was given, two `Repr` values
13/// must be equal only if they were packed from the same parts, and
14/// [`max_generation`](Self::max_generation) must be odd.
15///
16/// `generation` is safe to call and returns a `NonZero`, so safe code must
17/// not be able to make a `Repr` that `pack_unchecked` did not return. A
18/// `Repr` whose fields are private, like [`SplitRepr`] and [`PackedRepr`],
19/// meets this rule, because only `pack_unchecked` can make one.
20pub unsafe trait KeyLayout<Idx: KeyPiece, Gen: KeyPiece> {
21 /// The type a key stores its index and generation in.
22 type Repr: Copy + Eq + Hash + Send + Sync + 'static;
23
24 /// The largest index a key can hold.
25 fn max_idx() -> Idx;
26
27 /// The largest generation a key can hold. It is odd.
28 fn max_generation() -> Gen;
29
30 /// Packs an index and a generation.
31 ///
32 /// # Safety
33 ///
34 /// `idx` must be at most [`max_idx`](Self::max_idx), and `generation`
35 /// must be odd and at most [`max_generation`](Self::max_generation).
36 unsafe fn pack_unchecked(idx: Idx, generation: Gen) -> Self::Repr;
37
38 /// The index that was packed.
39 fn idx(repr: Self::Repr) -> Idx;
40
41 /// The generation that was packed.
42 fn generation(repr: Self::Repr) -> Gen::NonZero;
43}
44
45/// Stores the index and the generation as two fields, so a key is as large
46/// as the two put together, plus any padding their alignment needs. Every
47/// value of `Idx` and `Gen` fits.
48#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
49pub struct Split;
50
51/// The type a key with the [`Split`] layout stores its index and generation
52/// in.
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54pub struct SplitRepr<Idx: KeyPiece, Gen: KeyPiece> {
55 idx: Idx,
56 /// The generation is odd, so it is never zero, and storing it this way
57 /// gives `Option<Key>` the size of `Key`.
58 generation: Gen::NonZero,
59}
60
61// SAFETY: the two fields are stored and read back as they are.
62unsafe impl<Idx: KeyPiece, Gen: KeyPiece> KeyLayout<Idx, Gen> for Split {
63 type Repr = SplitRepr<Idx, Gen>;
64
65 #[inline]
66 fn max_idx() -> Idx {
67 Idx::MAX
68 }
69
70 /// The largest value of an unsigned integer is odd.
71 #[inline]
72 fn max_generation() -> Gen {
73 Gen::MAX
74 }
75
76 #[inline]
77 unsafe fn pack_unchecked(idx: Idx, generation: Gen) -> SplitRepr<Idx, Gen> {
78 debug_assert!(generation.is_odd());
79 // SAFETY: the caller promises an odd generation, and zero is even.
80 let generation = unsafe { generation.into_non_zero_unchecked() };
81 SplitRepr { idx, generation }
82 }
83
84 #[inline]
85 fn idx(repr: SplitRepr<Idx, Gen>) -> Idx {
86 repr.idx
87 }
88
89 #[inline]
90 fn generation(repr: SplitRepr<Idx, Gen>) -> Gen::NonZero {
91 repr.generation
92 }
93}
94
95/// Stores the index and the generation in the bits of one integer `R`, so a
96/// key is as large as `R`. The low `GEN_BITS` bits hold the generation and
97/// the bits above them hold the index.
98///
99/// `GEN_BITS` must be at least one and less than the bits of `R`, `Gen` must
100/// have at least `GEN_BITS` bits, and `Idx` must have at least the bits that
101/// are left for the index. A config that breaks one of these does not
102/// compile.
103///
104/// The largest index is `(1 << (R::BITS - GEN_BITS)) - 1` and the largest
105/// generation is `(1 << GEN_BITS) - 1`, no matter how wide `Idx` and `Gen`
106/// are. A slot whose generation reaches the largest one retires or wraps, as
107/// [`WRAP_ON_OVERFLOW`](crate::Config::WRAP_ON_OVERFLOW) says.
108///
109/// # Examples
110///
111/// ```
112/// use gen_map::{Config, GenMap, Key, Packed};
113///
114/// /// Four byte keys with 24 bits of index and 8 bits of generation.
115/// struct Compact;
116///
117/// impl Config for Compact {
118/// type Idx = u32;
119/// type Gen = u8;
120/// type Layout = Packed<u32, 8>;
121/// type Storage<S> = Vec<S>;
122/// }
123///
124/// let mut map = GenMap::<&str, Compact>::new_with_config();
125/// let key = map.insert("a");
126/// assert_eq!(core::mem::size_of_val(&key), 4);
127/// assert_eq!(core::mem::size_of::<Option<Key<Compact>>>(), 4);
128/// assert_eq!((key.idx(), key.generation()), (0, 1));
129/// ```
130#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
131pub struct Packed<R, const GEN_BITS: u32>(PhantomData<R>);
132
133/// The type a key with the [`Packed`] layout stores its index and
134/// generation in. Only
135/// [`pack_unchecked`](KeyLayout::pack_unchecked) can make one, so its
136/// generation field is never zero.
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
138pub struct PackedRepr<R: KeyPiece>(R::NonZero);
139
140/// Fails to compile when the bit counts of a [`Packed`] layout do not add
141/// up. The `const` block is evaluated for each set of types it is used with.
142#[inline(always)]
143fn check_packed<Idx: KeyPiece, Gen: KeyPiece, R: KeyPiece, const GEN_BITS: u32>() {
144 const {
145 assert!(GEN_BITS >= 1, "Packed needs at least one generation bit");
146 assert!(GEN_BITS < R::BITS, "Packed needs at least one index bit");
147 assert!(
148 Gen::BITS >= GEN_BITS,
149 "the Gen type of the config has fewer bits than GEN_BITS"
150 );
151 assert!(
152 Idx::BITS >= R::BITS - GEN_BITS,
153 "the Idx type of the config has fewer bits than the index field"
154 );
155 }
156}
157
158/// Returns a `u128` with its lowest `bits` bits set. `bits` must be below
159/// 128.
160#[inline]
161fn low_bits(bits: u32) -> u128 {
162 debug_assert!(bits < 128);
163 (1u128 << bits) - 1
164}
165
166// SAFETY: the two parts are put in bit fields that do not overlap and are
167// read back from the same fields, and the largest generation has all of its
168// bits set, so it is odd.
169unsafe impl<Idx: KeyPiece, Gen: KeyPiece, R: KeyPiece, const GEN_BITS: u32> KeyLayout<Idx, Gen>
170 for Packed<R, GEN_BITS>
171{
172 type Repr = PackedRepr<R>;
173
174 #[inline]
175 fn max_idx() -> Idx {
176 check_packed::<Idx, Gen, R, GEN_BITS>();
177 // SAFETY: the check makes sure `Idx` has at least as many bits as the
178 // index field.
179 unsafe { Idx::from_u128_unchecked(low_bits(R::BITS - GEN_BITS)) }
180 }
181
182 #[inline]
183 fn max_generation() -> Gen {
184 check_packed::<Idx, Gen, R, GEN_BITS>();
185 // SAFETY: the check makes sure `Gen` has at least `GEN_BITS` bits.
186 unsafe { Gen::from_u128_unchecked(low_bits(GEN_BITS)) }
187 }
188
189 #[inline]
190 unsafe fn pack_unchecked(idx: Idx, generation: Gen) -> PackedRepr<R> {
191 check_packed::<Idx, Gen, R, GEN_BITS>();
192 debug_assert!(idx <= <Self as KeyLayout<Idx, Gen>>::max_idx());
193 debug_assert!(generation.is_odd());
194 debug_assert!(generation <= <Self as KeyLayout<Idx, Gen>>::max_generation());
195 let bits = (idx.into_u128() << GEN_BITS) | generation.into_u128();
196 // SAFETY: the caller promises that `idx` fits in the index field and
197 // `generation` in the generation field, so `bits` fits in `R`, and
198 // that `generation` is odd, so `bits` is not zero.
199 PackedRepr(unsafe { R::from_u128_unchecked(bits).into_non_zero_unchecked() })
200 }
201
202 #[inline]
203 fn idx(repr: PackedRepr<R>) -> Idx {
204 check_packed::<Idx, Gen, R, GEN_BITS>();
205 // SAFETY: the index field has at most as many bits as `Idx`, which
206 // the check makes sure of.
207 unsafe { Idx::from_u128_unchecked(R::from_non_zero(repr.0).into_u128() >> GEN_BITS) }
208 }
209
210 #[inline]
211 fn generation(repr: PackedRepr<R>) -> Gen::NonZero {
212 check_packed::<Idx, Gen, R, GEN_BITS>();
213 // SAFETY: the generation field has at most as many bits as `Gen`,
214 // which the check makes sure of. A `PackedRepr` only comes from
215 // `pack_unchecked`, whose caller promised an odd generation, so the
216 // field is not zero.
217 unsafe {
218 Gen::from_u128_unchecked(R::from_non_zero(repr.0).into_u128() & low_bits(GEN_BITS))
219 .into_non_zero_unchecked()
220 }
221 }
222}