1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
#![doc = include_str!("../README.md")]

use std::fmt;

use self::{config::ConfigPrivate, control::PageControl, key::PageNo, page::Page};

mod config;
mod control;
mod handles;
mod key;
mod loom;
mod page;
mod slot;

pub use self::{
    config::{Config, DefaultConfig},
    handles::{BorrowedEntry, Iter, OwnedEntry, VacantEntry},
    key::Key,
};

// === Idr ===

/// An IDR (IDentifier Resolver) provides a way to efficiently and concurrently
/// map integer IDs to references to objects. It's particularly useful in
/// scenarios where you need to quickly find objects based on their ID. This
/// structure is designed to be highly efficient in terms of both speed and
/// memory usage.
pub struct Idr<T, C = DefaultConfig> {
    // TODO: flatten
    pages: Box<[Page<T, C>]>,
    // Used to synchronize page allocations.
    page_control: PageControl,
}

impl<T: 'static> Default for Idr<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T: 'static, C: Config> Idr<T, C> {
    /// The number of bits in each key which are used by the IDR.
    ///
    /// If other data is packed into the keys returned by [`Idr::insert()`],
    /// user code is free to use any bits higher than the `USED_BITS`-th bit.
    ///
    /// This is determined by the [`Config`] type that configures the IDR's
    /// parameters. By default, all bits are used; this can be changed by
    /// overriding the [`Config::RESERVED_BITS`] constant.
    pub const USED_BITS: u32 = C::USED_BITS;

    /// Returns a new IDR with the provided configuration parameters.
    pub fn new() -> Self {
        // Perform compile-time postmono checks.
        assert!(C::ENSURE_VALID);

        Self {
            pages: (0..C::MAX_PAGES).map(PageNo::new).map(Page::new).collect(),
            page_control: PageControl::default(),
        }
    }

    /// Inserts a value into the IDR, returning the key at which that
    /// value was inserted. This key can then be used to access the entry.
    ///
    /// This method is, usually, lock-free. However, it can block if a new page
    /// should be allocated. Thus, it can block max [`Config::MAX_PAGES`] times.
    /// Once allocated, the page is never deallocated until the IDR is dropped.
    ///
    /// Returns `None` if there is no more space in the IDR,
    /// and no items can be added until some are removed.
    ///
    /// # Panics
    ///
    /// If a new page should be allocated, but the allocator fails.
    ///
    /// # Example
    ///
    /// ```
    /// use idr_ebr::{Idr, EbrGuard};
    ///
    /// let idr = Idr::default();
    /// let key = idr.insert("foo").unwrap();
    /// assert_eq!(idr.get(key, &EbrGuard::new()).unwrap(), "foo");
    /// ```
    #[inline]
    pub fn insert(&self, value: T) -> Option<Key> {
        self.vacant_entry().map(|entry| {
            let key = entry.key();
            entry.insert(value);
            key
        })
    }

