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 pub struct Lazy<T> { 29 /// The lock that is used to ensure that only one thread calls the init function at the same time. 30 init_lock: SpinLock<()>, 31 /// The value that is initialized lazily. 32 value: UnsafeCell<MaybeUninit<T>>, 33 /// Whether the value has been initialized. 34 initialized: AtomicBool, 35 } 36 37 impl<T> Lazy<T> { 38 /// Creates a new `Lazy` value that will be initialized with the 39 /// result of the closure `init`. new() -> Lazy<T>40 pub const fn new() -> Lazy<T> { 41 Lazy { 42 value: UnsafeCell::new(MaybeUninit::uninit()), 43 initialized: AtomicBool::new(false), 44 init_lock: SpinLock::new(()), 45 } 46 } 47 48 /// Returns true if the value has been initialized. 49 #[inline(always)] initialized(&self) -> bool50 pub fn initialized(&self) -> bool { 51 let initialized = self.initialized.load(Ordering::Acquire); 52 if initialized { 53 return true; 54 } 55 return false; 56 } 57 58 /// Ensures that this lazy value is initialized. If the value has not 59 /// yet been initialized, this will raise a panic. 60 #[inline(always)] ensure(&self)61 pub fn ensure(&self) { 62 if self.initialized() { 63 return; 64 } 65 panic!("Lazy value was not initialized"); 66 } 67 init(&self, value: T)68 pub fn init(&self, value: T) { 69 assert!(!self.initialized()); 70 71 // We need this lock to ensure that only one thread calls the init function at the same time. 72 let _init_guard = self.init_lock.lock(); 73 // Check again, in case another thread initialized it while we were waiting for the lock. 74 let initialized = self.initialized(); 75 if initialized { 76 return; 77 } 78 unsafe { 79 (*self.value.get()).as_mut_ptr().write(value); 80 } 81 self.initialized.store(true, Ordering::Release); 82 } 83 /// Forces the evaluation of this lazy value and returns a reference to 84 /// the result. This is equivalent to the `Deref` impl, but is explicit. 85 /// This will initialize the value if it has not yet been initialized. get(&self) -> &T86 pub fn get(&self) -> &T { 87 self.ensure(); 88 return unsafe { self.get_unchecked() }; 89 } 90 91 /// Returns a reference to the value if it has been initialized. 92 /// Otherwise, returns `None`. try_get(&self) -> Option<&T>93 pub fn try_get(&self) -> Option<&T> { 94 if self.initialized() { 95 return Some(unsafe { self.get_unchecked() }); 96 } 97 return None; 98 } 99 100 /// Forces the evaluation of this lazy value and returns a mutable 101 /// reference to the result. This is equivalent to the `DerefMut` impl, 102 /// but is explicit. This will initialize the value if it has not yet 103 /// been initialized. get_mut(&mut self) -> &mut T104 pub fn get_mut(&mut self) -> &mut T { 105 self.ensure(); 106 return unsafe { self.get_mut_unchecked() }; 107 } 108 109 #[inline(always)] get_unchecked(&self) -> &T110 pub unsafe fn get_unchecked(&self) -> &T { 111 return &*(*self.value.get()).as_ptr(); 112 } 113 114 #[inline(always)] get_mut_unchecked(&mut self) -> &mut T115 pub unsafe fn get_mut_unchecked(&mut self) -> &mut T { 116 return &mut *(*self.value.get()).as_mut_ptr(); 117 } 118 } 119 120 impl<T> Deref for Lazy<T> { 121 type Target = T; 122 123 #[inline(always)] deref(&self) -> &T124 fn deref(&self) -> &T { 125 return self.get(); 126 } 127 } 128 129 impl<T> DerefMut for Lazy<T> { 130 #[inline(always)] deref_mut(&mut self) -> &mut T131 fn deref_mut(&mut self) -> &mut T { 132 return self.get_mut(); 133 } 134 } 135 136 impl<T: Debug> Debug for Lazy<T> { fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result137 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 138 if let Some(value) = self.try_get() { 139 return write!(f, "Lazy({:?})", value); 140 } else { 141 return write!(f, "Lazy(uninitialized)"); 142 } 143 } 144 } 145 146 impl<T> Drop for Lazy<T> { drop(&mut self)147 fn drop(&mut self) { 148 if self.initialized() { 149 unsafe { 150 (*self.value.get()).as_mut_ptr().drop_in_place(); 151 } 152 } 153 } 154 } 155 156 unsafe impl<T: Send + Sync> Sync for Lazy<T> {} 157 unsafe impl<T: Send> Send for Lazy<T> {} 158