Skip to content

Commit

Permalink
Invent a once box.
Browse files Browse the repository at this point in the history
  • Loading branch information
partim committed Oct 11, 2024
1 parent aca1ad4 commit a4b6351
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions src/local_array/oncebox.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::thread;
use std::ptr::null_mut;
use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, Ordering};


pub struct OnceBox<T> {
ptr: AtomicPtr<T>
}

impl<T> OnceBox<T> {
pub fn null() -> Self {
Self {
ptr: AtomicPtr::new(null_mut())
}
}

pub fn get(&self) -> Option<&T> {
let ptr = self.ptr.load(Ordering::Relaxed);
if ptr == null_mut() {
None
}
else {
Some(unsafe { &*ptr })
}
}

pub fn get_or_set(&self, value: T) -> &T {
let ptr = Box::leak(Box::new(value));
let res = match self.ptr.compare_exchange(
null_mut(), ptr, Ordering::SeqCst, Ordering::Acquire
) {
Ok(current) => {
// We set the new value, return it.
assert!(current.is_null());
ptr as *const _
}
Err(current) => {
// `current` is the real value we need to drop our value.
assert!(!current.is_null());
let _ = unsafe { Box::from_raw(ptr) };
current as *const _
}
};
unsafe { &*res }
}
}

impl<T> Drop for OnceBox<T> {
fn drop(&mut self) {
let ptr = self.ptr.swap(null_mut(), Ordering::Relaxed);
if !ptr.is_null() {
let _ = unsafe { Box::from_raw(ptr) };
}
}
}

0 comments on commit a4b6351

Please sign in to comment.