use std::fmt::{Debug, Error, Formatter};
use std::fs::File;
use std::io::Read;
#[cfg(not(feature = "no_flush_alloc"))]
use crate::ll::*;
pub fn rand() -> i64 {
let mut buf: [u8; 8] = [0u8; 8];
let mut f = File::open("/dev/urandom").unwrap();
f.read_exact(&mut buf).unwrap();
i64::from_be_bytes(buf)
}
#[inline]
#[cfg(target_os = "macos")]
pub fn cpu() -> usize {
std::thread::current().id().as_u64().get() as usize
}
#[inline]
#[cfg(target_os = "linux")]
pub fn cpu() -> usize {
unsafe { libc::sched_getcpu() as usize }
}
static mut CRASH_AT: Option<u32> = None;
static mut CRASH_ALLOWED: bool = false;
pub fn allow_crash(v: bool) {
unsafe {
CRASH_ALLOWED = v;
}
}
pub fn may_crash(ln: u32, cnt: i32) {
unsafe {
if !CRASH_ALLOWED {
return;
}
if let Some(line) = CRASH_AT {
if ln == line {
static mut COUNT: i32 = 0;
COUNT += 1;
println!("Crashed at line {}", ln);
std::process::exit(0);
}
} else {
for (key, value) in std::env::vars() {
if key == "CRASH_AT" {
let line: u32 = value.parse().unwrap_or(u32::MAX);
CRASH_AT = Some(line);
may_crash(ln, cnt);
return;
}
}
CRASH_AT = Some(u32::MAX);
}
}
}
#[repr(C)]
pub struct Ring<T, const N: usize> {
data: [T; N],
head: usize,
tail: usize,
}
impl<T, const N: usize> Ring<T, N> {
pub fn new() -> Self {
unsafe {
Self {
data: std::mem::zeroed(),
head: 0,
tail: 0,
}
}
}
#[inline]
pub fn push(&mut self, x: T) {
debug_assert!(
(self.tail+1)%N != self.head,
format!("too many slots are used (len = {})", N)
);
self.data[self.tail] = x;
self.tail = (self.tail + 1) % N;
}
#[inline]
pub fn push_sync(&mut self, x: T) {
debug_assert!(
(self.tail+1)%N != self.head,
format!("too many slots are used (len = {})", N)
);
self.data[self.tail] = x;
#[cfg(not(feature = "no_flush_alloc"))]
msync(&self.data[self.tail], 8);
self.tail = (self.tail + 1) % N;
#[cfg(not(feature = "no_flush_alloc"))]
msync(&self.head, 16);
}
#[inline]
pub fn sync_all(&self) {
if self.head == self.tail {
msync(&self.head, 16);
return;
}
#[cfg(not(feature = "no_flush_alloc"))]
{
let h = &self.data[self.head] as *const _ as usize;
let t = &self.data[self.tail] as *const _ as usize;
if h < t {
msync(&self.data[self.head], t - h);
msync(&self.head, 16);
} else {
let b = self as *const Self as usize;
msync(self, h - b);
let b = b + std::mem::size_of::<Self>();
msync(&self.data[self.tail], b - t);
}
}
}
#[inline]
pub fn contains(&self, x: T)-> bool where T: Eq {
let mut head = self.head;
while head != self.tail {
if x == self.data[head] {
return true;
}
head = (head + 1) % N;
}
false
}
#[inline]
pub fn clear(&mut self) {
self.head = self.tail;
}
#[inline]
pub fn empty(&self) -> bool {
self.head == self.tail
}
#[inline]
pub fn len(&self) -> usize {
((self.tail + N) - self.head) % N
}
}
impl<T: Copy, const N: usize> Ring<T, N> {
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.head == self.tail {
None
} else {
let res = Some(self.data[self.head]);
self.head = (self.head + 1) % N;
res
}
}
#[inline]
pub fn foreach<F: Fn(T) -> ()>(&mut self, f: F) {
while self.head != self.tail {
f(self.data[self.head]);
self.head = (self.head + 1) % N;
}
}
#[inline]
pub fn foreach_atomic<F: Fn(T), E: Fn()>(&mut self, f: F, end: E) {
while self.head != self.tail {
f(self.data[self.head]);
self.head = (self.head + 1) % N;
end();
}
}
#[inline]
pub fn foreach_reverse<F: Fn(T) -> ()>(&mut self, f: F) {
let mut tail = self.tail;
while tail != self.head {
let d = self.data[tail];
f(d);
tail = (tail + N - 1) % N;
}
}
#[inline]
pub fn find<F: Fn(T) -> bool>(&self, f: F) -> bool {
let mut head = self.head;
while head != self.tail {
let d = self.data[head];
if f(d) {
return true;
}
head = (head + 1) % N;
}
false
}
}
impl<T: Debug, const N: usize> Debug for Ring<T, N> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(f, "{{len: {}, [", self.len())?;
let mut head = self.head;
while head != self.tail {
write!(f, "{:?}", self.data[head])?;
head = (head + 1) % N;
if head != self.tail {
write!(f, ", ")?;
}
}
write!(f, "]}}")
}
}
mod test {
#![allow(unused)]
use super::Ring;
#[test]
fn ring_buffer() {
let mut rng: Ring<i32, 8> = Ring::new();
for i in 1..8 {
rng.push(i);
println!("{:?}", rng);
}
rng.foreach(|x| {
println!("{}", x);
});
}
}