From a4b6351237808786d2c23a7c3a00d14972cfeda6 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 11 Oct 2024 17:49:42 +0200 Subject: [PATCH] Invent a once box. --- src/local_array/oncebox.rs | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/local_array/oncebox.rs diff --git a/src/local_array/oncebox.rs b/src/local_array/oncebox.rs new file mode 100644 index 0000000..f139d41 --- /dev/null +++ b/src/local_array/oncebox.rs @@ -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 { + ptr: AtomicPtr +} + +impl OnceBox { + 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 Drop for OnceBox { + fn drop(&mut self) { + let ptr = self.ptr.swap(null_mut(), Ordering::Relaxed); + if !ptr.is_null() { + let _ = unsafe { Box::from_raw(ptr) }; + } + } +} +