prometheus/
atomic64.rs
1use std::cmp::*;
5use std::f64;
6use std::ops::*;
7use std::sync::atomic::{AtomicI64 as StdAtomicI64, AtomicU64 as StdAtomicU64, Ordering};
8
9pub trait Number:
12 Sized + AddAssign + SubAssign + PartialOrd + PartialEq + Copy + Send + Sync
13{
14 fn from_i64(v: i64) -> Self;
16 fn into_f64(self) -> f64;
18}
19
20impl Number for i64 {
21 #[inline]
22 fn from_i64(v: i64) -> Self {
23 v
24 }
25
26 #[inline]
27 fn into_f64(self) -> f64 {
28 self as f64
29 }
30}
31
32impl Number for u64 {
33 #[inline]
34 fn from_i64(v: i64) -> Self {
35 v as u64
36 }
37
38 #[inline]
39 fn into_f64(self) -> f64 {
40 self as f64
41 }
42}
43
44impl Number for f64 {
45 #[inline]
46 fn from_i64(v: i64) -> Self {
47 v as f64
48 }
49
50 #[inline]
51 fn into_f64(self) -> f64 {
52 self
53 }
54}
55
56pub trait Atomic: Send + Sync {
59 type T: Number;
61 fn new(val: Self::T) -> Self;
63 fn set(&self, val: Self::T);
65 fn get(&self) -> Self::T;
67 fn inc_by(&self, delta: Self::T);
69 fn dec_by(&self, delta: Self::T);
71}
72
73#[derive(Debug)]
75pub struct AtomicF64 {
76 inner: StdAtomicU64,
77}
78
79#[inline]
80fn u64_to_f64(val: u64) -> f64 {
81 f64::from_bits(val)
82}
83
84#[inline]
85fn f64_to_u64(val: f64) -> u64 {
86 f64::to_bits(val)
87}
88
89impl Atomic for AtomicF64 {
90 type T = f64;
91
92 fn new(val: Self::T) -> AtomicF64 {
93 AtomicF64 {
94 inner: StdAtomicU64::new(f64_to_u64(val)),
95 }
96 }
97
98 #[inline]
99 fn set(&self, val: Self::T) {
100 self.inner.store(f64_to_u64(val), Ordering::Relaxed);
101 }
102
103 #[inline]
104 fn get(&self) -> Self::T {
105 u64_to_f64(self.inner.load(Ordering::Relaxed))
106 }
107
108 #[inline]
109 fn inc_by(&self, delta: Self::T) {
110 loop {
111 let current = self.inner.load(Ordering::Acquire);
112 let new = u64_to_f64(current) + delta;
113 let result = self.inner.compare_exchange_weak(
114 current,
115 f64_to_u64(new),
116 Ordering::Release,
117 Ordering::Relaxed,
118 );
119 if result.is_ok() {
120 return;
121 }
122 }
123 }
124
125 #[inline]
126 fn dec_by(&self, delta: Self::T) {
127 self.inc_by(-delta);
128 }
129}
130
131impl AtomicF64 {
132 pub fn swap(&self, val: f64, ordering: Ordering) -> f64 {
134 u64_to_f64(self.inner.swap(f64_to_u64(val), ordering))
135 }
136}
137
138#[derive(Debug)]
140pub struct AtomicI64 {
141 inner: StdAtomicI64,
142}
143
144impl Atomic for AtomicI64 {
145 type T = i64;
146
147 fn new(val: Self::T) -> AtomicI64 {
148 AtomicI64 {
149 inner: StdAtomicI64::new(val),
150 }
151 }
152
153 #[inline]
154 fn set(&self, val: Self::T) {
155 self.inner.store(val, Ordering::Relaxed);
156 }
157
158 #[inline]
159 fn get(&self) -> Self::T {
160 self.inner.load(Ordering::Relaxed)
161 }
162
163 #[inline]
164 fn inc_by(&self, delta: Self::T) {
165 self.inner.fetch_add(delta, Ordering::Relaxed);
166 }
167
168 #[inline]
169 fn dec_by(&self, delta: Self::T) {
170 self.inner.fetch_sub(delta, Ordering::Relaxed);
171 }
172}
173
174#[derive(Debug)]
176pub struct AtomicU64 {
177 inner: StdAtomicU64,
178}
179
180impl Atomic for AtomicU64 {
181 type T = u64;
182
183 fn new(val: Self::T) -> AtomicU64 {
184 AtomicU64 {
185 inner: StdAtomicU64::new(val),
186 }
187 }
188
189 #[inline]
190 fn set(&self, val: Self::T) {
191 self.inner.store(val, Ordering::Relaxed);
192 }
193
194 #[inline]
195 fn get(&self) -> Self::T {
196 self.inner.load(Ordering::Relaxed)
197 }
198
199 #[inline]
200 fn inc_by(&self, delta: Self::T) {
201 self.inc_by_with_ordering(delta, Ordering::Relaxed);
202 }
203
204 #[inline]
205 fn dec_by(&self, delta: Self::T) {
206 self.inner.fetch_sub(delta, Ordering::Relaxed);
207 }
208}
209
210impl AtomicU64 {
211 pub(crate) fn compare_exchange_weak(
221 &self,
222 current: u64,
223 new: u64,
224 success: Ordering,
225 failure: Ordering,
226 ) -> Result<u64, u64> {
227 self.inner
228 .compare_exchange_weak(current, new, success, failure)
229 }
230
231 pub fn inc_by_with_ordering(&self, delta: u64, ordering: Ordering) {
233 self.inner.fetch_add(delta, ordering);
234 }
235
236 pub fn swap(&self, val: u64, ordering: Ordering) -> u64 {
238 self.inner.swap(val, ordering)
239 }
240}
241
242#[cfg(test)]
243mod test {
244 use std::f64::consts::PI;
245 use std::f64::{self, EPSILON};
246
247 use super::*;
248
249 #[test]
250 fn test_atomic_f64() {
251 let table: Vec<f64> = vec![0.0, 1.0, PI, f64::MIN, f64::MAX];
252
253 for f in table {
254 assert!((f - AtomicF64::new(f).get()).abs() < EPSILON);
255 }
256 }
257
258 #[test]
259 fn test_atomic_i64() {
260 let ai64 = AtomicI64::new(0);
261 assert_eq!(ai64.get(), 0);
262
263 ai64.inc_by(1);
264 assert_eq!(ai64.get(), 1);
265
266 ai64.inc_by(-5);
267 assert_eq!(ai64.get(), -4);
268 }
269
270 #[test]
271 fn test_atomic_u64() {
272 let au64 = AtomicU64::new(0);
273 assert_eq!(au64.get(), 0);
274
275 au64.inc_by(123);
276 assert_eq!(au64.get(), 123);
277 }
278}