33// a copy of which can be found in the LICENSE_STDLIB file.
44module std ::atomic ::types ;
55
6+ <*
7+ A wrapper providing atomic load, store and read-modify-write operations over a
8+ single value of `Type`. All operations default to SEQ_CONSISTENT ordering.
9+ *>
610struct Atomic <Type >
711{
812 Type data ;
@@ -30,8 +34,17 @@ macro void Atomic.store(&self, Type value, AtomicOrdering $ordering = SEQ_CONSIS
3034}
3135
3236<*
33- Atomically compare the value with `*expected` if equal, replace it with `desired`
37+ Atomically compare the value with `*expected`: if equal, replace it with `desired`
3438 and return true. Otherwise write the current value into `*expected` and return false.
39+
40+ @param [&inout] expected : "On entry the value to compare against; on a failed exchange it receives the current value."
41+ @param desired : "The value to store if the comparison succeeds."
42+ @param $success : "Memory ordering applied when the exchange succeeds, defaults to SEQ_CONSISTENT."
43+ @param $failure : "Memory ordering applied when the exchange fails, defaults to SEQ_CONSISTENT."
44+ @return "True if the value matched `*expected` and was replaced, false otherwise."
45+
46+ @require $success != NOT_ATOMIC && $success != UNORDERED : "Invalid success ordering."
47+ @require $failure != RELEASE && $failure != ACQUIRE_RELEASE : "Invalid failure ordering."
3548*>
3649macro bool Atomic .compare_exchange (& self , Type * expected , Type desired , AtomicOrdering $success = SEQ_CONSISTENT , AtomicOrdering $failure = SEQ_CONSISTENT )
3750{
@@ -41,66 +54,170 @@ macro bool Atomic.compare_exchange(&self, Type* expected, Type desired, AtomicOr
4154 return false ;
4255}
4356
57+ <*
58+ Atomically add `value` to the stored value.
59+
60+ @param value : "The value to add."
61+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
62+ @return "The previous value, before the addition."
63+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
64+ *>
4465macro Type Atomic .add (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT )
4566{
4667 return atomic ::fetch_add (& self .data , value , $ordering );
4768}
4869
70+ <*
71+ Atomically subtract `value` from the stored value.
72+
73+ @param value : "The value to subtract."
74+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
75+ @return "The previous value, before the subtraction."
76+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
77+ *>
4978macro Type Atomic .sub (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT )
5079{
5180 return atomic ::fetch_sub (& self .data , value , $ordering );
5281}
5382
83+ <*
84+ Atomically multiply the stored value by `value`, using a compare-exchange loop.
85+
86+ @param value : "The value to multiply by."
87+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
88+ @return "The previous value, before the multiplication."
89+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
90+ *>
5491macro Type Atomic .mul (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT )
5592{
5693 return atomic ::fetch_mul (& self .data , value , $ordering );
5794}
5895
96+ <*
97+ Atomically divide the stored value by `value`, using a compare-exchange loop.
98+
99+ @param value : "The value to divide by."
100+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
101+ @return "The previous value, before the division."
102+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
103+ *>
59104macro Type Atomic .div (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT )
60105{
61106 return atomic ::fetch_div (& self .data , value , $ordering );
62107}
63108
109+ <*
110+ Atomically replace the stored value with the maximum of it and `value`.
111+
112+ @param value : "The value to compare against."
113+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
114+ @return "The previous value, before the operation."
115+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
116+ *>
64117macro Type Atomic .max (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT )
65118{
66119 return atomic ::fetch_max (& self .data , value , $ordering );
67120}
68121
122+ <*
123+ Atomically replace the stored value with the minimum of it and `value`.
124+
125+ @param value : "The value to compare against."
126+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
127+ @return "The previous value, before the operation."
128+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
129+ *>
69130macro Type Atomic .min (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT )
70131{
71132 return atomic ::fetch_min (& self .data , value , $ordering );
72133}
73134
135+ <*
136+ Atomically bitwise-or the stored value with `value`. Not available for floats.
137+
138+ @param value : "The value to or with."
139+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
140+ @return "The previous value, before the operation."
141+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
142+ *>
74143macro Type Atomic .or (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT ) @if (types ::flat_kind (Type ) != FLOAT )
75144{
76145 return atomic ::fetch_or (& self .data , value , $ordering );
77146}
78147
148+ <*
149+ Atomically bitwise-xor the stored value with `value`. Not available for floats.
150+
151+ @param value : "The value to xor with."
152+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
153+ @return "The previous value, before the operation."
154+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
155+ *>
79156macro Type Atomic .xor (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT ) @if (types ::flat_kind (Type ) != FLOAT )
80157{
81158 return atomic ::fetch_xor (& self .data , value , $ordering );
82159}
83160
161+ <*
162+ Atomically bitwise-and the stored value with `value`. Not available for floats.
163+
164+ @param value : "The value to and with."
165+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
166+ @return "The previous value, before the operation."
167+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
168+ *>
84169macro Type Atomic .and (& self , Type value , AtomicOrdering $ordering = SEQ_CONSISTENT ) @if (types ::flat_kind (Type ) != FLOAT )
85170{
86171 return atomic ::fetch_and (& self .data , value , $ordering );
87172}
88173
174+ <*
175+ Atomically shift the stored value right by `amount`, using a compare-exchange loop.
176+ Not available for floats.
177+
178+ @param amount : "The number of bits to shift by."
179+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
180+ @return "The previous value, before the shift."
181+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
182+ *>
89183macro Type Atomic .shr (& self , Type amount , AtomicOrdering $ordering = SEQ_CONSISTENT ) @if (types ::flat_kind (Type ) != FLOAT )
90184{
91185 return atomic ::fetch_shift_right (& self .data , amount , $ordering );
92186}
93187
188+ <*
189+ Atomically shift the stored value left by `amount`, using a compare-exchange loop.
190+ Not available for floats.
191+
192+ @param amount : "The number of bits to shift by."
193+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
194+ @return "The previous value, before the shift."
195+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
196+ *>
94197macro Type Atomic .shl (& self , Type amount , AtomicOrdering $ordering = SEQ_CONSISTENT ) @if (types ::flat_kind (Type ) != FLOAT )
95198{
96199 return atomic ::fetch_shift_left (& self .data , amount , $ordering );
97200}
98201
202+ <*
203+ Atomically set the boolean flag to true. Only available for bool.
204+
205+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
206+ @return "The previous value of the flag."
207+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
208+ *>
99209macro Type Atomic .set (& self , AtomicOrdering $ordering = SEQ_CONSISTENT ) @if (types ::flat_kind (Type ) == BOOL )
100210{
101211 return atomic ::flag_set (& self .data , $ordering );
102212}
103213
214+ <*
215+ Atomically clear the boolean flag to false. Only available for bool.
216+
217+ @param $ordering : "Memory ordering, defaults to SEQ_CONSISTENT."
218+ @return "The previous value of the flag."
219+ @require $ordering != NOT_ATOMIC && $ordering != UNORDERED : "Invalid ordering for a read-modify-write."
220+ *>
104221macro Type Atomic .clear (& self , AtomicOrdering $ordering = SEQ_CONSISTENT ) @if (types ::flat_kind (Type ) == BOOL )
105222{
106223 return atomic ::flag_clear (& self .data , $ordering );
@@ -114,6 +231,12 @@ macro bool @is_native_atomic_value(#value) @private
114231 return is_native_atomic_type ($Typeof (#value));
115232}
116233
234+ <*
235+ Check whether a type can be operated on with native atomic instructions, that is,
236+ it is an int, pointer, function pointer, float or bool no larger than a pointer.
237+
238+ @return "True if `$Type` supports native atomic operations."
239+ *>
117240macro bool is_native_atomic_type ($Type )
118241{
119242 $if $Type ::size > void * ::size :
0 commit comments