1*76612720Slogin // Copyright (C) DragonOS Community longjin 2*76612720Slogin 3*76612720Slogin // This program is free software; you can redistribute it and/or 4*76612720Slogin // modify it under the terms of the GNU General Public License 5*76612720Slogin // as published by the Free Software Foundation; either version 2 6*76612720Slogin // of the License, or (at your option) any later version. 7*76612720Slogin 8*76612720Slogin // This program is distributed in the hope that it will be useful, 9*76612720Slogin // but WITHOUT ANY WARRANTY; without even the implied warranty of 10*76612720Slogin // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11*76612720Slogin // GNU General Public License for more details. 12*76612720Slogin 13*76612720Slogin // You should have received a copy of the GNU General Public License 14*76612720Slogin // along with this program; if not, write to the Free Software 15*76612720Slogin // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16*76612720Slogin // Or you can visit https://www.gnu.org/licenses/gpl-2.0.html 17*76612720Slogin #![allow(dead_code)] 18*76612720Slogin 19*76612720Slogin use core::cell::UnsafeCell; 20*76612720Slogin use core::fmt::Debug; 21*76612720Slogin use core::mem::MaybeUninit; 22*76612720Slogin use core::ops::{Deref, DerefMut}; 23*76612720Slogin use core::sync::atomic::{AtomicBool, Ordering}; 24*76612720Slogin 25*76612720Slogin use super::spinlock::SpinLock; 26*76612720Slogin 27*76612720Slogin /// A wrapper around a value that is initialized lazily. 28*76612720Slogin /// The value is initialized the first time it is accessed. 29*76612720Slogin /// This is useful for initializing values that are expensive to initialize. 30*76612720Slogin /// The value is initialized using the provided closure. 31*76612720Slogin /// The closure is only called once, and the result is cached. 32*76612720Slogin /// The value is not initialized if it is never accessed. 33*76612720Slogin pub struct Lazy<T: Sync> { 34*76612720Slogin /// The lock that is used to ensure that only one thread calls the init function at the same time. 35*76612720Slogin init_lock: SpinLock<()>, 36*76612720Slogin /// The value that is initialized lazily. 37*76612720Slogin value: UnsafeCell<MaybeUninit<T>>, 38*76612720Slogin /// Whether the value has been initialized. 39*76612720Slogin initialized: AtomicBool, 40*76612720Slogin } 41*76612720Slogin 42*76612720Slogin impl<T: Sync> Lazy<T> { 43*76612720Slogin /// Creates a new `Lazy` value that will be initialized with the 44*76612720Slogin /// result of the closure `init`. 45*76612720Slogin pub const fn new() -> Lazy<T> { 46*76612720Slogin Lazy { 47*76612720Slogin value: UnsafeCell::new(MaybeUninit::uninit()), 48*76612720Slogin initialized: AtomicBool::new(false), 49*76612720Slogin init_lock: SpinLock::new(()), 50*76612720Slogin } 51*76612720Slogin } 52*76612720Slogin 53*76612720Slogin /// Returns true if the value has been initialized. 54*76612720Slogin #[inline(always)] 55*76612720Slogin pub fn initialized(&self) -> bool { 56*76612720Slogin let initialized = self.initialized.load(Ordering::Acquire); 57*76612720Slogin if initialized { 58*76612720Slogin return true; 59*76612720Slogin } 60*76612720Slogin return false; 61*76612720Slogin } 62*76612720Slogin 63*76612720Slogin /// Ensures that this lazy value is initialized. If the value has not 64*76612720Slogin /// yet been initialized, this will raise a panic. 65*76612720Slogin #[inline(always)] 66*76612720Slogin pub fn ensure(&self) { 67*76612720Slogin if self.initialized() { 68*76612720Slogin return; 69*76612720Slogin } 70*76612720Slogin panic!("Lazy value was not initialized"); 71*76612720Slogin } 72*76612720Slogin 73*76612720Slogin pub fn init(&self, value: T) { 74*76612720Slogin assert!(!self.initialized()); 75*76612720Slogin 76*76612720Slogin // We need this lock to ensure that only one thread calls the init function at the same time. 77*76612720Slogin let _init_guard = self.init_lock.lock(); 78*76612720Slogin // Check again, in case another thread initialized it while we were waiting for the lock. 79*76612720Slogin let initialized = self.initialized(); 80*76612720Slogin if initialized { 81*76612720Slogin return; 82*76612720Slogin } 83*76612720Slogin unsafe { 84*76612720Slogin (*self.value.get()).as_mut_ptr().write(value); 85*76612720Slogin } 86*76612720Slogin self.initialized.store(true, Ordering::Release); 87*76612720Slogin } 88*76612720Slogin /// Forces the evaluation of this lazy value and returns a reference to 89*76612720Slogin /// the result. This is equivalent to the `Deref` impl, but is explicit. 90*76612720Slogin /// This will initialize the value if it has not yet been initialized. 91*76612720Slogin pub fn get(&self) -> &T { 92*76612720Slogin self.ensure(); 93*76612720Slogin return unsafe { self.get_unchecked() }; 94*76612720Slogin } 95*76612720Slogin 96*76612720Slogin /// Returns a reference to the value if it has been initialized. 97*76612720Slogin /// Otherwise, returns `None`. 98*76612720Slogin pub fn try_get(&self) -> Option<&T> { 99*76612720Slogin if self.initialized() { 100*76612720Slogin return Some(unsafe { self.get_unchecked() }); 101*76612720Slogin } 102*76612720Slogin return None; 103*76612720Slogin } 104*76612720Slogin 105*76612720Slogin /// Forces the evaluation of this lazy value and returns a mutable 106*76612720Slogin /// reference to the result. This is equivalent to the `DerefMut` impl, 107*76612720Slogin /// but is explicit. This will initialize the value if it has not yet 108*76612720Slogin /// been initialized. 109*76612720Slogin pub fn get_mut(&mut self) -> &mut T { 110*76612720Slogin self.ensure(); 111*76612720Slogin return unsafe { self.get_mut_unchecked() }; 112*76612720Slogin } 113*76612720Slogin 114*76612720Slogin #[inline(always)] 115*76612720Slogin pub unsafe fn get_unchecked(&self) -> &T { 116*76612720Slogin return &*(*self.value.get()).as_ptr(); 117*76612720Slogin } 118*76612720Slogin 119*76612720Slogin #[inline(always)] 120*76612720Slogin pub unsafe fn get_mut_unchecked(&mut self) -> &mut T { 121*76612720Slogin return &mut *(*self.value.get()).as_mut_ptr(); 122*76612720Slogin } 123*76612720Slogin } 124*76612720Slogin 125*76612720Slogin impl<T: Sync> Deref for Lazy<T> { 126*76612720Slogin type Target = T; 127*76612720Slogin 128*76612720Slogin #[inline(always)] 129*76612720Slogin fn deref(&self) -> &T { 130*76612720Slogin return self.get(); 131*76612720Slogin } 132*76612720Slogin } 133*76612720Slogin 134*76612720Slogin impl<T: Sync> DerefMut for Lazy<T> { 135*76612720Slogin #[inline(always)] 136*76612720Slogin fn deref_mut(&mut self) -> &mut T { 137*76612720Slogin return self.get_mut(); 138*76612720Slogin } 139*76612720Slogin } 140*76612720Slogin 141*76612720Slogin impl<T: Sync + Debug> Debug for Lazy<T> { 142*76612720Slogin fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 143*76612720Slogin if let Some(value) = self.try_get() { 144*76612720Slogin return write!(f, "Lazy({:?})", value); 145*76612720Slogin } else { 146*76612720Slogin return write!(f, "Lazy(uninitialized)"); 147*76612720Slogin } 148*76612720Slogin } 149*76612720Slogin } 150*76612720Slogin 151*76612720Slogin impl<T: Sync> Drop for Lazy<T> { 152*76612720Slogin fn drop(&mut self) { 153*76612720Slogin if self.initialized() { 154*76612720Slogin unsafe { 155*76612720Slogin (*self.value.get()).as_mut_ptr().drop_in_place(); 156*76612720Slogin } 157*76612720Slogin } 158*76612720Slogin } 159*76612720Slogin } 160