use core::marker::PhantomData;
use deko::read::AnyDecoder;
use memchr::memchr;
use memmap2::Mmap;
use std::fs::File;
use std::io::{self, Read, Stdin, stdin};
use std::path::Path;
const BUFFER_DEFAULT_SIZE: usize = 1 << 17;
const BUFFER_DOUBLE_UNTIL: usize = 1 << 24;
pub trait InputData<'a>: Iterator<Item = &'a [u8]> {
const RANDOM_ACCESS: bool;
fn first_byte(&self) -> u8;
fn current_block(&self) -> &[u8];
#[inline(always)]
fn compression_format(&mut self) -> io::Result<Option<deko::Format>> {
Ok(None)
}
#[inline(always)]
fn is_compressed(&mut self) -> io::Result<bool> {
Ok(self.compression_format()?.is_some())
}
#[inline(always)]
fn data(&self) -> &[u8] {
assert!(Self::RANDOM_ACCESS);
unimplemented!()
}
fn buffer(&self) -> &[u8];
fn buffer_offset(&self) -> usize {
0
}
fn is_end_of_buffer(&self) -> bool;
#[doc(hidden)]
#[inline(always)]
fn make_room(&mut self, _keep_from: usize) {}
#[doc(hidden)]
#[inline(always)]
fn grow_buffer(&mut self, _additional: usize) {}
#[doc(hidden)]
fn skip_to_newline(&mut self) -> Option<(usize, usize, usize)>;
}
pub trait FromInputData<'a, I: InputData<'a>>: Sized {
fn from_input(input: I) -> io::Result<Self>;
}
pub struct SliceInput<'a> {
data: &'a [u8],
pos: usize,
first_byte: u8,
last_block: [u8; 64],
}
impl<'a> SliceInput<'a> {
pub fn new(data: &'a [u8]) -> Self {
assert!(!data.is_empty());
let mut last_block = [0; 64];
last_block[..data.len() % 64].copy_from_slice(&data[(data.len() / 64) * 64..]);
Self {
data,
pos: 0,
first_byte: data[0],
last_block,
}
}
}
impl<'a> Iterator for SliceInput<'a> {
type Item = &'a [u8];
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
let pos = self.pos;
self.pos += 64;
if pos + 64 <= self.data.len() {
unsafe { Some(std::slice::from_raw_parts(self.data.as_ptr().add(pos), 64)) }
} else if pos < self.data.len() {
unsafe {
Some(std::slice::from_raw_parts(
self.last_block.as_ptr(),
self.data.len() % 64,
))
}
} else {
None
}
}
}
impl<'a> InputData<'a> for SliceInput<'a> {
const RANDOM_ACCESS: bool = true;
#[inline(always)]
fn first_byte(&self) -> u8 {
self.first_byte
}
#[inline(always)]
fn current_block(&self) -> &[u8] {
if 64 <= self.pos && self.pos <= self.data.len() {
unsafe { std::slice::from_raw_parts(self.data.as_ptr().add(self.pos - 64), 64) }
} else {
unsafe { std::slice::from_raw_parts(self.last_block.as_ptr(), self.data.len() % 64) }
}
}
#[inline(always)]
fn data(&self) -> &[u8] {
self.data
}
#[inline(always)]
fn buffer(&self) -> &[u8] {
self.data
}
#[inline(always)]
fn is_end_of_buffer(&self) -> bool {
self.pos >= self.data.len()
}
#[inline(always)]
fn skip_to_newline(&mut self) -> Option<(usize, usize, usize)> {
if self.pos >= self.data.len() {
return None;
}
let p = memchr(b'\n', &self.data[self.pos..])?;
let delta_blocks = p / 64;
let pos_in_block = p % 64;
let block_start = self.pos + delta_blocks * 64;
let block_end = (block_start + 64).min(self.data.len());
let block_len = block_end - block_start;
self.pos = block_start + 64;
Some((delta_blocks, pos_in_block, block_len))
}
}
pub trait FromSlice<'a>: FromInputData<'a, SliceInput<'a>> {
#[inline(always)]
fn from_slice(data: &'a [u8]) -> io::Result<Self> {
Self::from_input(SliceInput::new(data))
}
}
impl<'a, F: FromInputData<'a, SliceInput<'a>>> FromSlice<'a> for F {}
pub struct MmapInput<'a> {
slice: SliceInput<'a>,
_mmap: Mmap,
}
impl<'a> MmapInput<'a> {
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let file = File::open(path)?;
let _mmap = unsafe { Mmap::map(&file)? };
let data = unsafe { std::slice::from_raw_parts(_mmap.as_ptr(), _mmap.len()) };
Ok(Self {
slice: SliceInput::new(data),
_mmap,
})
}
}
impl<'a> Iterator for MmapInput<'a> {
type Item = &'a [u8];
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.slice.next()
}
}
impl<'a> InputData<'a> for MmapInput<'a> {
const RANDOM_ACCESS: bool = true;
#[inline(always)]
fn first_byte(&self) -> u8 {
self.slice.first_byte()
}
#[inline(always)]
fn current_block(&self) -> &[u8] {
self.slice.current_block()
}
#[inline(always)]
fn data(&self) -> &[u8] {
self.slice.data()
}
#[inline(always)]
fn buffer(&self) -> &[u8] {
self.slice.buffer()
}
#[inline(always)]
fn is_end_of_buffer(&self) -> bool {
self.slice.is_end_of_buffer()
}
#[inline(always)]
fn skip_to_newline(&mut self) -> Option<(usize, usize, usize)> {
self.slice.skip_to_newline()
}
}
pub trait FromMmap<'a>: FromInputData<'a, MmapInput<'a>> {
#[inline(always)]
fn from_file_mmap<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Self::from_input(MmapInput::new(path)?)
}
}
impl<'a, F: FromInputData<'a, MmapInput<'a>>> FromMmap<'a> for F {}
pub struct RamFileInput {
slice: SliceInput<'static>,
_vec: Vec<u8>,
}
impl RamFileInput {
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let _vec = std::fs::read(path)?;
let data = unsafe { std::slice::from_raw_parts(_vec.as_ptr(), _vec.len()) };
Ok(Self {
slice: SliceInput::new(data),
_vec,
})
}
}
impl Iterator for RamFileInput {
type Item = &'static [u8];
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.slice.next()
}
}
impl InputData<'static> for RamFileInput {
const RANDOM_ACCESS: bool = true;
#[inline(always)]
fn first_byte(&self) -> u8 {
self.slice.first_byte()
}
#[inline(always)]
fn current_block(&self) -> &[u8] {
self.slice.current_block()
}
#[inline(always)]
fn data(&self) -> &[u8] {
self.slice.data()
}
#[inline(always)]
fn buffer(&self) -> &[u8] {
self.slice.buffer()
}
#[inline(always)]
fn is_end_of_buffer(&self) -> bool {
self.slice.is_end_of_buffer()
}
#[inline(always)]
fn skip_to_newline(&mut self) -> Option<(usize, usize, usize)> {
self.slice.skip_to_newline()
}
}
pub trait FromRamFile: FromInputData<'static, RamFileInput> {
#[inline(always)]
fn from_file_in_ram<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Self::from_input(RamFileInput::new(path)?)
}
}
impl<F: FromInputData<'static, RamFileInput>> FromRamFile for F {}
pub struct ReaderInput<'a, R: Read + Send + 'a> {
data: Vec<u8>,
len: usize,
pos: usize,
offset: usize,
first_byte: u8,
decoder: AnyDecoder<R>,
_phantom: PhantomData<&'a ()>,
}
impl<'a, R: Read + Send + 'a> ReaderInput<'a, R> {
pub fn new(reader: R) -> Self {
let mut decoder = AnyDecoder::new(reader);
let mut data = vec![0; BUFFER_DEFAULT_SIZE];
let len = decoder
.read(&mut data[..64])
.expect("Error while reading data");
let first_byte = data[0];
Self {
data,
len,
pos: 0,
offset: 0,
first_byte,
decoder,
_phantom: PhantomData,
}
}
}
impl<'a, R: Read + Send + 'a> Iterator for ReaderInput<'a, R> {
type Item = &'a [u8];
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.len {
let saved_offset = self.offset;
let saved_pos = self.pos;
let saved_len = self.len;
self.offset += self.len;
self.pos = 0;
self.len = 0;
while self.len < self.data.len() {
let n = self
.decoder
.read(&mut self.data[self.len..])
.expect("Error while reading data");
if n == 0 {
break;
}
self.len += n;
}
if self.len == 0 {
self.offset = saved_offset;
self.pos = saved_pos;
self.len = saved_len;
return None;
}
let padded_len = self.len.next_multiple_of(64);
self.data[self.len..padded_len].fill(0);
}
let pos = self.pos;
self.pos += 64;
if pos + 64 <= self.len {
unsafe { Some(std::slice::from_raw_parts(self.data.as_ptr().add(pos), 64)) }
} else {
unsafe {
Some(std::slice::from_raw_parts(
self.data.as_ptr().add(pos),
self.len % 64,
))
}
}
}
}
impl<'a, R: Read + Send + 'a> InputData<'a> for ReaderInput<'a, R> {
const RANDOM_ACCESS: bool = false;
#[inline(always)]
fn first_byte(&self) -> u8 {
self.first_byte
}
#[inline(always)]
fn current_block(&self) -> &[u8] {
if 64 <= self.pos && self.pos <= self.len {
unsafe { std::slice::from_raw_parts(self.data.as_ptr().add(self.pos - 64), 64) }
} else {
unsafe {
std::slice::from_raw_parts(
self.data.as_ptr().add((self.len / 64) * 64),
self.len % 64,
)
}
}
}
#[inline(always)]
fn compression_format(&mut self) -> io::Result<Option<deko::Format>> {
let format = self.decoder.kind()?;
if format == deko::Format::Verbatim {
Ok(None)
} else {
Ok(Some(format))
}
}
#[inline(always)]
fn buffer(&self) -> &[u8] {
&self.data[..self.len]
}
#[inline(always)]
fn buffer_offset(&self) -> usize {
self.offset
}
#[inline(always)]
fn is_end_of_buffer(&self) -> bool {
self.pos >= self.len
}
#[inline(always)]
fn make_room(&mut self, keep_from: usize) {
let shift = keep_from.saturating_sub(self.offset);
let aligned_shift = (shift / 64) * 64;
if aligned_shift > 0 {
self.data.copy_within(aligned_shift..self.len, 0);
self.len -= aligned_shift;
self.pos -= aligned_shift;
self.offset += aligned_shift;
} else {
let new_size = if self.data.len() < BUFFER_DOUBLE_UNTIL {
self.data.len() * 2
} else {
self.data.len() + BUFFER_DOUBLE_UNTIL
};
self.data.resize(new_size, 0);
}
while self.len < self.data.len() {
let n = self
.decoder
.read(&mut self.data[self.len..])
.expect("Error while reading data");
if n == 0 {
break;
}
self.len += n;
}
let padded = self.len.next_multiple_of(64);
self.data[self.len..padded].fill(0);
}
#[inline(always)]
fn grow_buffer(&mut self, additional: usize) {
self.data.resize(self.len + additional, 0);
let n = self
.decoder
.read(&mut self.data[self.len..])
.expect("Error while reading data");
self.len += n;
let padded_len = self.len.next_multiple_of(64);
self.data[self.len..padded_len].fill(0);
}
#[inline(always)]
fn skip_to_newline(&mut self) -> Option<(usize, usize, usize)> {
if self.pos >= self.len {
return None;
}
let p = memchr(b'\n', &self.data[self.pos..self.len])?;
let delta_blocks = p / 64; let pos_in_block = p % 64; let block_start = self.pos + delta_blocks * 64;
let block_end = (block_start + 64).min(self.len);
let block_len = block_end - block_start;
self.pos = block_start + 64;
Some((delta_blocks, pos_in_block, block_len))
}
}
pub trait FromReader<'a, R: Read + Send + 'a>: FromInputData<'a, ReaderInput<'a, R>> {
#[inline(always)]
fn from_reader(reader: R) -> io::Result<Self> {
Self::from_input(ReaderInput::new(reader))
}
}
impl<'a, R: Read + Send + 'a, F: FromInputData<'a, ReaderInput<'a, R>>> FromReader<'a, R> for F {}
pub struct FileInput {
reader: ReaderInput<'static, File>,
}
impl FileInput {
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Ok(Self {
reader: ReaderInput::new(File::open(path)?),
})
}
}
impl Iterator for FileInput {
type Item = &'static [u8];
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.reader.next()
}
}
impl InputData<'static> for FileInput {
const RANDOM_ACCESS: bool = false;
#[inline(always)]
fn first_byte(&self) -> u8 {
self.reader.first_byte()
}
#[inline(always)]
fn current_block(&self) -> &[u8] {
self.reader.current_block()
}
#[inline(always)]
fn compression_format(&mut self) -> io::Result<Option<deko::Format>> {
self.reader.compression_format()
}
#[inline(always)]
fn buffer(&self) -> &[u8] {
self.reader.buffer()
}
#[inline(always)]
fn buffer_offset(&self) -> usize {
self.reader.buffer_offset()
}
#[inline(always)]
fn is_end_of_buffer(&self) -> bool {
self.reader.is_end_of_buffer()
}
#[inline(always)]
fn make_room(&mut self, keep_from: usize) {
self.reader.make_room(keep_from)
}
#[inline(always)]
fn grow_buffer(&mut self, additional: usize) {
self.reader.grow_buffer(additional)
}
#[inline(always)]
fn skip_to_newline(&mut self) -> Option<(usize, usize, usize)> {
self.reader.skip_to_newline()
}
}
pub trait FromFile: FromInputData<'static, FileInput> {
#[inline(always)]
fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
Self::from_input(FileInput::new(path)?)
}
}
impl<F: FromInputData<'static, FileInput>> FromFile for F {}
pub struct StdinInput {
reader: ReaderInput<'static, Stdin>,
}
impl StdinInput {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
reader: ReaderInput::new(stdin()),
}
}
}
impl Iterator for StdinInput {
type Item = &'static [u8];
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.reader.next()
}
}
impl InputData<'static> for StdinInput {
const RANDOM_ACCESS: bool = false;
#[inline(always)]
fn first_byte(&self) -> u8 {
self.reader.first_byte()
}
#[inline(always)]
fn current_block(&self) -> &[u8] {
self.reader.current_block()
}
#[inline(always)]
fn compression_format(&mut self) -> io::Result<Option<deko::Format>> {
self.reader.compression_format()
}
#[inline(always)]
fn buffer(&self) -> &[u8] {
self.reader.buffer()
}
#[inline(always)]
fn buffer_offset(&self) -> usize {
self.reader.buffer_offset()
}
#[inline(always)]
fn is_end_of_buffer(&self) -> bool {
self.reader.is_end_of_buffer()
}
#[inline(always)]
fn make_room(&mut self, keep_from: usize) {
self.reader.make_room(keep_from)
}
#[inline(always)]
fn grow_buffer(&mut self, additional: usize) {
self.reader.grow_buffer(additional)
}
#[inline(always)]
fn skip_to_newline(&mut self) -> Option<(usize, usize, usize)> {
self.reader.skip_to_newline()
}
}
pub trait FromStdin: FromInputData<'static, StdinInput> {
#[inline(always)]
fn from_stdin() -> io::Result<Self> {
Self::from_input(StdinInput::new())
}
}
impl<F: FromInputData<'static, StdinInput>> FromStdin for F {}