1
1
use std:: {
2
2
cell:: UnsafeCell ,
3
- mem :: { self , MaybeUninit } ,
3
+ hint ,
4
4
panic:: { RefUnwindSafe , UnwindSafe } ,
5
- ptr,
6
5
sync:: atomic:: { AtomicBool , Ordering } ,
7
6
} ;
8
7
@@ -11,7 +10,7 @@ use parking_lot::Mutex;
11
10
pub ( crate ) struct OnceCell < T > {
12
11
mutex : Mutex < ( ) > ,
13
12
is_initialized : AtomicBool ,
14
- value : UnsafeCell < MaybeUninit < T > > ,
13
+ value : UnsafeCell < Option < T > > ,
15
14
}
16
15
17
16
// Why do we need `T: Send`?
@@ -30,7 +29,7 @@ impl<T> OnceCell<T> {
30
29
OnceCell {
31
30
mutex : parking_lot:: const_mutex ( ( ) ) ,
32
31
is_initialized : AtomicBool :: new ( false ) ,
33
- value : UnsafeCell :: new ( MaybeUninit :: uninit ( ) ) ,
32
+ value : UnsafeCell :: new ( None ) ,
34
33
}
35
34
}
36
35
@@ -60,7 +59,9 @@ impl<T> OnceCell<T> {
60
59
let value = f ( ) ?;
61
60
// Safe b/c we have a unique access and no panic may happen
62
61
// until the cell is marked as initialized.
63
- unsafe { self . as_mut_ptr ( ) . write ( value) } ;
62
+ let slot: & mut Option < T > = unsafe { & mut * self . value . get ( ) } ;
63
+ debug_assert ! ( slot. is_none( ) ) ;
64
+ * slot = Some ( value) ;
64
65
self . is_initialized . store ( true , Ordering :: Release ) ;
65
66
}
66
67
Ok ( ( ) )
@@ -75,58 +76,29 @@ impl<T> OnceCell<T> {
75
76
/// the contents are acquired by (synchronized to) this thread.
76
77
pub ( crate ) unsafe fn get_unchecked ( & self ) -> & T {
77
78
debug_assert ! ( self . is_initialized( ) ) ;
78
- & * self . as_ptr ( )
79
+ let slot: & Option < T > = & * self . value . get ( ) ;
80
+ match slot {
81
+ Some ( value) => value,
82
+ // This unsafe does improve performance, see `examples/bench`.
83
+ None => {
84
+ debug_assert ! ( false ) ;
85
+ hint:: unreachable_unchecked ( )
86
+ }
87
+ }
79
88
}
80
89
81
90
/// Gets the mutable reference to the underlying value.
82
91
/// Returns `None` if the cell is empty.
83
92
pub ( crate ) fn get_mut ( & mut self ) -> Option < & mut T > {
84
- if self . is_initialized ( ) {
85
- // Safe b/c we have a unique access and value is initialized.
86
- Some ( unsafe { & mut * self . as_mut_ptr ( ) } )
87
- } else {
88
- None
89
- }
93
+ // Safe b/c we have an exclusive access
94
+ let slot: & mut Option < T > = unsafe { & mut * self . value . get ( ) } ;
95
+ slot. as_mut ( )
90
96
}
91
97
92
98
/// Consumes this `OnceCell`, returning the wrapped value.
93
99
/// Returns `None` if the cell was empty.
94
100
pub ( crate ) fn into_inner ( self ) -> Option < T > {
95
- if !self . is_initialized ( ) {
96
- return None ;
97
- }
98
-
99
- // Safe b/c we have a unique access and value is initialized.
100
- let value: T = unsafe { ptr:: read ( self . as_ptr ( ) ) } ;
101
-
102
- // It's OK to `mem::forget` without dropping, because both `self.mutex`
103
- // and `self.is_initialized` are not heap-allocated.
104
- mem:: forget ( self ) ;
105
-
106
- Some ( value)
107
- }
108
-
109
- fn as_ptr ( & self ) -> * const T {
110
- unsafe {
111
- let slot: & MaybeUninit < T > = & * self . value . get ( ) ;
112
- slot. as_ptr ( )
113
- }
114
- }
115
-
116
- fn as_mut_ptr ( & self ) -> * mut T {
117
- unsafe {
118
- let slot: & mut MaybeUninit < T > = & mut * self . value . get ( ) ;
119
- slot. as_mut_ptr ( )
120
- }
121
- }
122
- }
123
-
124
- impl < T > Drop for OnceCell < T > {
125
- fn drop ( & mut self ) {
126
- if self . is_initialized ( ) {
127
- // Safe b/c we have a unique access and value is initialized.
128
- unsafe { ptr:: drop_in_place ( self . as_mut_ptr ( ) ) } ;
129
- }
101
+ self . value . into_inner ( )
130
102
}
131
103
}
132
104
0 commit comments