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