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