use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
pub struct AtomicCounter {
value: AtomicUsize,
}
impl AtomicCounter {
pub const fn new() -> Self {
Self {
value: AtomicUsize::new(0),
}
}
pub const fn with_initial(initial: usize) -> Self {
Self {
value: AtomicUsize::new(initial),
}
}
pub fn get(&self) -> usize {
self.value.load(Ordering::Relaxed)
}
pub fn set(&self, value: usize) {
self.value.store(value, Ordering::Relaxed);
}
pub fn increment(&self) -> usize {
self.value.fetch_add(1, Ordering::Relaxed)
}
pub fn add(&self, amount: usize) -> usize {
self.value.fetch_add(amount, Ordering::Relaxed)
}
pub fn fetch_add(&self, amount: usize, ordering: Ordering) -> usize {
self.value.fetch_add(amount, ordering)
}
pub fn decrement(&self) -> usize {
self.value.fetch_sub(1, Ordering::Relaxed)
}
pub fn subtract(&self, amount: usize) -> usize {
self.value.fetch_sub(amount, Ordering::Relaxed)
}
pub fn max(&self, value: usize) -> usize {
self.value.fetch_max(value, Ordering::Relaxed)
}
pub fn min(&self, value: usize) -> usize {
self.value.fetch_min(value, Ordering::Relaxed)
}
pub fn reset(&self) -> usize {
self.value.swap(0, Ordering::Relaxed)
}
pub fn compare_and_swap(&self, current: usize, new: usize) -> (usize, bool) {
match self
.value
.compare_exchange_weak(current, new, Ordering::Relaxed, Ordering::Relaxed)
{
Ok(prev) => (prev, true),
Err(prev) => (prev, false),
}
}
}
impl Default for AtomicCounter {
fn default() -> Self {
Self::new()
}
}
impl Clone for AtomicCounter {
fn clone(&self) -> Self {
Self::with_initial(self.get())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_atomic_counter_basic() {
let counter = AtomicCounter::new();
assert_eq!(counter.get(), 0);
counter.increment();
assert_eq!(counter.get(), 1);
counter.decrement();
assert_eq!(counter.get(), 0);
}
#[test]
fn test_atomic_counter_add_subtract() {
let counter = AtomicCounter::new();
counter.add(10);
assert_eq!(counter.get(), 10);
counter.subtract(5);
assert_eq!(counter.get(), 5);
}
#[test]
fn test_atomic_counter_max_min() {
let counter = AtomicCounter::with_initial(5);
counter.max(3); assert_eq!(counter.get(), 5);
counter.max(10); assert_eq!(counter.get(), 10);
counter.min(15); assert_eq!(counter.get(), 10);
counter.min(7); assert_eq!(counter.get(), 7);
}
#[test]
fn test_atomic_counter_reset() {
let counter = AtomicCounter::with_initial(42);
let prev = counter.reset();
assert_eq!(prev, 42);
assert_eq!(counter.get(), 0);
}
}