1use std::mem::{transmute, size_of, transmute_copy, forget};
16use std::ops::Deref;
17use std::sync::atomic::{AtomicUsize, Ordering};
18 use std::marker::PhantomData;
19use std::marker::Sync;
20use std::cell::Cell;
21
22#[cfg(target_pointer_width = "32")]
26const PTR_SIZE: usize = 4;
27#[cfg(target_pointer_width = "64")]
28const PTR_SIZE: usize = 8;
29
30const MAX_WEIGHT_EXP: u8 = PTR_SIZE as u8 * 8 - 1;
31const MAX_WEIGHT: usize = 1usize << MAX_WEIGHT_EXP; pub struct Orc<'a, T: 'a> {
35 pointer_data: [u8; PTR_SIZE - 1], weight_exp: Cell<u8>,
37 lifetime_and_type: PhantomData<&'a T>,
38}
39
40unsafe impl<'a, T> Sync for Orc<'a, T> {}
41
42impl<'a, T> Drop for Orc<'a, T> {
43 fn drop(&mut self) {
44 let slot = construct_pointer::<T>(self.pointer_data, 0);
45 let weight = two_two_the(self.weight_exp.get());
46 slot.weight.fetch_sub(weight, Ordering::Release);
47 }
48}
49
50impl<'a, T> Clone for Orc<'a, T> {
51 fn clone(&self) -> Orc<'a, T> {
52 if self.weight_exp.get() > 1 {
53 self.weight_exp.set(self.weight_exp.get() - 1);
54 return Orc {
55 weight_exp: Cell::new(self.weight_exp.get()),
56 pointer_data: self.pointer_data,
57 lifetime_and_type: PhantomData,
58 };
59 }
60 panic!("not implemented yet");
61 }
62}
63
64impl<'a, T> Deref for Orc<'a, T> {
65 type Target = T;
66
67 #[inline(always)]
68 fn deref(&self) -> &T {
69 let slot = construct_pointer::<T>(self.pointer_data, 0);
70 match slot.data {
71 Some(ref d) => d,
72 None => unreachable!(), }
74 }
75}
76
77struct OrcInner<T> {
80 weight: AtomicUsize,
81 data: Option<T>,
82}
83
84pub struct OrcHeap<T> {
86 heap: Vec<OrcInner<T>>,
87}
88
89unsafe impl<'a, T> Sync for OrcHeap<T> {}
90
91impl<'a, T> OrcHeap<T> {
92 pub fn new() -> OrcHeap<T> {
99 const DEFAULT_HEAP_SIZE: usize = 16;
100 OrcHeap::<T>::with_capacity(DEFAULT_HEAP_SIZE)
101 }
102
103 pub fn with_capacity(capacity: usize) -> OrcHeap<T> {
110 let mut heap = Vec::with_capacity(capacity);
111 for _ in 0..capacity {
113 heap.push(OrcInner {
114 weight: AtomicUsize::new(0),
115 data: None,
116 });
117 }
118 let (_, weight) = deconstruct_pointer(heap.iter().nth(capacity - 1).unwrap());
120 assert_eq!(weight, 0);
121
122 OrcHeap::<T> { heap: heap }
123 }
124
125
126 pub fn alloc(&'a self, value: T) -> Result<Orc<T>, &'static str> {
128 let mut position = 0;
131 loop {
132 unsafe {
133 let slot = self.heap.get_unchecked(position);
134 if slot.weight.compare_and_swap(0, MAX_WEIGHT, Ordering::Relaxed) == 0 {
135 let ref data: Option<T> = slot.data;
137 let mut_data: *mut Option<T> = hack_transmute(data);
138 *mut_data = Some(value);
140 let (pointer_data, _) = deconstruct_pointer(slot);
142 return Ok(Orc::<'a, T> {
143 pointer_data: pointer_data,
144 weight_exp: Cell::new(MAX_WEIGHT_EXP),
145 lifetime_and_type: PhantomData,
146 });
147 }
148 }
149
150 position += 1;
151 if position == self.heap.capacity() {
152 position = 0;
153 break;
155 }
156 }
157 Err("Out of memory")
158 }
159
160
161 pub fn collect(&'a self) {
162 for position in 0..self.heap.capacity() {
163 unsafe {
164 let slot = self.heap.get_unchecked(position);
165 if slot.weight.compare_and_swap(0, MAX_WEIGHT, Ordering::Relaxed) == 0 {
166 let ref data: Option<T> = slot.data;
167 let mut_data: *mut Option<T> = hack_transmute(data);
168 *mut_data = None;
170 }
171 }
172 }
173 }
174}
175
176
177#[inline(always)]
180fn deconstruct_pointer<T>(p: &OrcInner<T>) -> ([u8; PTR_SIZE - 1], u8) {
181 unsafe {
182 let p: usize = transmute(p);
183 transmute(usize::from_le(p)) }
185}
186
187#[inline(always)]
188fn construct_pointer<'a, T>(pointer: [u8; PTR_SIZE - 1], weight: u8) -> &'a OrcInner<T> {
189 unsafe {
190 let p: usize = transmute((pointer, weight));
191 transmute(usize::from_le(p)) }
193}
194
195#[inline(always)]
196fn two_two_the(exp: u8) -> usize {
197 1usize << exp
198}
199
200#[inline(always)]
202unsafe fn hack_transmute<T, U>(x: T) -> U {
203 debug_assert_eq!(size_of::<T>(), size_of::<U>());
204 let y = transmute_copy(&x);
205 forget(x);
206 y
207}
208
209#[test]
212fn test_two_two_the() {
213 assert_eq!(two_two_the(0), 1);
214 assert_eq!(two_two_the(1), 2);
215 assert_eq!(two_two_the(8), 256);
216}
217
218
219#[cfg(test)]
222mod test_drop {
223 use OrcHeap;
224 use std::cell::Cell;
225
226 struct DropTest<'a>(&'a Cell<usize>);
227
228 impl<'a> Drop for DropTest<'a> {
229 fn drop(&mut self) {
230 let v = self.0.get();
231 self.0.set(v - 1);
232 }
233 }
234
235 #[test]
236 #[allow(unused_variables)]
237 fn test_drop() {
238 let test_size = 1000;
239 let values_in_existence = Cell::new(test_size);
240
241 let heap = OrcHeap::with_capacity(test_size);
242
243 for _ in 0..test_size {
244 let o = heap.alloc(DropTest(&values_in_existence)).unwrap();
245 }
246 heap.collect();
247 assert_eq!(values_in_existence.get(), 0);
248 }
249
250 #[test]
251 #[allow(unused_variables)]
252 fn test_heap_freed() {
253 let test_size = 2;
254 let values_in_existence = Cell::new(5);
255
256 let heap = OrcHeap::with_capacity(test_size);
257
258 {
259 let a = heap.alloc(DropTest(&values_in_existence)).unwrap();
260 let b = heap.alloc(DropTest(&values_in_existence)).unwrap();
261 }
262 let c = heap.alloc(DropTest(&values_in_existence)).unwrap();
264 let d = heap.alloc(DropTest(&values_in_existence)).unwrap();
265 assert_eq!(values_in_existence.get(), 3); assert!(heap.alloc(DropTest(&values_in_existence)).is_err())
269 }
270}
271
272#[cfg(test)]
273mod test_concurrency {
274 extern crate crossbeam;
278 use OrcHeap;
279
280 #[test]
281 fn test_concurrency() {
282 extern crate crossbeam;
283 let test_size = 1000;
284
285 let heap = OrcHeap::with_capacity(test_size * 10);
286
287 crossbeam::scope(|scope| {
288 for _ in 0..test_size {
289 scope.spawn(|| {
290 for j in 0..test_size {
291 if let Ok(v) = heap.alloc(j) {
292 assert_eq!(*v, j);
293 }
294 }
295 });
296 }
297 });
298 }
299}