@@ -69,8 +69,6 @@ pub struct AtomicVal[T] {
6969// new_atomic creates a new atomic value of `T` type
7070@[inline]
7171pub fn new_atomic [T](val T) & AtomicVal[T] {
72- // can't use `$if T is $int || T is bool` with $compile_error() now
73- // see issue #24562
7472 $if T is $int {
7573 return & AtomicVal[T]{
7674 val: val
@@ -79,8 +77,12 @@ pub fn new_atomic[T](val T) &AtomicVal[T] {
7977 return & AtomicVal[T]{
8078 val: val
8179 }
80+ } $else $if T is voidptr {
81+ return & AtomicVal[T]{
82+ val: val
83+ }
8284 } $else {
83- $compile_error ('atomic: only support number and bool types' )
85+ $compile_error ('atomic: only support number, bool, and voidptr types' )
8486 }
8587 return unsafe { nil }
8688}
@@ -99,19 +101,24 @@ pub fn (mut a AtomicVal[T]) load() T {
99101 } $else $if T is u64 || T is i64 {
100102 return T (C.atomic_load_u64 (voidptr (& a.val)))
101103 } $else $if T is int {
102- // TODO: remove this test or a compile time support $if sizeof() ==
103104 if sizeof (int ) == 4 {
104105 return int (C.atomic_load_u32 (voidptr (& a.val)))
105106 } else {
106107 return int (C.atomic_load_u64 (voidptr (& a.val)))
107108 }
108109 } $else $if T is isize || T is usize {
109- // TODO: remove this test or a compile time support $if sizeof() ==
110110 if sizeof (isize) == 4 {
111111 return T (C.atomic_load_u32 (voidptr (& a.val)))
112112 } else {
113113 return T (C.atomic_load_u64 (voidptr (& a.val)))
114114 }
115+ } $else $if T is voidptr {
116+ // TODO: this should be $if sizeof(T) == 4
117+ $if x32 {
118+ return T (C.atomic_load_u32 (voidptr (& a.val)))
119+ } $else {
120+ return T (C.atomic_load_u64 (voidptr (& a.val)))
121+ }
115122 }
116123 return a.val
117124}
@@ -120,90 +127,207 @@ pub fn (mut a AtomicVal[T]) load() T {
120127@[inline]
121128pub fn (mut a AtomicVal[T]) store (val T) {
122129 $if T is bool {
123- C.atomic_store_byte (voidptr (& a.val), val)
130+ C.atomic_store_byte (voidptr (& a.val), u8 ( val) )
124131 } $else $if T is u8 || T is i8 {
125- C.atomic_store_byte (voidptr (& a.val), val)
132+ C.atomic_store_byte (voidptr (& a.val), u8 ( val) )
126133 } $else $if T is u16 || T is i16 {
127- C.atomic_store_u16 (voidptr (& a.val), val)
134+ C.atomic_store_u16 (voidptr (& a.val), u16 ( val) )
128135 } $else $if T is u32 || T is i32 {
129- C.atomic_store_u32 (voidptr (& a.val), val)
136+ C.atomic_store_u32 (voidptr (& a.val), u32 ( val) )
130137 } $else $if T is u64 || T is i64 {
131- C.atomic_store_u64 (voidptr (& a.val), val)
138+ C.atomic_store_u64 (voidptr (& a.val), u64 ( val) )
132139 } $else $if T is int {
133- // TODO: remove this test or a compile time support $if sizeof() ==
134140 if sizeof (int ) == 4 {
135- C.atomic_store_u32 (voidptr (& a.val), val)
141+ C.atomic_store_u32 (voidptr (& a.val), u32 ( val) )
136142 } else {
137- C.atomic_store_u64 (voidptr (& a.val), val)
143+ C.atomic_store_u64 (voidptr (& a.val), u64 ( val) )
138144 }
139145 } $else $if T is isize || T is usize {
140- // TODO: remove this test or a compile time support $if sizeof() ==
141146 if sizeof (isize) == 4 {
142- C.atomic_store_u32 (voidptr (& a.val), val)
147+ C.atomic_store_u32 (voidptr (& a.val), u32 ( val) )
143148 } else {
144- C.atomic_store_u64 (voidptr (& a.val), val)
149+ C.atomic_store_u64 (voidptr (& a.val), u64 (val))
150+ }
151+ } $else $if T is voidptr {
152+ // TODO: this should be $if sizeof(T) == 4
153+ $if x32 {
154+ C.atomic_store_u32 (voidptr (& a.val), u32 (val))
155+ } $else {
156+ C.atomic_store_u64 (voidptr (& a.val), u64 (val))
145157 }
146158 }
147159}
148160
149- // add adds the atomic value with `delta`
161+ // add adds the atomic value with `delta` and returns the previous value
150162@[inline]
151163pub fn (mut a AtomicVal[T]) add (delta T) T {
152164 $if T is bool {
153- panic ('atomic: can not add() a bool type' )
165+ panic ('atomic: add() not supported for bool type' )
166+ } $else $if T is voidptr {
167+ panic ('atomic: add() not supported for voidptr type' )
154168 } $else $if T is u8 || T is i8 {
155- C.atomic_fetch_add_byte (voidptr (& a.val), delta)
169+ old := C.atomic_fetch_add_byte (voidptr (& a.val), u8 (delta))
170+ return T (old)
156171 } $else $if T is u16 || T is i16 {
157- C.atomic_fetch_add_u16 (voidptr (& a.val), delta)
172+ old := C.atomic_fetch_add_u16 (voidptr (& a.val), u16 (delta))
173+ return T (old)
158174 } $else $if T is u32 || T is i32 {
159- C.atomic_fetch_add_u32 (voidptr (& a.val), delta)
175+ old := C.atomic_fetch_add_u32 (voidptr (& a.val), u32 (delta))
176+ return T (old)
160177 } $else $if T is u64 || T is i64 {
161- C.atomic_fetch_add_u64 (voidptr (& a.val), delta)
178+ old := C.atomic_fetch_add_u64 (voidptr (& a.val), u64 (delta))
179+ return T (old)
162180 } $else $if T is int {
163- // TODO: remove this test or a compile time support $if sizeof() ==
164181 if sizeof (int ) == 4 {
165- C.atomic_fetch_add_u32 (voidptr (& a.val), delta)
182+ old := C.atomic_fetch_add_u32 (voidptr (& a.val), u32 (delta))
183+ return T (old)
166184 } else {
167- C.atomic_fetch_add_u64 (voidptr (& a.val), delta)
185+ old := C.atomic_fetch_add_u64 (voidptr (& a.val), u64 (delta))
186+ return T (old)
168187 }
169188 } $else $if T is isize || T is usize {
170- // TODO: remove this test or a compile time support $if sizeof() ==
171189 if sizeof (isize) == 4 {
172- C.atomic_fetch_add_u32 (voidptr (& a.val), delta)
190+ old := C.atomic_fetch_add_u32 (voidptr (& a.val), u32 (delta))
191+ return T (old)
173192 } else {
174- C.atomic_fetch_add_u64 (voidptr (& a.val), delta)
193+ old := C.atomic_fetch_add_u64 (voidptr (& a.val), u64 (delta))
194+ return T (old)
175195 }
176196 }
177- return T (a.val )
197+ panic ( 'unreachable' )
178198}
179199
180- // sub subs the atomic value with `delta`
200+ // sub subtracts the atomic value with `delta` and returns the previous value
181201@[inline]
182202pub fn (mut a AtomicVal[T]) sub (delta T) T {
183203 $if T is bool {
184- panic ('atomic: can not sub() a bool type' )
204+ panic ('atomic: sub() not supported for bool type' )
205+ } $else $if T is voidptr {
206+ panic ('atomic: sub() not supported for voidptr type' )
185207 } $else $if T is u8 || T is i8 {
186- C.atomic_fetch_sub_byte (voidptr (& a.val), delta)
208+ old := C.atomic_fetch_sub_byte (voidptr (& a.val), u8 (delta))
209+ return T (old)
187210 } $else $if T is u16 || T is i16 {
188- C.atomic_fetch_sub_u16 (voidptr (& a.val), delta)
211+ old := C.atomic_fetch_sub_u16 (voidptr (& a.val), u16 (delta))
212+ return T (old)
189213 } $else $if T is u32 || T is i32 {
190- C.atomic_fetch_sub_u32 (voidptr (& a.val), delta)
214+ old := C.atomic_fetch_sub_u32 (voidptr (& a.val), u32 (delta))
215+ return T (old)
191216 } $else $if T is u64 || T is i64 {
192- C.atomic_fetch_sub_u64 (voidptr (& a.val), delta)
217+ old := C.atomic_fetch_sub_u64 (voidptr (& a.val), u64 (delta))
218+ return T (old)
193219 } $else $if T is int {
194- // TODO: remove this test or a compile time support $if sizeof() ==
195220 if sizeof (int ) == 4 {
196- C.atomic_fetch_sub_u32 (voidptr (& a.val), delta)
221+ old := C.atomic_fetch_sub_u32 (voidptr (& a.val), u32 (delta))
222+ return T (old)
197223 } else {
198- C.atomic_fetch_sub_u64 (voidptr (& a.val), delta)
224+ old := C.atomic_fetch_sub_u64 (voidptr (& a.val), u64 (delta))
225+ return T (old)
199226 }
200227 } $else $if T is isize || T is usize {
201- // TODO: remove this test or a compile time support $if sizeof() ==
202228 if sizeof (isize) == 4 {
203- C.atomic_fetch_sub_u32 (voidptr (& a.val), delta)
229+ old := C.atomic_fetch_sub_u32 (voidptr (& a.val), u32 (delta))
230+ return T (old)
231+ } else {
232+ old := C.atomic_fetch_sub_u64 (voidptr (& a.val), u64 (delta))
233+ return T (old)
234+ }
235+ }
236+ panic ('unreachable' )
237+ }
238+
239+ // swap sets the `new` value and returns the previous value
240+ @[inline]
241+ pub fn (mut a AtomicVal[T]) swap (new T) T {
242+ $if T is bool {
243+ old := C.atomic_exchange_byte (voidptr (& a.val), u8 (new))
244+ return old != 0
245+ } $else $if T is u8 || T is i8 {
246+ old := C.atomic_exchange_byte (voidptr (& a.val), u8 (new))
247+ return T (old)
248+ } $else $if T is u16 || T is i16 {
249+ old := C.atomic_exchange_u16 (voidptr (& a.val), u16 (new))
250+ return T (old)
251+ } $else $if T is u32 || T is i32 {
252+ old := C.atomic_exchange_u32 (voidptr (& a.val), u32 (new))
253+ return T (old)
254+ } $else $if T is u64 || T is i64 {
255+ old := C.atomic_exchange_u64 (voidptr (& a.val), u64 (new))
256+ return T (old)
257+ } $else $if T is int {
258+ if sizeof (int ) == 4 {
259+ old := C.atomic_exchange_u32 (voidptr (& a.val), u32 (new))
260+ return T (old)
204261 } else {
205- C.atomic_fetch_sub_u64 (voidptr (& a.val), delta)
262+ old := C.atomic_exchange_u64 (voidptr (& a.val), u64 (new))
263+ return T (old)
264+ }
265+ } $else $if T is isize || T is usize {
266+ if sizeof (isize) == 4 {
267+ old := C.atomic_exchange_u32 (voidptr (& a.val), u32 (new))
268+ return T (old)
269+ } else {
270+ old := C.atomic_exchange_u64 (voidptr (& a.val), u64 (new))
271+ return T (old)
272+ }
273+ } $else $if T is voidptr {
274+ // TODO: this should be $if sizeof(T) == 4
275+ $if x32 {
276+ old := C.atomic_exchange_u32 (voidptr (& a.val), u32 (new))
277+ return T (old)
278+ } $else {
279+ old := C.atomic_exchange_u64 (voidptr (& a.val), u64 (new))
280+ return T (old)
281+ }
282+ }
283+ panic ('unreachable' )
284+ }
285+
286+ // compare_and_swap executes the compare-and-swap(CAS) operation
287+ // if atomic value == `expected`, then it will be set to `new`, and return true
288+ // else return false, and the atomic value remains unchanged
289+ @[inline]
290+ pub fn (mut a AtomicVal[T]) compare_and_swap (expected T, new T) bool {
291+ $if T is bool {
292+ mut exp := u8 (expected)
293+ return C.atomic_compare_exchange_strong_byte (voidptr (& a.val), & exp, u8 (new))
294+ } $else $if T is u8 || T is i8 {
295+ mut exp := u8 (expected)
296+ return C.atomic_compare_exchange_strong_byte (voidptr (& a.val), & exp, u8 (new))
297+ } $else $if T is u16 || T is i16 {
298+ mut exp := u16 (expected)
299+ return C.atomic_compare_exchange_strong_u16 (voidptr (& a.val), & exp, u16 (new))
300+ } $else $if T is u32 || T is i32 {
301+ mut exp := u32 (expected)
302+ return C.atomic_compare_exchange_strong_u32 (voidptr (& a.val), & exp, u32 (new))
303+ } $else $if T is u64 || T is i64 {
304+ mut exp := u64 (expected)
305+ return C.atomic_compare_exchange_strong_u64 (voidptr (& a.val), & exp, u64 (new))
306+ } $else $if T is int {
307+ if sizeof (int ) == 4 {
308+ mut exp := u32 (expected)
309+ return C.atomic_compare_exchange_strong_u32 (voidptr (& a.val), & exp, u32 (new))
310+ } else {
311+ mut exp := u64 (expected)
312+ return C.atomic_compare_exchange_strong_u64 (voidptr (& a.val), & exp, u64 (new))
313+ }
314+ } $else $if T is isize || T is usize {
315+ if sizeof (isize) == 4 {
316+ mut exp := u32 (expected)
317+ return C.atomic_compare_exchange_strong_u32 (voidptr (& a.val), & exp, u32 (new))
318+ } else {
319+ mut exp := u64 (expected)
320+ return C.atomic_compare_exchange_strong_u64 (voidptr (& a.val), & exp, u64 (new))
321+ }
322+ } $else $if T is voidptr {
323+ // TODO: this should be $if sizeof(T) == 4
324+ $if x32 {
325+ mut exp := u32 (expected)
326+ return C.atomic_compare_exchange_strong_u32 (voidptr (& a.val), & exp, u32 (new))
327+ } $else {
328+ mut exp := u64 (expected)
329+ return C.atomic_compare_exchange_strong_u64 (voidptr (& a.val), & exp, u64 (new))
206330 }
207331 }
208- return T (a.val )
332+ panic ( 'unreachable' )
209333}
0 commit comments