1use std::sync::atomic::{AtomicU64, Ordering};
14use std::time::{Duration, Instant};
15
16#[repr(align(64))]
21pub struct Counter {
22 value: AtomicU64,
24 created_at: Instant,
26}
27
28#[derive(Debug, Clone)]
30pub struct CounterStats {
31 pub value: u64,
33 pub age: Duration,
35 pub rate_per_second: f64,
37 pub total: u64,
39}
40
41impl Counter {
42 #[inline]
44 pub fn new() -> Self {
45 Self {
46 value: AtomicU64::new(0),
47 created_at: Instant::now(),
48 }
49 }
50
51 #[inline]
53 pub fn with_value(initial: u64) -> Self {
54 Self {
55 value: AtomicU64::new(initial),
56 created_at: Instant::now(),
57 }
58 }
59
60 #[inline(always)]
67 pub fn inc(&self) {
68 self.value.fetch_add(1, Ordering::Relaxed);
69 }
70
71 #[inline(always)]
76 pub fn add(&self, amount: u64) {
77 self.value.fetch_add(amount, Ordering::Relaxed);
78 }
79
80 #[inline(always)]
82 pub fn get(&self) -> u64 {
83 self.value.load(Ordering::Relaxed)
84 }
85
86 #[inline]
90 pub fn reset(&self) {
91 self.value.store(0, Ordering::SeqCst);
92 }
93
94 #[inline]
98 pub fn set(&self, value: u64) {
99 self.value.store(value, Ordering::SeqCst);
100 }
101
102 #[inline]
106 pub fn compare_and_swap(&self, expected: u64, new: u64) -> Result<u64, u64> {
107 match self.value.compare_exchange(
108 expected,
109 new,
110 Ordering::SeqCst,
111 Ordering::SeqCst,
112 ) {
113 Ok(prev) => Ok(prev),
114 Err(current) => Err(current),
115 }
116 }
117
118 #[inline]
120 pub fn fetch_add(&self, amount: u64) -> u64 {
121 self.value.fetch_add(amount, Ordering::Relaxed)
122 }
123
124 #[inline]
126 pub fn add_and_get(&self, amount: u64) -> u64 {
127 self.value.fetch_add(amount, Ordering::Relaxed) + amount
128 }
129
130 #[inline]
132 pub fn inc_and_get(&self) -> u64 {
133 self.value.fetch_add(1, Ordering::Relaxed) + 1
134 }
135
136 pub fn stats(&self) -> CounterStats {
138 let value = self.get();
139 let age = self.created_at.elapsed();
140 let age_seconds = age.as_secs_f64();
141
142 let rate_per_second = if age_seconds > 0.0 {
143 value as f64 / age_seconds
144 } else {
145 0.0
146 };
147
148 CounterStats {
149 value,
150 age,
151 rate_per_second,
152 total: value,
153 }
154 }
155
156 #[inline]
158 pub fn age(&self) -> Duration {
159 self.created_at.elapsed()
160 }
161
162 #[inline]
164 pub fn is_zero(&self) -> bool {
165 self.get() == 0
166 }
167
168 #[inline]
170 pub fn rate_per_second(&self) -> f64 {
171 let age_seconds = self.age().as_secs_f64();
172 if age_seconds > 0.0 {
173 self.get() as f64 / age_seconds
174 } else {
175 0.0
176 }
177 }
178
179 #[inline]
181 pub fn saturating_add(&self, amount: u64) {
182 loop {
183 let current = self.get();
184 let new_value = current.saturating_add(amount);
185
186 if new_value == current {
188 break;
189 }
190
191 match self.compare_and_swap(current, new_value) {
193 Ok(_) => break,
194 Err(_) => continue, }
196 }
197 }
198}
199
200impl Default for Counter {
201 #[inline]
202 fn default() -> Self {
203 Self::new()
204 }
205}
206
207impl std::fmt::Display for Counter {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 write!(f, "Counter({})", self.get())
210 }
211}
212
213impl std::fmt::Debug for Counter {
214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215 f.debug_struct("Counter")
216 .field("value", &self.get())
217 .field("age", &self.age())
218 .field("rate_per_second", &self.rate_per_second())
219 .finish()
220 }
221}
222
223unsafe impl Send for Counter {}
225unsafe impl Sync for Counter {}
226
227impl Counter {
229 #[inline]
233 pub fn batch_inc(&self, count: usize) {
234 if count > 0 {
235 self.add(count as u64);
236 }
237 }
238
239 #[inline]
241 pub fn inc_if(&self, condition: bool) {
242 if condition {
243 self.inc();
244 }
245 }
246
247 #[inline]
249 pub fn inc_max(&self, max_value: u64) -> bool {
250 loop {
251 let current = self.get();
252 if current >= max_value {
253 return false;
254 }
255
256 match self.compare_and_swap(current, current + 1) {
257 Ok(_) => return true,
258 Err(_) => continue, }
260 }
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267 use std::sync::Arc;
268 use std::thread;
269
270 #[test]
271 fn test_basic_operations() {
272 let counter = Counter::new();
273
274 assert_eq!(counter.get(), 0);
275 assert!(counter.is_zero());
276
277 counter.inc();
278 assert_eq!(counter.get(), 1);
279 assert!(!counter.is_zero());
280
281 counter.add(5);
282 assert_eq!(counter.get(), 6);
283
284 counter.reset();
285 assert_eq!(counter.get(), 0);
286
287 counter.set(42);
288 assert_eq!(counter.get(), 42);
289 }
290
291 #[test]
292 fn test_fetch_operations() {
293 let counter = Counter::new();
294
295 assert_eq!(counter.fetch_add(10), 0);
296 assert_eq!(counter.get(), 10);
297
298 assert_eq!(counter.inc_and_get(), 11);
299 assert_eq!(counter.add_and_get(5), 16);
300 }
301
302 #[test]
303 fn test_compare_and_swap() {
304 let counter = Counter::new();
305 counter.set(10);
306
307 assert_eq!(counter.compare_and_swap(10, 20), Ok(10));
309 assert_eq!(counter.get(), 20);
310
311 assert_eq!(counter.compare_and_swap(10, 30), Err(20));
313 assert_eq!(counter.get(), 20);
314 }
315
316 #[test]
317 fn test_saturating_add() {
318 let counter = Counter::new();
319 counter.set(u64::MAX - 5);
320
321 counter.saturating_add(10);
322 assert_eq!(counter.get(), u64::MAX);
323
324 counter.saturating_add(100);
326 assert_eq!(counter.get(), u64::MAX);
327 }
328
329 #[test]
330 fn test_conditional_operations() {
331 let counter = Counter::new();
332
333 counter.inc_if(true);
334 assert_eq!(counter.get(), 1);
335
336 counter.inc_if(false);
337 assert_eq!(counter.get(), 1);
338
339 assert!(counter.inc_max(5));
341 assert_eq!(counter.get(), 2);
342
343 counter.set(5);
344 assert!(!counter.inc_max(5));
345 assert_eq!(counter.get(), 5);
346 }
347
348 #[test]
349 fn test_statistics() {
350 let counter = Counter::new();
351 counter.add(100);
352
353 let stats = counter.stats();
354 assert_eq!(stats.value, 100);
355 assert_eq!(stats.total, 100);
356 assert!(stats.age > Duration::from_nanos(0));
357 assert!(stats.rate_per_second >= 0.0);
359 }
360
361 #[test]
362 fn test_high_concurrency() {
363 let counter = Arc::new(Counter::new());
364 let num_threads = 100;
365 let increments_per_thread = 1000;
366
367 let handles: Vec<_> = (0..num_threads)
368 .map(|_| {
369 let counter = Arc::clone(&counter);
370 thread::spawn(move || {
371 for _ in 0..increments_per_thread {
372 counter.inc();
373 }
374 })
375 })
376 .collect();
377
378 for handle in handles {
379 handle.join().unwrap();
380 }
381
382 assert_eq!(counter.get(), num_threads * increments_per_thread);
383
384 let stats = counter.stats();
385 assert!(stats.rate_per_second > 0.0);
386 }
387
388 #[test]
389 fn test_batch_operations() {
390 let counter = Counter::new();
391
392 counter.batch_inc(1000);
393 assert_eq!(counter.get(), 1000);
394
395 counter.batch_inc(0); assert_eq!(counter.get(), 1000);
397 }
398
399 #[test]
400 fn test_display_and_debug() {
401 let counter = Counter::new();
402 counter.set(42);
403
404 let display_str = format!("{}", counter);
405 assert!(display_str.contains("42"));
406
407 let debug_str = format!("{:?}", counter);
408 assert!(debug_str.contains("Counter"));
409 assert!(debug_str.contains("42"));
410 }
411}
412
413#[cfg(test)]
414mod benchmarks {
415 use super::*;
416 use std::time::Instant;
417
418 #[test]
419 fn bench_counter_increment() {
420 let counter = Counter::new();
421 let iterations = 10_000_000;
422
423 let start = Instant::now();
424 for _ in 0..iterations {
425 counter.inc();
426 }
427 let elapsed = start.elapsed();
428
429 println!("Counter increment: {:.2} ns/op",
430 elapsed.as_nanos() as f64 / iterations as f64);
431
432 assert!(elapsed.as_nanos() / iterations < 100);
434 assert_eq!(counter.get(), iterations as u64);
435 }
436
437 #[test]
438 fn bench_counter_add() {
439 let counter = Counter::new();
440 let iterations = 1_000_000;
441
442 let start = Instant::now();
443 for i in 0..iterations {
444 counter.add(i + 1);
445 }
446 let elapsed = start.elapsed();
447
448 println!("Counter add: {:.2} ns/op",
449 elapsed.as_nanos() as f64 / iterations as f64);
450
451 assert!(elapsed.as_nanos() / (iterations as u128) < 200);
453 }
454
455 #[test]
456 fn bench_counter_get() {
457 let counter = Counter::new();
458 counter.set(42);
459 let iterations = 100_000_000;
460
461 let start = Instant::now();
462 let mut sum = 0;
463 for _ in 0..iterations {
464 sum += counter.get();
465 }
466 let elapsed = start.elapsed();
467
468 println!("Counter get: {:.2} ns/op",
469 elapsed.as_nanos() as f64 / iterations as f64);
470
471 assert_eq!(sum, 42 * iterations);
473
474 assert!(elapsed.as_nanos() / (iterations as u128) < 50);
476 }
477}