use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
pub const CACHE_LINE_SIZE: usize = 64;
#[repr(align(64))] #[derive(Debug)]
pub struct AtomicCounter {
_pad0: [u8; 28],
value: AtomicU64,
_pad1: [u8; 28],
}
impl AtomicCounter {
#[must_use]
pub const fn new(initial: u64) -> Self {
Self {
_pad0: [0; 28],
value: AtomicU64::new(initial),
_pad1: [0; 28],
}
}
#[inline]
pub fn get(&self) -> u64 {
self.value.load(Ordering::Relaxed)
}
#[inline]
pub fn load(&self, ordering: Ordering) -> u64 {
self.value.load(ordering)
}
#[inline]
pub fn set(&self, value: u64) {
self.value.store(value, Ordering::Relaxed);
}
#[inline]
pub fn store(&self, value: u64, ordering: Ordering) {
self.value.store(value, ordering);
}
#[inline]
pub fn fetch_increment(&self) -> u64 {
self.value.fetch_add(1, Ordering::Relaxed)
}
#[inline]
pub fn increment(&self) {
self.fetch_increment();
}
#[inline]
pub fn fetch_add(&self, delta: u64) -> u64 {
self.value.fetch_add(delta, Ordering::Relaxed)
}
#[inline]
pub fn add(&self, delta: u64) {
self.fetch_add(delta);
}
#[inline]
pub fn fetch_sub(&self, delta: u64) -> u64 {
self.value.fetch_sub(delta, Ordering::Relaxed)
}
#[inline]
pub fn sub(&self, delta: u64) {
self.fetch_sub(delta);
}
#[inline]
pub fn compare_exchange(&self, current: u64, new: u64) -> Result<u64, u64> {
self.value
.compare_exchange(current, new, Ordering::Relaxed, Ordering::Relaxed)
}
#[inline]
pub fn reset(&self) {
self.set(0);
}
}
impl Default for AtomicCounter {
fn default() -> Self {
Self::new(0)
}
}
impl Clone for AtomicCounter {
fn clone(&self) -> Self {
Self::new(self.get())
}
}
#[derive(Debug)]
pub struct AtomicIndex {
value: AtomicUsize,
}
impl AtomicIndex {
#[must_use]
pub const fn new(initial: usize) -> Self {
Self {
value: AtomicUsize::new(initial),
}
}
#[inline]
pub fn get(&self) -> usize {
self.value.load(Ordering::Relaxed)
}
#[inline]
pub fn set(&self, value: usize) {
self.value.store(value, Ordering::Relaxed);
}
#[inline]
pub fn increment(&self) -> usize {
self.value.fetch_add(1, Ordering::Relaxed)
}
#[inline]
pub fn add(&self, delta: usize) -> usize {
self.value.fetch_add(delta, Ordering::Relaxed)
}
}
impl Default for AtomicIndex {
fn default() -> Self {
Self::new(0)
}
}
pub mod ordering {
use super::*;
pub const RELAXED: Ordering = Ordering::Relaxed;
pub const ACQUIRE: Ordering = Ordering::Acquire;
pub const RELEASE: Ordering = Ordering::Release;
pub const ACQ_REL: Ordering = Ordering::AcqRel;
pub const SEQ_CST: Ordering = Ordering::SeqCst;
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use std::thread;
#[test]
fn test_atomic_counter_new() {
let counter = AtomicCounter::new(42);
assert_eq!(counter.get(), 42);
}
#[test]
fn test_atomic_counter_default() {
let counter = AtomicCounter::default();
assert_eq!(counter.get(), 0);
}
#[test]
fn test_atomic_counter_set_get() {
let counter = AtomicCounter::new(0);
counter.set(100);
assert_eq!(counter.get(), 100);
}
#[test]
fn test_atomic_counter_increment() {
let counter = AtomicCounter::new(5);
counter.increment();
assert_eq!(counter.get(), 6);
counter.increment();
assert_eq!(counter.get(), 7);
}
#[test]
fn test_atomic_counter_fetch_increment() {
let counter = AtomicCounter::new(10);
let prev = counter.fetch_increment();
assert_eq!(prev, 10);
assert_eq!(counter.get(), 11);
}
#[test]
fn test_atomic_counter_add() {
let counter = AtomicCounter::new(10);
counter.add(5);
assert_eq!(counter.get(), 15);
}
#[test]
fn test_atomic_counter_fetch_add() {
let counter = AtomicCounter::new(10);
let prev = counter.fetch_add(7);
assert_eq!(prev, 10);
assert_eq!(counter.get(), 17);
}
#[test]
fn test_atomic_counter_sub() {
let counter = AtomicCounter::new(20);
counter.sub(5);
assert_eq!(counter.get(), 15);
}
#[test]
fn test_atomic_counter_fetch_sub() {
let counter = AtomicCounter::new(20);
let prev = counter.fetch_sub(8);
assert_eq!(prev, 20);
assert_eq!(counter.get(), 12);
}
#[test]
fn test_atomic_counter_compare_exchange_success() {
let counter = AtomicCounter::new(10);
let result = counter.compare_exchange(10, 20);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 10);
assert_eq!(counter.get(), 20);
}
#[test]
fn test_atomic_counter_compare_exchange_failure() {
let counter = AtomicCounter::new(10);
let result = counter.compare_exchange(5, 20);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), 10);
assert_eq!(counter.get(), 10);
}
#[test]
fn test_atomic_counter_reset() {
let counter = AtomicCounter::new(100);
counter.reset();
assert_eq!(counter.get(), 0);
}
#[test]
fn test_atomic_counter_clone() {
let counter1 = AtomicCounter::new(42);
let counter2 = counter1.clone();
assert_eq!(counter2.get(), 42);
counter1.increment();
assert_eq!(counter1.get(), 43);
assert_eq!(counter2.get(), 42); }
#[test]
fn test_atomic_counter_concurrent() {
let counter = Arc::new(AtomicCounter::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter_clone = Arc::clone(&counter);
let handle = thread::spawn(move || {
for _ in 0..1000 {
counter_clone.increment();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.get(), 10000);
}
#[test]
fn test_atomic_counter_memory_ordering() {
let counter = AtomicCounter::new(0);
counter.store(10, Ordering::Release);
let value = counter.load(Ordering::Acquire);
assert_eq!(value, 10);
}
#[test]
fn test_atomic_index_new() {
let index = AtomicIndex::new(5);
assert_eq!(index.get(), 5);
}
#[test]
fn test_atomic_index_default() {
let index = AtomicIndex::default();
assert_eq!(index.get(), 0);
}
#[test]
fn test_atomic_index_set_get() {
let index = AtomicIndex::new(0);
index.set(42);
assert_eq!(index.get(), 42);
}
#[test]
fn test_atomic_index_increment() {
let index = AtomicIndex::new(10);
let prev = index.increment();
assert_eq!(prev, 10);
assert_eq!(index.get(), 11);
}
#[test]
fn test_atomic_index_add() {
let index = AtomicIndex::new(10);
let prev = index.add(5);
assert_eq!(prev, 10);
assert_eq!(index.get(), 15);
}
#[test]
fn test_cache_line_size() {
assert_eq!(CACHE_LINE_SIZE, 64);
}
#[test]
fn test_atomic_counter_size() {
use std::mem;
assert_eq!(mem::size_of::<AtomicCounter>(), 64);
assert_eq!(mem::align_of::<AtomicCounter>(), 64);
}
#[test]
fn test_ordering_constants() {
use ordering::*;
assert!(matches!(RELAXED, Ordering::Relaxed));
assert!(matches!(ACQUIRE, Ordering::Acquire));
assert!(matches!(RELEASE, Ordering::Release));
assert!(matches!(ACQ_REL, Ordering::AcqRel));
assert!(matches!(SEQ_CST, Ordering::SeqCst));
}
}