You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
6.0 KiB
236 lines
6.0 KiB
|
|
//#[inline]
|
|
fn reverse<T>(slice: &mut [T])
|
|
{
|
|
match slice {
|
|
[ref mut a, ref mut rest @ .., ref mut b] => {
|
|
std::mem::swap(a, b);
|
|
reverse(rest)
|
|
},
|
|
[] | [_] => (),
|
|
}
|
|
}
|
|
|
|
/// This actually works! And is so easily parallelisable with something like rayon, or asyncing by spawning/creating the tail-call into a new task, then either waiting them concurrently or in parallen (spawn or created future from just calling the function without awaiting it)
|
|
#[allow(dead_code)]
|
|
fn binsearch<'a, V: ?Sized, T: PartialEq<V> + 'a>(slice: &'a [T], find: &V) -> Option<&'a T>
|
|
{
|
|
match slice {
|
|
[ref a, pivot @ .., ref b] => {
|
|
match (a==find, b==find) {
|
|
(true, _) => Some(a),
|
|
(_, true) => Some(b),
|
|
_ => binsearch(pivot, find),
|
|
}
|
|
},
|
|
[ref a] if a == find => Some(a),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
trait Input: AsRef<[u8]> + std::fmt::Debug{}
|
|
impl<T: ?Sized> Input for T
|
|
where T: AsRef<[u8]> + std::fmt::Debug{}
|
|
|
|
fn collect_input() -> Box<dyn Iterator<Item= impl Input + 'static> + 'static>
|
|
{
|
|
use std::{
|
|
ffi::{OsStr, OsString},
|
|
os::unix::ffi::*,
|
|
};
|
|
|
|
//#[derive(Debug)]
|
|
enum MaybeUTF8
|
|
{
|
|
UTF8(String),
|
|
Raw(OsString),
|
|
Static(&'static [u8]),
|
|
}
|
|
|
|
impl std::fmt::Debug for MaybeUTF8
|
|
{
|
|
// Custom Debug impl to ensure output is identical when `output-quoted` is enabled.
|
|
#[inline]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
|
{
|
|
let dbg: &dyn std::fmt::Debug = match self {
|
|
Self::UTF8(string) => string,
|
|
Self::Raw(raw) => raw,
|
|
|
|
Self::Static(&[]) => return f.write_str("\"\""),
|
|
Self::Static(bytes) => return std::fmt::Debug::fmt(OsStr::from_bytes(bytes), f),
|
|
};
|
|
std::fmt::Debug::fmt(dbg, f)
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for MaybeUTF8
|
|
{
|
|
#[inline]
|
|
fn as_ref(&self) -> &[u8]
|
|
{
|
|
match self {
|
|
Self::UTF8(string) => string.as_bytes(),
|
|
Self::Raw(raw) => raw.as_bytes(),
|
|
Self::Static(bytes) => bytes,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<String> for MaybeUTF8
|
|
{
|
|
#[inline(always)]
|
|
fn from(from: String) -> Self
|
|
{
|
|
Self::UTF8(from)
|
|
}
|
|
}
|
|
|
|
impl From<OsString> for MaybeUTF8
|
|
{
|
|
#[inline(always)]
|
|
fn from(from: OsString) -> Self
|
|
{
|
|
Self::Raw(from)
|
|
}
|
|
}
|
|
|
|
impl MaybeUTF8
|
|
{
|
|
#[inline(always)]
|
|
pub const fn from_static_bytes(bytes: &'static [u8]) -> Self
|
|
{
|
|
Self::Static(bytes)
|
|
}
|
|
#[inline(always)]
|
|
pub fn from_raw_bytes(bytes: &[u8]) -> Self
|
|
{
|
|
Self::Raw(OsStr::from_bytes(bytes).to_os_string())
|
|
}
|
|
#[inline(always)]
|
|
//#[deprecated(note="XXX: TODO: Only use this if the read_until() into vec does not add the '\n' into the vec as well. Otherwise, *always* use this.")]
|
|
pub fn from_raw_vec(vec: Vec<u8>) -> Self
|
|
{
|
|
Self::Raw(OsString::from_vec(vec))
|
|
}
|
|
}
|
|
|
|
if std::env::args_os().len() <= 1 {
|
|
use std::io::{
|
|
self,
|
|
BufRead,
|
|
};
|
|
// No args, collect stdin lines
|
|
if !cfg!(feature="byte-strings") {
|
|
// Collect utf8 string lines
|
|
Box::new(io::stdin()
|
|
.lock()
|
|
.lines()
|
|
.filter_map(Result::ok)
|
|
.map(MaybeUTF8::from))
|
|
} else {
|
|
// Collect arbitrary byte strings
|
|
struct OsLineReader<'a>(io::StdinLock<'a>, Vec<u8>);
|
|
|
|
impl<'a> Iterator for OsLineReader<'a>
|
|
{
|
|
type Item = MaybeUTF8;
|
|
fn next(&mut self) -> Option<Self::Item>
|
|
{
|
|
Some(match handle_fmt_err_or(self.0.read_until(b'\n', &mut self.1), || 0) {
|
|
0 => return None,
|
|
1 if self.1[0] == b'\n' => MaybeUTF8::from_static_bytes(&[]),
|
|
read_sz => {
|
|
let line = if self.1[read_sz-1] == b'\n' {
|
|
MaybeUTF8::from_raw_bytes(&self.1[..(read_sz-1)])
|
|
} else {
|
|
MaybeUTF8::from_raw_vec(self.1.clone())
|
|
};
|
|
debug_assert_ne!(line.as_ref().iter().last().copied(), Some(b'\n'), "Deliminator still in output");
|
|
|
|
self.1.clear();
|
|
line
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
Box::new(OsLineReader(io::stdin().lock(), // Acquire the lock until the iterator is consumed (like all other paths in this function)
|
|
Vec::with_capacity(4096))) // Buffer of size 4k
|
|
}
|
|
} else {
|
|
// Has arguments, return them
|
|
if cfg!(feature="byte-strings") {
|
|
Box::new(std::env::args_os().skip(1).map(MaybeUTF8::from))
|
|
} else if cfg!(feature="ignore-invalid-args") {
|
|
Box::new(std::env::args_os().skip(1).filter_map(|os| os.into_string().ok()).map(MaybeUTF8::from))
|
|
} else {
|
|
Box::new(std::env::args_os().skip(1).map(|os| os.to_string_lossy().into_owned().into()))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
#[cfg_attr(feature="ignore-output-errors", inline)]
|
|
fn handle_fmt_err_or<F, T>(res: std::io::Result<T>, or: F) -> T
|
|
where F: FnOnce() -> T
|
|
{
|
|
#[cfg(not(feature="ignore-output-errors"))] {
|
|
match res {
|
|
Ok(v) => return v,
|
|
Err(e) => eprintln!("[!] failed to write line: {e}"),
|
|
}
|
|
return or();
|
|
}
|
|
|
|
|
|
#[cfg(feature="ignore-output-errors")]
|
|
res.unwrap_or_else(|_| or())
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
#[cfg_attr(feature="ignore-output-errors", inline(always))]
|
|
fn handle_fmt_err<T>(res: std::io::Result<T>)
|
|
{
|
|
#[cfg(not(feature="ignore-output-errors"))]
|
|
if let Err(e) = res {
|
|
eprintln!("[!] failed to write line: {e}");
|
|
}
|
|
let _ = res;
|
|
}
|
|
|
|
fn main() {
|
|
let mut args: Vec<_> = collect_input().collect();
|
|
reverse(&mut args[..]);
|
|
//eprintln!("{:?}", binsearch(&args[..], "1")); // It works!
|
|
#[cfg(feature="output-lines")]
|
|
{
|
|
#[allow(unused_imports)]
|
|
use std::io::{
|
|
Write, BufWriter,
|
|
};
|
|
#[cfg(feature="buffer-output")]
|
|
let mut out = BufWriter::new(std::io::stdout().lock());
|
|
#[cfg(not(feature="buffer-output"))]
|
|
let mut out = std::io::stdout().lock();
|
|
for x in args.iter() {
|
|
handle_fmt_err({
|
|
if cfg!(feature="output-quoted") {
|
|
//XXX: This doesn't flush, right? It shouldn't, but maybe we should test it?
|
|
writeln!(&mut out, "{:?}", x)
|
|
}
|
|
else {
|
|
//writeln!(&mut out, "{}", x)
|
|
out.write(x.as_ref())
|
|
.and_then(|_| out.write(b"\n"))
|
|
.map(|_| {})
|
|
}
|
|
});
|
|
}
|
|
//#[cfg(feature="buffer-output")]
|
|
handle_fmt_err(out.flush()); //XXX: Do we need to flush when not buffering output? Does it matter since buffering output will be enabled by default and should almost always be enabled?
|
|
}
|
|
#[cfg(not(feature="output-lines"))]
|
|
println!("{:?}", args);
|
|
}
|