use core;
pub const MAX_THREADS: usize = 16;


pub struct FixedQueue<T:Sized>{
  data: [Option<T>;MAX_THREADS],
  size: usize,
  start: usize,
}
impl<T:Sized> Default for FixedQueue<T> {
  fn default() -> Self {
    Self::new()
  }
}
impl<T:Sized> FixedQueue<T> {
  pub fn new() -> Self {
    FixedQueue{
      data:[None,None,None,None,None,None,None,None,
            None,None,None,None,None,None,None,None,
      ],
      size:0,
      start:0,
    }
  }
  pub fn can_push(&self) -> bool {
    self.size < self.data.len()
  }
  pub fn size(&self) -> usize {
    self.size
  }
  pub fn push(&mut self, item: T) -> Result<(), ()> {
    if self.size == self.data.len() {
      return Err(());
    }
    let index = (self.start + self.size) % self.data.len();
    self.data[index] = Some(item);
    self.size += 1;
    Ok(())
  }
  pub fn pop(&mut self) -> Option<T> {
    if self.size == 0 {
      return None;
    }
    let index = self.start%self.data.len();
    let ret = core::mem::replace(&mut self.data[index], None);
    self.start += 1;
    self.size -= 1;
    ret
  }
  pub fn how_much_free_space(&self) -> usize {
    self.data.len() - self.size
  }
  pub fn remove<F:Fn(&Option<T>) ->bool>(&mut self,f:F) -> Option<T> {
    if self.size == 0 {
      return None;
    }
    for index in 0..self.size {
      if f(&self.data[(self.start + index)%self.data.len()]) {
        let start_index = self.start%self.data.len();
        let target_index = (self.start + index)%self.data.len();
        let ret = core::mem::replace(&mut self.data[target_index], None);
        let replace = core::mem::replace(&mut self.data[start_index], None);
        let is_none = core::mem::replace(&mut self.data[target_index], replace);
        assert!(is_none.is_none());
        self.start += 1;
        self.size -= 1;
        return ret
      }
    }
    None
  }
}
