lockfree_cuckoohash/
pointer.rs1use clippy_utilities::{Cast, OverflowArithmetic};
2use crossbeam_epoch::Guard;
3use std::marker::PhantomData;
4use std::sync::atomic::{AtomicUsize, Ordering};
5
6#[derive(Debug)]
9pub struct AtomicPtr<T: ?Sized> {
10 data: AtomicUsize,
12 _marker: PhantomData<*mut T>,
14}
15
16unsafe impl<T: ?Sized + Send + Sync> Send for AtomicPtr<T> {}
17unsafe impl<T: ?Sized + Send + Sync> Sync for AtomicPtr<T> {}
18
19impl<T> AtomicPtr<T> {
20 const fn from_usize(data: usize) -> Self {
22 Self {
23 data: AtomicUsize::new(data),
24 _marker: PhantomData,
25 }
26 }
27
28 #[allow(clippy::as_conversions)]
30 pub fn new(value: T) -> Self {
31 let b = Box::new(value);
32 let raw_ptr = Box::into_raw(b);
33 Self::from_usize(raw_ptr as usize)
34 }
35
36 pub const fn null() -> Self {
38 Self::from_usize(0)
39 }
40
41 pub fn load<'g>(&self, ord: Ordering, _: &'g Guard) -> SharedPtr<'g, T> {
43 SharedPtr::from_usize(self.data.load(ord))
44 }
45
46 pub fn compare_and_set<'g>(
48 &self,
49 current_ptr: SharedPtr<'_, T>,
50 new_ptr: SharedPtr<'_, T>,
51 ord: Ordering,
52 _: &'g Guard,
53 ) -> Result<SharedPtr<'g, T>, (SharedPtr<'g, T>, SharedPtr<'g, T>)> {
54 let new = new_ptr.as_usize();
55 self.data
57 .compare_exchange(current_ptr.as_usize(), new, ord, ord)
58 .map(|_| SharedPtr::from_usize(current_ptr.as_usize()))
59 .map_err(|current| (SharedPtr::from_usize(current), SharedPtr::from_usize(new)))
60 }
61}
62
63pub struct SharedPtr<'g, T: 'g> {
67 data: usize,
72 _marker: PhantomData<(&'g (), *const T)>,
74}
75
76impl<T> Clone for SharedPtr<'_, T> {
77 fn clone(&self) -> Self {
78 Self {
79 data: self.data,
80 _marker: PhantomData,
81 }
82 }
83}
84
85impl<T> Copy for SharedPtr<'_, T> {}
86
87impl<T> SharedPtr<'_, T> {
88 pub const fn from_usize(data: usize) -> Self {
90 SharedPtr {
91 data,
92 _marker: PhantomData,
93 }
94 }
95
96 pub fn from_box(b: Box<T>) -> Self {
98 Self::from_raw(Box::into_raw(b))
99 }
100
101 #[allow(clippy::as_conversions)]
103 pub fn from_raw(raw: *const T) -> Self {
104 Self::from_usize(raw as usize)
105 }
106
107 pub const fn null() -> Self {
109 Self::from_usize(0)
110 }
111
112 pub unsafe fn into_box(self) -> Box<T> {
114 Box::from_raw(self.as_mut_raw())
115 }
116
117 pub const fn as_usize(self) -> usize {
119 self.data
120 }
121
122 fn decompose_lower_u2(data: usize) -> (usize, u8) {
126 let mask: usize = 3;
127 (data & !mask, (data & mask).cast::<u8>())
129 }
130
131 fn decompose_higher_u8(data: usize) -> (u8, usize) {
135 let mask: usize = (1_usize.overflowing_shl(56).0).overflow_sub(1);
136 (data.overflow_shr(56).cast::<u8>(), data & mask)
138 }
139
140 #[allow(clippy::as_conversions)]
145 pub fn decompose(self) -> (u8, *const T, u8) {
146 let data = self.data;
147 let (higher_u62, lower_u2) = Self::decompose_lower_u2(data);
148 let (higher_u8, raw_ptr) = Self::decompose_higher_u8(higher_u62);
149 (higher_u8, raw_ptr as *const T, lower_u2)
150 }
151
152 pub fn as_raw(self) -> *const T {
154 let (_, raw, _) = self.decompose();
155 raw
156 }
157
158 #[allow(clippy::as_conversions)]
160 pub fn as_mut_raw(self) -> *mut T {
161 let const_raw = self.as_raw();
162 const_raw as *mut T
163 }
164
165 pub fn with_lower_u2(self, lower_u8: u8) -> Self {
167 let mask: usize = 3;
168 Self::from_usize(self.data & !mask | lower_u8.cast::<usize>())
170 }
171
172 pub fn with_higher_u8(self, higher_u8: u8) -> Self {
174 let data = self.data;
175 let mask: usize = (1_usize.overflowing_shl(56).0).overflow_sub(1);
176 Self::from_usize((data & mask) | ((higher_u8.cast::<usize>()).overflowing_shl(56).0))
178 }
179}