use std::mem;
use std::default::Default;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use super::super::atomic_arc::AtomicArc;
use super::super::atomic_cell::AtomicCell;
pub const SEGMENT_SIZE: usize = 32;
#[derive(Debug)]
pub enum Expanded<T> {
No,
Expanded(Arc<Segment<T>>),
}
#[derive(Debug)]
pub struct Segment<T> {
data: [AtomicCell<T>; SEGMENT_SIZE],
write_index: AtomicUsize,
next: AtomicArc<Segment<T>>,
}
impl<T> Segment<T> {
pub fn empty() -> Segment<T> {
Segment {
data: Default::default(),
write_index: AtomicUsize::new(0),
next: AtomicArc::empty(),
}
}
pub fn try_pop(&self, index: usize) -> Option<T> {
unsafe {
self.data[index].read()
}
}
pub fn append(&self, value: T) -> Expanded<T> {
match self.get_write_index() {
Some(index) => {
unsafe { self.data[index].write(value) }
Expanded::No
},
None => {
let next_segment = match self.next.get() {
Some(next_segment) => next_segment,
None => {
self.expand();
self.next.get().unwrap()
}
};
mem::drop(next_segment.append(value));
Expanded::Expanded(next_segment)
},
}
}
fn get_write_index(&self) -> Option<usize> {
match self.write_index.fetch_add(1, Ordering::SeqCst) {
index if index >= SEGMENT_SIZE => None,
index => Some(index),
}
}
fn expand(&self) {
let new_segment = Arc::new(Segment::empty());
self.expand_with_segment(new_segment)
}
fn expand_with_segment(&self, new_segment: Arc<Segment<T>>) {
match self.next.set(new_segment) {
Ok(()) => (),
Err(new_segment) => {
let next_segment = self.next.get().unwrap();
next_segment.expand_with_segment(new_segment);
}
}
}
pub fn next_segment(&self) -> Option<Arc<Segment<T>>> {
self.next.get()
}
pub fn reset(&mut self) {
self.write_index.store(0, Ordering::Relaxed);
let old_arc = mem::replace(&mut self.next, AtomicArc::empty());
mem::drop(old_arc);
}
}