    /// Returns a handle to a vacant entry allowing for further manipulation.
    ///
    /// This method is, usually, lock-free. However, it can block if a new page
    /// should be allocated. Thus, it can block max [`Config::MAX_PAGES`] times.
    /// Once allocated, the page is never deallocated until the IDR is dropped.
    ///
    /// This method is useful when creating values that must contain their
    /// IDR key. The returned [`VacantEntry`] reserves a slot in the IDR and
    /// is able to return the key of the entry.
    ///
    /// Returns `None` if there is no more space in the IDR,
    /// and no items can be added until some are removed.
    ///
    /// # Panics
    ///
    /// If a new page should be allocated, but the allocator fails.
    ///
    /// # Example
    ///
    /// ```
    /// use idr_ebr::{Idr, EbrGuard};
    ///
    /// let idr = Idr::default();
    ///
    /// let key = {
    ///     let entry = idr.vacant_entry().unwrap();
    ///     let key = entry.key();
    ///     entry.insert((key, "foo"));
    ///     key
    /// };
    ///
    /// assert_eq!(idr.get(key, &EbrGuard::new()).unwrap().0, key);
    /// assert_eq!(idr.get(key, &EbrGuard::new()).unwrap().1, "foo");
    /// ```
    #[inline]
    pub fn vacant_entry(&self) -> Option<VacantEntry<'_, T, C>> {
        self.page_control.choose(&self.pages, |page| {
            page.reserve(&self.page_control)
                .map(|(key, slot)| VacantEntry::new(page, slot, key))
        })
    }

    /// Removes the entry at the given key in the IDR, returning `true` if a
    /// value was present at the moment of the removal.
    ///
    /// This method is lock-free.
    ///
    /// The removed entry becomes unreachable for getting instantly,
    /// but it still can be accessed using existing handles.
    ///
    /// An object behind the entry is not actually dropped until all handles are
    /// dropped and EBR garbage is cleaned up.
    ///
    /// # Example
    ///
    /// ```
    /// use idr_ebr::{Idr, EbrGuard};
    ///
    /// let idr = Idr::default();
    /// let key = idr.insert("foo").unwrap();
    ///
    /// let guard = EbrGuard::new();
    /// let entry = idr.get(key, &guard).unwrap();
    ///
    /// // Remove the entry from the IDR.
    /// assert!(idr.remove(key));
    ///
    /// // Repeat removal will return false.
    /// assert!(!idr.remove(key));
    ///
    /// // Now, the entry is unrechable using IDR.
    /// assert!(!idr.contains(key));
    ///
    /// // However, it still can be accessed using the handle.
    /// assert_eq!(entry, "foo");
    ///
    /// // An object behind the entry is not dropped until all handles are dropped.
    /// // The real destruction of the object can be delayed according to EBR.
    /// drop(guard);
    /// ```
    #[inline]
    pub fn remove(&self, key: Key) -> bool {
        let page_no = key.page_no::<C>();
        self.pages
            .get(page_no.to_usize())
            .map_or(false, |page| page.remove(key))
    }

    /// Returns a borrowed handle to the entry associated with the given key,
    /// or `None` if the IDR contains no entry for the given key.
    ///
    /// This method is wait-free.
    ///
    /// While the handle exists, it indicates to the IDR that the entry the
    /// handle references is currently being accessed. If the entry is
    /// removed from the IDR while a handle exists, it's still accessible via
    /// the handle.
    ///
    /// This method **doesn't modify memory**, thus it creates no contention on
    /// it at all. This is the whole point of the EBR pattern and the reason
    /// why it's used here.
    ///
    /// The returned handle cannot be send to another thread.
    /// Also, it means it cannot be hold over `.await` points.
    ///
    /// # Example
    ///
    /// ```
    /// use idr_ebr::{Idr, EbrGuard, Key};
    ///
    /// let idr = Idr::default();
    /// let key = idr.insert("foo").unwrap();
    ///
    /// let guard = EbrGuard::new();
    /// let entry = idr.get(key, &guard).unwrap();
    /// assert_eq!(entry, "foo");
    ///
    /// // If the entry is removed, the handle is still valid.
    /// assert!(idr.remove(key));
    /// assert_eq!(entry, "foo");
    ///
    /// // Getting entry for an unknown key produces None.
    /// assert!(idr.get(Key::try_from(12345).unwrap(), &guard).is_none());
    /// ```
    #[inline]
    pub fn get<'g>(&self, key: Key, guard: &'g EbrGuard) -> Option<BorrowedEntry<'g, T>> {
        let page_no = key.page_no::<C>();
        let page = self.pages.get(page_no.to_usize())?;
        page.get(key, guard)
    }

    /// Returns a owned handle to the entry associated with the given key,
    /// or `None` if the IDR contains no entry for the given key.
    ///
    /// This method is lock-free.
    ///
    /// While the handle exists, it indicates to the IDR that the entry the
    /// handle references is currently being accessed. If the entry is
    /// removed from the IDR while a handle exists, it's still accessible via
    /// the handle.
    ///
    /// Unlike [`Idr::get()`], which borrows the IDR, this method holds a strong
    /// reference to the object itself:
    /// * It modify the memory and, therefore, creates contention on it.
    /// * The IDR can be dropped while the handle exists.
    /// * It can be send to another thread.
    /// * It can be hold over `.await` points.
    ///
    /// # Example
    ///
    /// ```
    /// use idr_ebr::Idr;
    ///
    /// let idr = Idr::default();
    /// let key = idr.insert("foo").unwrap();
    ///
    /// let entry = idr.get_owned(key).unwrap();
    ///
    /// // The IDR can be dropped.
    /// drop(idr);
    ///
    /// // The handle can be send to another thread.
    /// std::thread::spawn(move || {
    ///     assert_eq!(entry, "foo");
    /// }).join().unwrap();
    /// ```
    #[inline]
    pub fn get_owned(&self, key: Key) -> Option<OwnedEntry<T>> {
        self.get(key, &EbrGuard::new()).map(BorrowedEntry::to_owned)
    }

    /// Returns `true` if the IDR contains an entry for the given key.
    ///
    /// This method is wait-free.
    ///
    /// # Example
    ///
    /// ```
    /// use idr_ebr::Idr;
    ///
    /// let idr = Idr::default();
    ///
    /// let key = idr.insert("foo").unwrap();
    /// assert!(idr.contains(key));
    ///
    /// idr.remove(key);
    /// assert!(!idr.contains(key));
    /// ```
    #[inline]
    pub fn contains(&self, key: Key) -> bool {
        self.get(key, &EbrGuard::new()).is_some()
    }

    /// Returns a fused iterator over all occupied entries in the IDR.
    /// An order of iteration is not guaranteed. Added during iteration entries
    /// can be observed via the iterator, but it depends on the current position
    /// of the iterator.
    ///
    /// This method is wait-free and [`Iter::next()`] is also wait-free.
    ///
    /// While the handle exists, it indicates to the IDR that the entry the
    /// handle references is currently being accessed. If the entry is
    /// removed from the IDR while a handle exists, it's still accessible via
    /// the handle.
    ///
    /// This method **doesn't modify memory**, thus it creates no contention on
    /// it at all. This is the whole point of the EBR pattern and the reason
    /// why it's used here.
    ///
    /// The returned iterator cannot be send to another thread.
    /// Also, it means it cannot be hold over `.await` points.
    ///
    /// # Example
    ///
    /// ```
    /// use idr_ebr::{Idr, EbrGuard};
    ///
    /// let idr = Idr::default();
    /// let foo_key = idr.insert("foo").unwrap();
    /// let bar_key = idr.insert("bar").unwrap();
    ///
    /// let guard = EbrGuard::new();
    /// let mut iter = idr.iter(&guard);
    ///
    /// let (key, entry) = iter.next().unwrap();
    /// assert_eq!(key, foo_key);
    /// assert_eq!(entry, "foo");
    ///
    /// let (key, entry) = iter.next().unwrap();
    /// assert_eq!(key, bar_key);
    /// assert_eq!(entry, "bar");
    ///
    /// let baz_key = idr.insert("baz").unwrap();
    /// let (key, entry) = iter.next().unwrap();
    /// assert_eq!(key, baz_key);
    /// assert_eq!(entry, "baz");
    /// ```
    #[inline]
    pub fn iter<'g>(&self, guard: &'g EbrGuard) -> Iter<'g, '_, T, C> {
        Iter::new(&self.pages, guard)
    }
}

impl<T, C: Config> fmt::Debug for Idr<T, C> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Idr")
            .field("allocated_pages", &self.page_control.allocated())
            .field("config", &C::debug())
            .finish_non_exhaustive()
    }
}

// === EbrGuard ===

/// [`EbrGuard`] allows to access entries of [`Idr`].
///
/// Wraps [`sdd::Guard`] in order to avoid potential breaking changes.
#[derive(Default)]
#[must_use]
pub struct EbrGuard(sdd::Guard);

impl EbrGuard {
    /// Creates a new [`EbrGuard`].
    ///
    /// # Panics
    ///
    /// The maximum number of [`EbrGuard`] instances in a thread is limited to
    /// `u32::MAX`; a thread panics when the number of [`EbrGuard`]
    /// instances in the thread exceeds the limit.
    ///
    /// # Examples
    ///
    /// ```
    /// use idr_ebr::EbrGuard;
    ///
    /// let guard = EbrGuard::new();
    /// ```
    #[inline]
    pub fn new() -> Self {
        Self(sdd::Guard::new())
    }
}

impl fmt::Debug for EbrGuard {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EbrGuard").finish()
    }
}