5
5
6
6
use crate :: sync:: atomic:: Ordering ;
7
7
8
- #[ cfg( target_pointer_width = "64" ) ]
9
- use crate :: sync:: atomic:: AtomicU64 ;
10
-
11
- #[ cfg( target_pointer_width = "32" ) ]
12
- use crate :: sync:: atomic:: AtomicU32 ;
8
+ use crate :: sync:: atomic:: AtomicUsize ;
13
9
14
10
/// Sets the `bit` of `x`.
15
11
#[ inline]
@@ -30,7 +26,7 @@ const fn unset_bit(x: u64, bit: u32) -> u64 {
30
26
}
31
27
32
28
/// Maximum number of features that can be cached.
33
- const CACHE_CAPACITY : u32 = 63 ;
29
+ const CACHE_CAPACITY : u32 = 62 ;
34
30
35
31
/// This type is used to initialize the cache
36
32
#[ derive( Copy , Clone ) ]
@@ -81,83 +77,51 @@ impl Initializer {
81
77
}
82
78
83
79
/// This global variable is a cache of the features supported by the CPU.
84
- static CACHE : Cache = Cache :: uninitialized ( ) ;
85
-
86
- /// Feature cache with capacity for `CACHE_CAPACITY` features.
87
- ///
88
- /// Note: the last feature bit is used to represent an
89
- /// uninitialized cache.
90
80
#[ cfg( target_pointer_width = "64" ) ]
91
- struct Cache ( AtomicU64 ) ;
81
+ static CACHE : [ Cache ; 1 ] = [ Cache :: uninitialized ( ) ] ;
92
82
93
- #[ cfg( target_pointer_width = "64" ) ]
94
- #[ allow( clippy:: use_self) ]
95
- impl Cache {
96
- /// Creates an uninitialized cache.
97
- #[ allow( clippy:: declare_interior_mutable_const) ]
98
- const fn uninitialized ( ) -> Self {
99
- Cache ( AtomicU64 :: new ( u64:: max_value ( ) ) )
100
- }
101
- /// Is the cache uninitialized?
102
- #[ inline]
103
- pub ( crate ) fn is_uninitialized ( & self ) -> bool {
104
- self . 0 . load ( Ordering :: Relaxed ) == u64:: max_value ( )
105
- }
106
-
107
- /// Is the `bit` in the cache set?
108
- #[ inline]
109
- pub ( crate ) fn test ( & self , bit : u32 ) -> bool {
110
- test_bit ( CACHE . 0 . load ( Ordering :: Relaxed ) , bit)
111
- }
112
-
113
- /// Initializes the cache.
114
- #[ inline]
115
- pub ( crate ) fn initialize ( & self , value : Initializer ) {
116
- self . 0 . store ( value. 0 , Ordering :: Relaxed ) ;
117
- }
118
- }
83
+ /// This global variable is a cache of the features supported by the CPU.
84
+ #[ cfg( target_pointer_width = "32" ) ]
85
+ static CACHE : [ Cache ; 2 ] = [ Cache :: uninitialized ( ) , Cache :: uninitialized ( ) ] ;
119
86
120
- /// Feature cache with capacity for `CACHE_CAPACITY ` features.
87
+ /// Feature cache with capacity for `usize::max_value() - 1 ` features.
121
88
///
122
89
/// Note: the last feature bit is used to represent an
123
90
/// uninitialized cache.
124
- #[ cfg( target_pointer_width = "32" ) ]
125
- struct Cache ( AtomicU32 , AtomicU32 ) ;
91
+ ///
92
+ /// Note: we use `Relaxed` atomic operations, because we are only interested
93
+ /// in the effects of operations on a single memory location. That is, we only
94
+ /// need "modification order", and not the full-blown "happens before".
95
+ struct Cache ( AtomicUsize ) ;
126
96
127
- #[ cfg( target_pointer_width = "32" ) ]
128
97
impl Cache {
98
+ const CAPACITY : u32 = ( std:: mem:: size_of :: < usize > ( ) * 8 - 1 ) as u32 ;
99
+ const MASK : usize = ( 1 << Cache :: CAPACITY ) - 1 ;
100
+
129
101
/// Creates an uninitialized cache.
102
+ #[ allow( clippy:: declare_interior_mutable_const) ]
130
103
const fn uninitialized ( ) -> Self {
131
- Cache (
132
- AtomicU32 :: new ( u32:: max_value ( ) ) ,
133
- AtomicU32 :: new ( u32:: max_value ( ) ) ,
134
- )
104
+ Cache ( AtomicUsize :: new ( usize:: max_value ( ) ) )
135
105
}
136
106
/// Is the cache uninitialized?
137
107
#[ inline]
138
108
pub ( crate ) fn is_uninitialized ( & self ) -> bool {
139
- self . 1 . load ( Ordering :: Relaxed ) == u32 :: max_value ( )
109
+ self . 0 . load ( Ordering :: Relaxed ) == usize :: max_value ( )
140
110
}
141
111
142
112
/// Is the `bit` in the cache set?
143
113
#[ inline]
144
114
pub ( crate ) fn test ( & self , bit : u32 ) -> bool {
145
- if bit < 32 {
146
- test_bit ( CACHE . 0 . load ( Ordering :: Relaxed ) as u64 , bit)
147
- } else {
148
- test_bit ( CACHE . 1 . load ( Ordering :: Relaxed ) as u64 , bit - 32 )
149
- }
115
+ test_bit ( self . 0 . load ( Ordering :: Relaxed ) as u64 , bit)
150
116
}
151
117
152
118
/// Initializes the cache.
153
119
#[ inline]
154
- pub ( crate ) fn initialize ( & self , value : Initializer ) {
155
- let lo: u32 = value. 0 as u32 ;
156
- let hi: u32 = ( value. 0 >> 32 ) as u32 ;
157
- self . 0 . store ( lo, Ordering :: Relaxed ) ;
158
- self . 1 . store ( hi, Ordering :: Relaxed ) ;
120
+ fn initialize ( & self , value : usize ) {
121
+ self . 0 . store ( value, Ordering :: Relaxed ) ;
159
122
}
160
123
}
124
+
161
125
cfg_if:: cfg_if! {
162
126
if #[ cfg( feature = "std_detect_env_override" ) ] {
163
127
#[ inline( never) ]
@@ -167,16 +131,25 @@ cfg_if::cfg_if! {
167
131
let _ = super :: Feature :: from_str( v) . map( |v| value. unset( v as u32 ) ) ;
168
132
}
169
133
}
170
- CACHE . initialize ( value) ;
134
+ do_initialize ( value) ;
171
135
}
172
136
} else {
173
137
#[ inline]
174
138
fn initialize( value: Initializer ) {
175
- CACHE . initialize ( value) ;
139
+ do_initialize ( value) ;
176
140
}
177
141
}
178
142
}
179
143
144
+ #[ inline]
145
+ fn do_initialize ( value : Initializer ) {
146
+ CACHE [ 0 ] . initialize ( ( value. 0 ) as usize & Cache :: MASK ) ;
147
+ #[ cfg( target_pointer_width = "32" ) ]
148
+ {
149
+ CACHE [ 1 ] . initialize ( ( value. 0 >> Cache :: CAPACITY ) as usize & Cache :: MASK ) ;
150
+ }
151
+ }
152
+
180
153
/// Tests the `bit` of the storage. If the storage has not been initialized,
181
154
/// initializes it with the result of `f()`.
182
155
///
@@ -194,8 +167,18 @@ pub(crate) fn test<F>(bit: u32, f: F) -> bool
194
167
where
195
168
F : FnOnce ( ) -> Initializer ,
196
169
{
197
- if CACHE . is_uninitialized ( ) {
198
- initialize ( f ( ) ) ;
170
+ #[ cfg( target_pointer_width = "32" ) ]
171
+ {
172
+ if bit >= Cache :: CAPACITY {
173
+ if CACHE [ 1 ] . is_uninitialized ( ) {
174
+ initialize ( f ( ) )
175
+ }
176
+ return CACHE [ 1 ] . test ( bit - Cache :: CAPACITY ) ;
177
+ }
178
+ }
179
+
180
+ if CACHE [ 0 ] . is_uninitialized ( ) {
181
+ initialize ( f ( ) )
199
182
}
200
- CACHE . test ( bit)
183
+ CACHE [ 0 ] . test ( bit)
201
184
}
0 commit comments