1use std::collections::HashMap;
30use std::hash::{BuildHasher, Hash, Hasher};
31use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
32use std::sync::{Arc, Condvar, Mutex, MutexGuard};
33use std::time::Duration;
34
35use crate::error::{CoreError, CoreResult, ErrorContext};
36
37const DEFAULT_SHARD_COUNT: usize = 64;
43
44pub struct ConcurrentHashMap<K, V, S = std::hash::RandomState> {
50 shards: Vec<Mutex<HashMap<K, V, S>>>,
51 shard_count: usize,
52 hash_builder: S,
53 len: AtomicUsize,
54}
55
56impl<K, V> ConcurrentHashMap<K, V, std::hash::RandomState>
57where
58 K: Eq + Hash + Clone,
59 V: Clone,
60{
61 pub fn new() -> Self {
63 Self::with_shard_count(DEFAULT_SHARD_COUNT)
64 }
65
66 pub fn with_shard_count(n: usize) -> Self {
68 let shard_count = n.max(1);
69 let hash_builder = std::hash::RandomState::new();
70 let shards = (0..shard_count)
71 .map(|_| Mutex::new(HashMap::with_hasher(hash_builder.clone())))
72 .collect();
73 Self {
74 shards,
75 shard_count,
76 hash_builder,
77 len: AtomicUsize::new(0),
78 }
79 }
80}
81
82impl<K, V, S> ConcurrentHashMap<K, V, S>
83where
84 K: Eq + Hash + Clone,
85 V: Clone,
86 S: BuildHasher + Clone,
87{
88 fn shard_index(&self, key: &K) -> usize {
89 (self.hash_builder.hash_one(&key) as usize) % self.shard_count
90 }
91
92 fn lock_shard(&self, idx: usize) -> CoreResult<MutexGuard<'_, HashMap<K, V, S>>> {
93 self.shards[idx].lock().map_err(|e| {
94 CoreError::ComputationError(ErrorContext::new(format!(
95 "concurrent hash map shard {idx} mutex poisoned: {e}"
96 )))
97 })
98 }
99
100 pub fn insert(&self, key: K, value: V) -> Option<V> {
102 let idx = self.shard_index(&key);
103 let mut shard = match self.lock_shard(idx) {
104 Ok(s) => s,
105 Err(_) => return None,
106 };
107 let prev = shard.insert(key, value);
108 if prev.is_none() {
109 self.len.fetch_add(1, Ordering::Release);
110 }
111 prev
112 }
113
114 pub fn get(&self, key: &K) -> Option<V> {
116 let idx = self.shard_index(key);
117 let shard = match self.lock_shard(idx) {
118 Ok(s) => s,
119 Err(_) => return None,
120 };
121 shard.get(key).cloned()
122 }
123
124 pub fn remove(&self, key: &K) -> Option<V> {
126 let idx = self.shard_index(key);
127 let mut shard = match self.lock_shard(idx) {
128 Ok(s) => s,
129 Err(_) => return None,
130 };
131 let removed = shard.remove(key);
132 if removed.is_some() {
133 self.len.fetch_sub(1, Ordering::Release);
134 }
135 removed
136 }
137
138 pub fn contains_key(&self, key: &K) -> bool {
140 let idx = self.shard_index(key);
141 match self.lock_shard(idx) {
142 Ok(shard) => shard.contains_key(key),
143 Err(_) => false,
144 }
145 }
146
147 pub fn len(&self) -> usize {
149 self.len.load(Ordering::Acquire)
150 }
151
152 pub fn is_empty(&self) -> bool {
154 self.len() == 0
155 }
156
157 pub fn get_and_modify<F, R>(&self, key: &K, f: F) -> Option<R>
161 where
162 F: FnOnce(&mut V) -> R,
163 {
164 let idx = self.shard_index(key);
165 let mut shard = match self.lock_shard(idx) {
166 Ok(s) => s,
167 Err(_) => return None,
168 };
169 shard.get_mut(key).map(f)
170 }
171
172 pub fn get_or_insert_with<F>(&self, key: K, f: F) -> V
176 where
177 F: FnOnce() -> V,
178 {
179 let idx = self.shard_index(&key);
180 let mut shard = match self.lock_shard(idx) {
181 Ok(s) => s,
182 Err(_) => return f(),
183 };
184 if let Some(existing) = shard.get(&key) {
185 return existing.clone();
186 }
187 let value = f();
188 let cloned = value.clone();
189 shard.insert(key, value);
190 self.len.fetch_add(1, Ordering::Release);
191 cloned
192 }
193
194 pub fn keys(&self) -> Vec<K> {
196 let mut result = Vec::new();
197 for shard_mutex in &self.shards {
198 if let Ok(shard) = shard_mutex.lock() {
199 result.extend(shard.keys().cloned());
200 }
201 }
202 result
203 }
204
205 pub fn clear(&self) {
207 for shard_mutex in &self.shards {
208 if let Ok(mut shard) = shard_mutex.lock() {
209 shard.clear();
210 }
211 }
212 self.len.store(0, Ordering::Release);
213 }
214}
215
216unsafe impl<K: Send, V: Send, S: Send> Send for ConcurrentHashMap<K, V, S> {}
218unsafe impl<K: Send + Sync, V: Send + Sync, S: Send + Sync> Sync for ConcurrentHashMap<K, V, S> {}
219
220impl<K, V> Default for ConcurrentHashMap<K, V, std::hash::RandomState>
221where
222 K: Eq + Hash + Clone,
223 V: Clone,
224{
225 fn default() -> Self {
226 Self::new()
227 }
228}
229
230pub struct BoundedQueue<T> {
240 buffer: Mutex<std::collections::VecDeque<T>>,
241 capacity: usize,
242 not_empty: Condvar,
243 not_full: Condvar,
244 len: AtomicUsize,
245 closed: AtomicBool,
246}
247
248impl<T> BoundedQueue<T> {
249 pub fn new(capacity: usize) -> Self {
251 let cap = capacity.max(1);
252 Self {
253 buffer: Mutex::new(std::collections::VecDeque::with_capacity(cap)),
254 capacity: cap,
255 not_empty: Condvar::new(),
256 not_full: Condvar::new(),
257 len: AtomicUsize::new(0),
258 closed: AtomicBool::new(false),
259 }
260 }
261
262 pub fn push(&self, item: T) -> Result<(), T> {
264 if self.closed.load(Ordering::Acquire) {
265 return Err(item);
266 }
267 let mut buf = match self.buffer.lock() {
268 Ok(b) => b,
269 Err(_) => return Err(item),
270 };
271 if buf.len() >= self.capacity {
272 return Err(item);
273 }
274 buf.push_back(item);
275 self.len.fetch_add(1, Ordering::Release);
276 self.not_empty.notify_one();
277 Ok(())
278 }
279
280 pub fn push_blocking(&self, item: T) -> CoreResult<()> {
282 self.push_blocking_timeout(item, None)
283 }
284
285 pub fn push_blocking_timeout(&self, mut item: T, timeout: Option<Duration>) -> CoreResult<()> {
287 let deadline = timeout.map(|d| std::time::Instant::now() + d);
288
289 loop {
290 if self.closed.load(Ordering::Acquire) {
291 return Err(CoreError::ComputationError(ErrorContext::new(
292 "queue is closed".to_string(),
293 )));
294 }
295
296 let mut buf = self.buffer.lock().map_err(|e| {
297 CoreError::ComputationError(ErrorContext::new(format!("queue mutex poisoned: {e}")))
298 })?;
299
300 if buf.len() < self.capacity {
301 buf.push_back(item);
302 self.len.fetch_add(1, Ordering::Release);
303 self.not_empty.notify_one();
304 return Ok(());
305 }
306
307 if let Some(dl) = deadline {
309 let remaining = dl.saturating_duration_since(std::time::Instant::now());
310 if remaining.is_zero() {
311 return Err(CoreError::ComputationError(ErrorContext::new(
312 "push timed out".to_string(),
313 )));
314 }
315 let (b, timeout_result) =
316 self.not_full.wait_timeout(buf, remaining).map_err(|e| {
317 CoreError::ComputationError(ErrorContext::new(format!(
318 "condvar wait failed: {e}"
319 )))
320 })?;
321 drop(b);
322 if timeout_result.timed_out() {
323 return Err(CoreError::ComputationError(ErrorContext::new(
324 "push timed out".to_string(),
325 )));
326 }
327 } else {
328 let _b = self.not_full.wait(buf).map_err(|e| {
329 CoreError::ComputationError(ErrorContext::new(format!(
330 "condvar wait failed: {e}"
331 )))
332 })?;
333 }
334 }
335 }
336
337 pub fn pop(&self) -> Option<T> {
339 let mut buf = match self.buffer.lock() {
340 Ok(b) => b,
341 Err(_) => return None,
342 };
343 let item = buf.pop_front();
344 if item.is_some() {
345 self.len.fetch_sub(1, Ordering::Release);
346 self.not_full.notify_one();
347 }
348 item
349 }
350
351 pub fn pop_blocking(&self) -> CoreResult<Option<T>> {
353 self.pop_blocking_timeout(None)
354 }
355
356 pub fn pop_blocking_timeout(&self, timeout: Option<Duration>) -> CoreResult<Option<T>> {
358 let deadline = timeout.map(|d| std::time::Instant::now() + d);
359
360 loop {
361 let mut buf = self.buffer.lock().map_err(|e| {
362 CoreError::ComputationError(ErrorContext::new(format!("queue mutex poisoned: {e}")))
363 })?;
364
365 if let Some(item) = buf.pop_front() {
366 self.len.fetch_sub(1, Ordering::Release);
367 self.not_full.notify_one();
368 return Ok(Some(item));
369 }
370
371 if self.closed.load(Ordering::Acquire) {
372 return Ok(None);
373 }
374
375 if let Some(dl) = deadline {
376 let remaining = dl.saturating_duration_since(std::time::Instant::now());
377 if remaining.is_zero() {
378 return Ok(None); }
380 let (b, timeout_result) =
381 self.not_empty.wait_timeout(buf, remaining).map_err(|e| {
382 CoreError::ComputationError(ErrorContext::new(format!(
383 "condvar wait failed: {e}"
384 )))
385 })?;
386 drop(b);
387 if timeout_result.timed_out() {
388 return Ok(None);
389 }
390 } else {
391 let _b = self.not_empty.wait(buf).map_err(|e| {
392 CoreError::ComputationError(ErrorContext::new(format!(
393 "condvar wait failed: {e}"
394 )))
395 })?;
396 }
397 }
398 }
399
400 pub fn len(&self) -> usize {
402 self.len.load(Ordering::Acquire)
403 }
404
405 pub fn is_empty(&self) -> bool {
407 self.len() == 0
408 }
409
410 pub fn capacity(&self) -> usize {
412 self.capacity
413 }
414
415 pub fn close(&self) {
419 self.closed.store(true, Ordering::Release);
420 self.not_empty.notify_all();
421 self.not_full.notify_all();
422 }
423
424 pub fn is_closed(&self) -> bool {
426 self.closed.load(Ordering::Acquire)
427 }
428}
429
430unsafe impl<T: Send> Send for BoundedQueue<T> {}
431unsafe impl<T: Send> Sync for BoundedQueue<T> {}
432
433pub struct ConcurrentAccumulator<T: Clone> {
442 shards: Vec<Mutex<T>>,
444 shard_count: usize,
445 combiner: Arc<dyn Fn(T, T) -> T + Send + Sync>,
447 identity: T,
449 counter: AtomicUsize,
451}
452
453impl<T: Clone + Send + Sync + 'static> ConcurrentAccumulator<T> {
454 pub fn new<F>(identity: T, combiner: F, shard_count: usize) -> Self
458 where
459 F: Fn(T, T) -> T + Send + Sync + 'static,
460 {
461 let sc = shard_count.max(1);
462 let shards = (0..sc).map(|_| Mutex::new(identity.clone())).collect();
463 Self {
464 shards,
465 shard_count: sc,
466 combiner: Arc::new(combiner),
467 identity,
468 counter: AtomicUsize::new(0),
469 }
470 }
471
472 pub fn accumulate(&self, value: T) {
474 let idx = self.counter.fetch_add(1, Ordering::Relaxed) % self.shard_count;
475 if let Ok(mut shard) = self.shards[idx].lock() {
476 let old = shard.clone();
477 *shard = (self.combiner)(old, value);
478 }
479 }
480
481 pub fn result(&self) -> T {
483 let mut acc = self.identity.clone();
484 for shard_mutex in &self.shards {
485 if let Ok(shard) = shard_mutex.lock() {
486 acc = (self.combiner)(acc, shard.clone());
487 }
488 }
489 acc
490 }
491
492 pub fn reset(&self) {
494 for shard_mutex in &self.shards {
495 if let Ok(mut shard) = shard_mutex.lock() {
496 *shard = self.identity.clone();
497 }
498 }
499 self.counter.store(0, Ordering::Relaxed);
500 }
501}
502
503unsafe impl<T: Clone + Send> Send for ConcurrentAccumulator<T> {}
504unsafe impl<T: Clone + Send + Sync> Sync for ConcurrentAccumulator<T> {}
505
506pub struct AtomicF64Accumulator {
514 bits: AtomicU64,
515 count: AtomicU64,
516}
517
518impl AtomicF64Accumulator {
519 pub fn new() -> Self {
521 Self {
522 bits: AtomicU64::new(0.0_f64.to_bits()),
523 count: AtomicU64::new(0),
524 }
525 }
526
527 pub fn add(&self, value: f64) {
529 loop {
530 let current_bits = self.bits.load(Ordering::Acquire);
531 let current = f64::from_bits(current_bits);
532 let new = current + value;
533 let new_bits = new.to_bits();
534 if self
535 .bits
536 .compare_exchange_weak(current_bits, new_bits, Ordering::AcqRel, Ordering::Acquire)
537 .is_ok()
538 {
539 self.count.fetch_add(1, Ordering::Relaxed);
540 return;
541 }
542 }
543 }
544
545 pub fn value(&self) -> f64 {
547 f64::from_bits(self.bits.load(Ordering::Acquire))
548 }
549
550 pub fn count(&self) -> u64 {
552 self.count.load(Ordering::Acquire)
553 }
554
555 pub fn reset(&self) {
557 self.bits.store(0.0_f64.to_bits(), Ordering::Release);
558 self.count.store(0, Ordering::Release);
559 }
560}
561
562impl Default for AtomicF64Accumulator {
563 fn default() -> Self {
564 Self::new()
565 }
566}
567
568pub struct WriterPreferenceRwLock<T> {
577 data: std::sync::RwLock<T>,
578 writers_waiting: AtomicUsize,
580 reader_gate: Mutex<()>,
582 reader_gate_cv: Condvar,
583}
584
585impl<T> WriterPreferenceRwLock<T> {
586 pub fn new(data: T) -> Self {
588 Self {
589 data: std::sync::RwLock::new(data),
590 writers_waiting: AtomicUsize::new(0),
591 reader_gate: Mutex::new(()),
592 reader_gate_cv: Condvar::new(),
593 }
594 }
595
596 pub fn read(&self) -> CoreResult<ReadGuard<'_, T>> {
600 {
602 let mut gate = self.reader_gate.lock().map_err(|e| {
603 CoreError::ComputationError(ErrorContext::new(format!("gate mutex poisoned: {e}")))
604 })?;
605 while self.writers_waiting.load(Ordering::Acquire) > 0 {
606 gate = self.reader_gate_cv.wait(gate).map_err(|e| {
607 CoreError::ComputationError(ErrorContext::new(format!(
608 "condvar wait failed: {e}"
609 )))
610 })?;
611 }
612 }
613 let guard = self.data.read().map_err(|e| {
614 CoreError::ComputationError(ErrorContext::new(format!("rwlock poisoned: {e}")))
615 })?;
616 Ok(ReadGuard { guard })
617 }
618
619 pub fn write(&self) -> CoreResult<WriteGuard<'_, T>> {
624 self.writers_waiting.fetch_add(1, Ordering::Release);
625 let guard = self.data.write().map_err(|e| {
626 self.writers_waiting.fetch_sub(1, Ordering::Release);
627 CoreError::ComputationError(ErrorContext::new(format!("rwlock poisoned: {e}")))
628 })?;
629 self.writers_waiting.fetch_sub(1, Ordering::Release);
630 self.reader_gate_cv.notify_all();
632 Ok(WriteGuard { guard })
633 }
634
635 pub fn try_read(&self) -> CoreResult<Option<ReadGuard<'_, T>>> {
637 if self.writers_waiting.load(Ordering::Acquire) > 0 {
638 return Ok(None);
639 }
640 match self.data.try_read() {
641 Ok(guard) => Ok(Some(ReadGuard { guard })),
642 Err(std::sync::TryLockError::WouldBlock) => Ok(None),
643 Err(std::sync::TryLockError::Poisoned(e)) => Err(CoreError::ComputationError(
644 ErrorContext::new(format!("rwlock poisoned: {e}")),
645 )),
646 }
647 }
648
649 pub fn try_write(&self) -> CoreResult<Option<WriteGuard<'_, T>>> {
651 match self.data.try_write() {
652 Ok(guard) => Ok(Some(WriteGuard { guard })),
653 Err(std::sync::TryLockError::WouldBlock) => Ok(None),
654 Err(std::sync::TryLockError::Poisoned(e)) => Err(CoreError::ComputationError(
655 ErrorContext::new(format!("rwlock poisoned: {e}")),
656 )),
657 }
658 }
659}
660
661unsafe impl<T: Send> Send for WriterPreferenceRwLock<T> {}
662unsafe impl<T: Send + Sync> Sync for WriterPreferenceRwLock<T> {}
663
664pub struct ReadGuard<'a, T> {
666 guard: std::sync::RwLockReadGuard<'a, T>,
667}
668
669impl<T> std::ops::Deref for ReadGuard<'_, T> {
670 type Target = T;
671 fn deref(&self) -> &T {
672 &self.guard
673 }
674}
675
676pub struct WriteGuard<'a, T> {
678 guard: std::sync::RwLockWriteGuard<'a, T>,
679}
680
681impl<T> std::ops::Deref for WriteGuard<'_, T> {
682 type Target = T;
683 fn deref(&self) -> &T {
684 &self.guard
685 }
686}
687
688impl<T> std::ops::DerefMut for WriteGuard<'_, T> {
689 fn deref_mut(&mut self) -> &mut T {
690 &mut self.guard
691 }
692}
693
694pub struct DoubleBuffer<T> {
704 buffers: [Mutex<T>; 2],
705 front_index: AtomicUsize,
707 new_frame: Condvar,
709 new_frame_mutex: Mutex<bool>,
710}
711
712impl<T: Clone> DoubleBuffer<T> {
713 pub fn new(initial: T) -> Self {
715 Self {
716 buffers: [Mutex::new(initial.clone()), Mutex::new(initial)],
717 front_index: AtomicUsize::new(0),
718 new_frame: Condvar::new(),
719 new_frame_mutex: Mutex::new(false),
720 }
721 }
722
723 pub fn read_front(&self) -> CoreResult<T> {
725 let idx = self.front_index.load(Ordering::Acquire);
726 let guard = self.buffers[idx].lock().map_err(|e| {
727 CoreError::ComputationError(ErrorContext::new(format!("buffer mutex poisoned: {e}")))
728 })?;
729 Ok(guard.clone())
730 }
731
732 pub fn write_and_swap<F>(&self, f: F) -> CoreResult<()>
734 where
735 F: FnOnce(&mut T),
736 {
737 let front = self.front_index.load(Ordering::Acquire);
738 let back = 1 - front;
739 {
740 let mut guard = self.buffers[back].lock().map_err(|e| {
741 CoreError::ComputationError(ErrorContext::new(format!(
742 "buffer mutex poisoned: {e}"
743 )))
744 })?;
745 f(&mut guard);
746 }
747 self.front_index.store(back, Ordering::Release);
749 if let Ok(mut flag) = self.new_frame_mutex.lock() {
751 *flag = true;
752 self.new_frame.notify_all();
753 }
754 Ok(())
755 }
756
757 pub fn wait_and_read(&self, timeout: Duration) -> CoreResult<Option<T>> {
759 let mut flag = self.new_frame_mutex.lock().map_err(|e| {
760 CoreError::ComputationError(ErrorContext::new(format!("mutex poisoned: {e}")))
761 })?;
762 if !*flag {
763 let (f, timeout_result) = self.new_frame.wait_timeout(flag, timeout).map_err(|e| {
764 CoreError::ComputationError(ErrorContext::new(format!("condvar wait failed: {e}")))
765 })?;
766 flag = f;
767 if timeout_result.timed_out() && !*flag {
768 return Ok(None);
769 }
770 }
771 *flag = false;
772 drop(flag);
773 self.read_front().map(Some)
774 }
775
776 pub fn publish(&self, value: T) -> CoreResult<()> {
778 self.write_and_swap(|buf| {
779 *buf = value;
780 })
781 }
782}
783
784unsafe impl<T: Send> Send for DoubleBuffer<T> {}
785unsafe impl<T: Send + Sync> Sync for DoubleBuffer<T> {}
786
787#[cfg(test)]
792mod tests {
793 use super::*;
794 use std::sync::Arc;
795 use std::thread;
796
797 #[test]
800 fn test_hashmap_basic() {
801 let map: ConcurrentHashMap<String, i32> = ConcurrentHashMap::new();
802 assert!(map.is_empty());
803
804 map.insert("a".to_string(), 1);
805 map.insert("b".to_string(), 2);
806 assert_eq!(map.len(), 2);
807 assert_eq!(map.get(&"a".to_string()), Some(1));
808 assert_eq!(map.get(&"b".to_string()), Some(2));
809 assert_eq!(map.get(&"c".to_string()), None);
810 }
811
812 #[test]
813 fn test_hashmap_remove() {
814 let map: ConcurrentHashMap<String, i32> = ConcurrentHashMap::new();
815 map.insert("x".to_string(), 10);
816 assert_eq!(map.remove(&"x".to_string()), Some(10));
817 assert_eq!(map.len(), 0);
818 assert!(map.is_empty());
819 }
820
821 #[test]
822 fn test_hashmap_concurrent() {
823 let map = Arc::new(ConcurrentHashMap::<u64, u64>::new());
824 let mut handles = Vec::new();
825
826 for t in 0..8 {
827 let m = map.clone();
828 handles.push(thread::spawn(move || {
829 for i in 0..1000 {
830 let key = t * 1000 + i;
831 m.insert(key, key * 2);
832 }
833 }));
834 }
835
836 for h in handles {
837 h.join().expect("thread join");
838 }
839
840 assert_eq!(map.len(), 8000);
841 assert_eq!(map.get(&0), Some(0));
842 assert_eq!(map.get(&7999), Some(7999 * 2));
843 }
844
845 #[test]
846 fn test_hashmap_get_or_insert_with() {
847 let map: ConcurrentHashMap<String, i32> = ConcurrentHashMap::new();
848 let v = map.get_or_insert_with("key".to_string(), || 42);
849 assert_eq!(v, 42);
850 let v2 = map.get_or_insert_with("key".to_string(), || 99);
851 assert_eq!(v2, 42); }
853
854 #[test]
855 fn test_hashmap_get_and_modify() {
856 let map: ConcurrentHashMap<String, i32> = ConcurrentHashMap::new();
857 map.insert("k".to_string(), 10);
858 let result = map.get_and_modify(&"k".to_string(), |v| {
859 *v += 5;
860 *v
861 });
862 assert_eq!(result, Some(15));
863 }
864
865 #[test]
866 fn test_hashmap_keys_and_clear() {
867 let map: ConcurrentHashMap<u32, u32> = ConcurrentHashMap::new();
868 for i in 0..10 {
869 map.insert(i, i);
870 }
871 let keys = map.keys();
872 assert_eq!(keys.len(), 10);
873 map.clear();
874 assert!(map.is_empty());
875 }
876
877 #[test]
878 fn test_hashmap_contains_key() {
879 let map: ConcurrentHashMap<String, i32> = ConcurrentHashMap::new();
880 map.insert("hello".into(), 1);
881 assert!(map.contains_key(&"hello".to_string()));
882 assert!(!map.contains_key(&"world".to_string()));
883 }
884
885 #[test]
888 fn test_queue_basic() {
889 let q: BoundedQueue<i32> = BoundedQueue::new(4);
890 assert!(q.is_empty());
891 assert_eq!(q.capacity(), 4);
892
893 q.push(1).expect("push 1");
894 q.push(2).expect("push 2");
895 assert_eq!(q.len(), 2);
896
897 assert_eq!(q.pop(), Some(1));
898 assert_eq!(q.pop(), Some(2));
899 assert_eq!(q.pop(), None);
900 }
901
902 #[test]
903 fn test_queue_full() {
904 let q: BoundedQueue<i32> = BoundedQueue::new(2);
905 q.push(1).expect("push");
906 q.push(2).expect("push");
907 assert!(q.push(3).is_err()); }
909
910 #[test]
911 fn test_queue_concurrent() {
912 let q = Arc::new(BoundedQueue::<u32>::new(1024));
913 let mut handles = Vec::new();
914
915 for t in 0..4 {
917 let q2 = q.clone();
918 handles.push(thread::spawn(move || {
919 for i in 0..250 {
920 let val = t * 250 + i;
921 while q2.push(val).is_err() {
922 thread::yield_now();
923 }
924 }
925 }));
926 }
927
928 let q3 = q.clone();
930 let consumer = thread::spawn(move || {
931 let mut count = 0u32;
932 while count < 1000 {
933 if q3.pop().is_some() {
934 count += 1;
935 } else {
936 thread::yield_now();
937 }
938 }
939 count
940 });
941
942 for h in handles {
943 h.join().expect("producer");
944 }
945 let total = consumer.join().expect("consumer");
946 assert_eq!(total, 1000);
947 }
948
949 #[test]
950 fn test_queue_close() {
951 let q: BoundedQueue<i32> = BoundedQueue::new(8);
952 q.push(1).expect("push");
953 q.close();
954 assert!(q.is_closed());
955 assert!(q.push(2).is_err()); assert_eq!(q.pop(), Some(1)); }
958
959 #[test]
962 fn test_accumulator_sum() {
963 let acc = ConcurrentAccumulator::new(0i64, |a, b| a + b, 4);
964 for i in 1..=100 {
965 acc.accumulate(i);
966 }
967 assert_eq!(acc.result(), 5050);
968 }
969
970 #[test]
971 fn test_accumulator_concurrent() {
972 let acc = Arc::new(ConcurrentAccumulator::new(0u64, |a, b| a + b, 8));
973 let mut handles = Vec::new();
974
975 for _ in 0..8 {
976 let a = acc.clone();
977 handles.push(thread::spawn(move || {
978 for i in 0..1000u64 {
979 a.accumulate(i);
980 }
981 }));
982 }
983
984 for h in handles {
985 h.join().expect("thread");
986 }
987
988 assert_eq!(acc.result(), 8 * 499500);
990 }
991
992 #[test]
993 fn test_accumulator_reset() {
994 let acc = ConcurrentAccumulator::new(0i32, |a, b| a + b, 4);
995 acc.accumulate(10);
996 acc.accumulate(20);
997 assert_eq!(acc.result(), 30);
998 acc.reset();
999 assert_eq!(acc.result(), 0);
1000 }
1001
1002 #[test]
1005 fn test_atomic_f64() {
1006 let acc = AtomicF64Accumulator::new();
1007 acc.add(1.0);
1008 acc.add(2.0);
1009 acc.add(3.0);
1010 assert!((acc.value() - 6.0).abs() < 1e-10);
1011 assert_eq!(acc.count(), 3);
1012 }
1013
1014 #[test]
1015 fn test_atomic_f64_concurrent() {
1016 let acc = Arc::new(AtomicF64Accumulator::new());
1017 let mut handles = Vec::new();
1018
1019 for _ in 0..8 {
1020 let a = acc.clone();
1021 handles.push(thread::spawn(move || {
1022 for _ in 0..10000 {
1023 a.add(1.0);
1024 }
1025 }));
1026 }
1027 for h in handles {
1028 h.join().expect("thread");
1029 }
1030 assert!((acc.value() - 80000.0).abs() < 1.0);
1031 assert_eq!(acc.count(), 80000);
1032 }
1033
1034 #[test]
1035 fn test_atomic_f64_reset() {
1036 let acc = AtomicF64Accumulator::new();
1037 acc.add(42.0);
1038 acc.reset();
1039 assert!((acc.value()).abs() < 1e-15);
1040 assert_eq!(acc.count(), 0);
1041 }
1042
1043 #[test]
1046 fn test_rwlock_basic() {
1047 let lock = WriterPreferenceRwLock::new(42);
1048 {
1049 let r = lock.read().expect("read");
1050 assert_eq!(*r, 42);
1051 }
1052 {
1053 let mut w = lock.write().expect("write");
1054 *w = 99;
1055 }
1056 {
1057 let r = lock.read().expect("read");
1058 assert_eq!(*r, 99);
1059 }
1060 }
1061
1062 #[test]
1063 fn test_rwlock_concurrent_readers() {
1064 let lock = Arc::new(WriterPreferenceRwLock::new(vec![1, 2, 3]));
1065 let mut handles = Vec::new();
1066
1067 for _ in 0..8 {
1068 let l = lock.clone();
1069 handles.push(thread::spawn(move || {
1070 for _ in 0..100 {
1071 let r = l.read().expect("read");
1072 assert!(!r.is_empty());
1073 }
1074 }));
1075 }
1076
1077 for h in handles {
1078 h.join().expect("thread");
1079 }
1080 }
1081
1082 #[test]
1083 fn test_rwlock_try_read_write() {
1084 let lock = WriterPreferenceRwLock::new(0);
1085 let r = lock.try_read().expect("try_read");
1086 assert!(r.is_some());
1087 drop(r);
1088
1089 let w = lock.try_write().expect("try_write");
1090 assert!(w.is_some());
1091 }
1092
1093 #[test]
1096 fn test_double_buffer_basic() {
1097 let db = DoubleBuffer::new(0i32);
1098 assert_eq!(db.read_front().expect("read"), 0);
1099
1100 db.publish(42).expect("publish");
1101 assert_eq!(db.read_front().expect("read"), 42);
1102 }
1103
1104 #[test]
1105 fn test_double_buffer_write_and_swap() {
1106 let db = DoubleBuffer::new(vec![0u8; 4]);
1107 db.write_and_swap(|buf| {
1108 buf[0] = 1;
1109 buf[1] = 2;
1110 })
1111 .expect("write");
1112 let front = db.read_front().expect("read");
1113 assert_eq!(front[0], 1);
1114 assert_eq!(front[1], 2);
1115 }
1116
1117 #[test]
1118 fn test_double_buffer_wait_timeout() {
1119 let db = Arc::new(DoubleBuffer::new(0));
1120 let db2 = db.clone();
1121
1122 let producer = thread::spawn(move || {
1123 thread::sleep(Duration::from_millis(50));
1124 db2.publish(99).expect("publish");
1125 });
1126
1127 let result = db.wait_and_read(Duration::from_secs(2)).expect("wait");
1128 assert_eq!(result, Some(99));
1129 producer.join().expect("producer");
1130 }
1131
1132 #[test]
1133 fn test_double_buffer_concurrent() {
1134 let db = Arc::new(DoubleBuffer::new(0u64));
1135 let db_w = db.clone();
1136 let writer_done = Arc::new(AtomicBool::new(false));
1137 let writer_done_w = writer_done.clone();
1138
1139 let writer = thread::spawn(move || {
1140 for i in 1..=100u64 {
1141 db_w.publish(i).expect("publish");
1142 }
1143 writer_done_w.store(true, Ordering::Release);
1144 });
1145
1146 let db_r = db.clone();
1152 let writer_done_r = writer_done.clone();
1153 let reader = thread::spawn(move || {
1154 let mut max_seen = 0u64;
1155 loop {
1156 let v = db_r.read_front().expect("read");
1157 if v > max_seen {
1158 max_seen = v;
1159 }
1160 if writer_done_r.load(Ordering::Acquire) {
1161 for _ in 0..16 {
1163 let v = db_r.read_front().expect("read");
1164 if v > max_seen {
1165 max_seen = v;
1166 }
1167 }
1168 break;
1169 }
1170 thread::yield_now();
1171 }
1172 max_seen
1173 });
1174
1175 writer.join().expect("writer");
1176 let max_seen = reader.join().expect("reader");
1177 assert!(max_seen > 0);
1178 assert_eq!(max_seen, 100);
1181 }
1182}
1183
1184pub mod compressed_trie;
1189pub mod persistent_vector;
1190pub mod queue;
1191pub mod skip_list;
1192pub mod stack;
1193
1194pub use compressed_trie::CompressedTrie;
1195pub use persistent_vector::PersistentRrbVec;
1196pub use queue::LockFreeQueue;
1197pub use skip_list::SkipList;
1198pub use stack::LockFreeStack;
1199
1200pub mod async_utils;
1205pub mod barrier;
1206pub mod parallel_iter;
1207pub mod work_stealing;
1208pub use async_utils as concurrent_async;
1209
1210pub use barrier::{CountDownLatch, CyclicBarrier, PhaseBarrier, SpinBarrier};
1211pub use concurrent_async::{
1212 BackoffStrategy, FutureExecutor, JoinFuture, RetryPolicy, Semaphore, SemaphoreGuard,
1213 TokenBucketRateLimiter,
1214};
1215pub use parallel_iter::{
1216 parallel_filter, parallel_for_each, parallel_map, parallel_merge_sort, parallel_partition,
1217 parallel_prefix_sum, parallel_reduce, parallel_scan, ScanMode,
1218};
1219pub use work_stealing::{
1220 Priority, PriorityTaskQueue, SchedulerConfig, SchedulerStats, StealResult, WorkStealingDeque,
1221 WorkStealingScheduler,
1222};