lockfree_object_pool/
linear_page.rs
1use crate::page::{Page, PageId};
2use std::ptr;
3use std::sync::atomic::{AtomicPtr, Ordering};
4
5pub struct LinearPage<T> {
6 page: Page<T>,
7 next: AtomicPtr<LinearPage<T>>,
8}
9
10impl<T> LinearPage<T> {
11 #[inline]
12 pub fn new<I>(init: I) -> Self
13 where
14 I: Fn() -> T,
15 {
16 Self {
17 page: Page::new(init),
18 next: AtomicPtr::new(ptr::null_mut()),
19 }
20 }
21
22 #[inline]
23 pub fn get_or_create_next<I>(&self, init: I) -> &Self
24 where
25 I: Fn() -> T,
26 {
27 let mut current = self.next.load(Ordering::Relaxed);
28 if current.is_null() {
29 let new = Box::into_raw(Box::new(LinearPage::<T>::new(init)));
30 match self
31 .next
32 .compare_exchange(current, new, Ordering::SeqCst, Ordering::Relaxed)
33 {
34 Ok(_) => {
35 current = new;
36 }
37 Err(x) => {
38 unsafe {
39 drop(Box::from_raw(new))
41 };
42 current = x;
43 }
44 }
45 }
46 unsafe {
47 current.as_ref().unwrap()
49 }
50 }
51
52 #[inline]
53 pub fn alloc<I>(&self, init: I) -> (&Page<T>, PageId)
54 where
55 I: Fn() -> T + Clone,
56 {
57 let mut linear_page = self;
58 loop {
59 match linear_page.page.alloc() {
60 Some(id) => {
61 return (&linear_page.page, id);
62 }
63 None => {
64 linear_page = linear_page.get_or_create_next(init.clone());
65 }
66 };
67 }
68 }
69}
70
71impl<T> Drop for LinearPage<T> {
72 #[inline]
73 fn drop(&mut self) {
74 let current = self.next.load(Ordering::Relaxed);
75 if !current.is_null() {
76 unsafe {
77 drop(Box::from_raw(current))
79 };
80 }
81 }
82}