From ad2a33094e832808cf6c3e8166623b6f398ce62e Mon Sep 17 00:00:00 2001 From: traxys Date: Mon, 1 Dec 2025 13:57:20 +0100 Subject: [PATCH] Import last years utils --- Cargo.lock | 458 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 ++ src/lib.rs | 128 ++++++++++++++ src/tinyvec.rs | 433 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1031 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/tinyvec.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..84b4c38 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,458 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "aoc_2025" +version = "0.1.0" +dependencies = [ + "arrayvec", + "bstr", + "clap", + "color-eyre", + "humantime", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "color-eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tracing" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..79f1947 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "aoc_2025" +version = "0.1.0" +authors = ["traxys "] +edition = "2024" + +[dependencies] +arrayvec = "0.7.6" +bstr = "1.11.0" +clap = { version = "4.5.21", features = ["derive"] } +color-eyre = "0.6.3" +humantime = "2.1.0" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7af1ebe --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,128 @@ +use std::path::PathBuf; + +use arrayvec::ArrayVec; +use bstr::{BString, ByteSlice}; +use clap::Parser; + +pub mod tinyvec; + +pub fn neighbours(l: usize, c: usize, map: L) -> ArrayVec<(usize, usize), 4> +where + L: AsRef<[C]>, + C: AsRef<[T]>, +{ + let mut a = ArrayVec::new(); + + if l != 0 { + a.push((l - 1, c)); + } + if c != 0 { + a.push((l, c - 1)); + } + if l + 1 != map.as_ref().len() { + a.push((l + 1, c)) + } + if c + 1 != map.as_ref()[0].as_ref().len() { + a.push((l, c + 1)) + } + + a +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum Direction { + Up, + Right, + Down, + Left, +} + +impl Direction { + pub fn turn_right(self) -> Self { + match self { + Self::Up => Self::Right, + Self::Right => Self::Down, + Self::Down => Self::Left, + Self::Left => Self::Up, + } + } + + pub fn turn_left(self) -> Self { + match self { + Self::Up => Self::Left, + Self::Left => Self::Down, + Self::Down => Self::Right, + Self::Right => Self::Up, + } + } + + pub fn walk(&self, l: usize, c: usize) -> (usize, usize) { + match self { + Direction::Up => (l - 1, c), + Direction::Right => (l, c + 1), + Direction::Down => (l + 1, c), + Direction::Left => (l, c - 1), + } + } + + pub fn all() -> [Self; 4] { + [Self::Up, Self::Right, Self::Down, Self::Left] + } +} + +#[derive(Parser)] +struct Args { + #[arg(short, long)] + part: u32, + #[arg(short, long)] + input: PathBuf, +} + +#[derive(Debug)] +pub struct Context { + pub part: u32, + pub input: BString, +} + +#[macro_export] +macro_rules! print_res { + ($($tt:tt)*) => { + if (!std::env::var("AOC_BENCH").is_ok()) { + println!($($tt)*) + } + }; +} + +#[macro_export] +macro_rules! print_res_part { + ($($tt:tt)*) => { + if (!std::env::var("AOC_BENCH").is_ok()) { + print!($($tt)*) + } + }; +} + +pub fn parse_u64_bytes(b: &[u8]) -> u64 { + b.iter() + .map(|d| { + if d.is_ascii_digit() { + (d - b'0') as u64 + } else { + panic!("Invalid digit in {}", b.as_bstr()) + } + }) + .fold(0, |acc, d| acc * 10 + d) +} + +pub fn load() -> color_eyre::Result { + color_eyre::install()?; + + let args = Args::parse(); + + let input = std::fs::read(args.input)?.into(); + + Ok(Context { + part: args.part, + input, + }) +} diff --git a/src/tinyvec.rs b/src/tinyvec.rs new file mode 100644 index 0000000..ea272cb --- /dev/null +++ b/src/tinyvec.rs @@ -0,0 +1,433 @@ +use std::{alloc::Layout, iter::Copied, marker::PhantomData, mem::ManuallyDrop}; + +const STACK_LEN: usize = std::mem::size_of::<*mut u8>() * 2 - 1; + +#[repr(C)] +struct TinyHeapVec { + len: u8, + data: *mut u8, +} + +#[derive(Clone, Copy)] +#[repr(C)] +struct TinyStackVec { + len: u8, + data: [u8; STACK_LEN], +} + +#[derive(Clone, Copy)] +#[repr(C)] +struct TinyVecLen { + len: u8, +} + +union TinyVecInner { + len: TinyVecLen, + heap: ManuallyDrop, + stack: TinyStackVec, +} + +pub struct TinyVec { + inner: TinyVecInner, + _ph: PhantomData, +} + +impl TinyVec { + pub fn new() -> Self { + const { + if std::mem::align_of::() != 1 { + panic!("alignof T must be 1") + } + } + + Self { + inner: TinyVecInner { + stack: TinyStackVec { + len: 0, + data: [0; STACK_LEN], + }, + }, + _ph: PhantomData, + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn len(&self) -> usize { + unsafe { (self.inner.len.len & 127) as usize } + } + + fn heap_layout() -> Layout { + Layout::from_size_align(127 * size_of::(), 1).unwrap() + } + + pub fn insert_at(&mut self, at: usize, v: T) { + if at > self.len() { + panic!("Out of bound access") + } + + if at == self.len() { + return self.push(v); + } + + let ptr = match self.is_stack() { + true => { + let new_stack_len = (self.len() + 1) * size_of::(); + if new_stack_len > STACK_LEN { + self.spill(); + self.insert_at(at, v); + return; + } else { + unsafe { self.inner.stack.data.as_mut_ptr() } + } + } + false => unsafe { self.inner.heap.data }, + }; + + unsafe { + let place = ptr.cast::().add(at); + place.add(1).copy_from(place, self.len() - at); + place.write(v); + self.inner.len.len += 1 + } + } + + pub fn extend_from_slice(&mut self, slice: &[T]) { + let old_len = self.len(); + let new_len = old_len + slice.len(); + if new_len > 127 { + panic!("Out of capacity") + } + + let ptr = match self.is_stack() { + true if new_len * size_of::() <= STACK_LEN => unsafe { + self.inner.stack.data.as_mut_ptr() + }, + true => { + self.spill(); + self.extend_from_slice(slice); + return; + } + false => unsafe { self.inner.heap.data }, + }; + + unsafe { + ptr.cast::() + .add(old_len) + .copy_from(slice.as_ptr(), slice.len()); + self.inner.len.len += slice.len() as u8 + } + } + + pub fn push(&mut self, v: T) { + if self.len() == 127 { + panic!("Out of capacity"); + } + + let ptr = match self.is_stack() { + true => { + let new_stack_len = (self.len() + 1) * size_of::(); + if new_stack_len > STACK_LEN { + self.spill(); + self.push(v); + return; + } else { + unsafe { self.inner.stack.data.as_mut_ptr() } + } + } + false => unsafe { self.inner.heap.data }, + }; + + unsafe { + ptr.cast::().add(self.len()).write(v); + self.inner.len.len += 1 + }; + } + + fn spill(&mut self) { + assert!(self.is_stack()); + unsafe { + let data = self.inner.stack.data; + self.inner.len.len |= 128; + (*self.inner.heap).data = std::alloc::alloc(Self::heap_layout()); + (*self.inner.heap) + .data + .copy_from(&data as *const _, size_of_val(&data)); + } + } + + fn is_stack(&self) -> bool { + let len = unsafe { self.inner.len.len } as usize; + + len & 128 == 0 + } +} + +impl std::fmt::Debug for TinyVec { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_list().entries(self).finish() + } +} + +impl std::ops::Deref for TinyVec { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + match self.is_stack() { + true => unsafe { + core::slice::from_raw_parts(self.inner.stack.data.as_ptr() as *const _, self.len()) + }, + false => unsafe { + core::slice::from_raw_parts(self.inner.heap.data as *const _, self.len()) + }, + } + } +} + +impl std::ops::DerefMut for TinyVec { + fn deref_mut(&mut self) -> &mut Self::Target { + match self.is_stack() { + true => unsafe { + core::slice::from_raw_parts_mut( + self.inner.stack.data.as_ptr() as *mut _, + self.len(), + ) + }, + false => unsafe { + core::slice::from_raw_parts_mut(self.inner.heap.data as *mut _, self.len()) + }, + } + } +} + +impl Extend for TinyVec { + fn extend>(&mut self, iter: I) { + for v in iter { + self.push(v); + } + } +} + +impl FromIterator for TinyVec { + fn from_iter>(iter: I) -> Self { + let mut s = Self::new(); + s.extend(iter); + s + } +} + +pub struct IntoIter { + index: usize, + v: TinyVec, +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + match self.v.get(self.index) { + None => None, + Some(&e) => { + self.index += 1; + Some(e) + } + } + } +} + +impl IntoIterator for TinyVec { + type Item = T; + + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { index: 0, v: self } + } +} + +impl<'a, T: Copy> IntoIterator for &'a TinyVec { + type Item = T; + + type IntoIter = Copied>; + + fn into_iter(self) -> Self::IntoIter { + self.iter().copied() + } +} + +impl Drop for TinyVec { + fn drop(&mut self) { + if !self.is_stack() { + unsafe { + std::alloc::dealloc(self.inner.heap.data, Self::heap_layout()); + } + } + } +} + +impl Default for TinyVec { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod test { + use itertools::Itertools; + + use crate::tinyvec::STACK_LEN; + + use super::TinyVec; + + #[test] + pub fn empty() { + let a = TinyVec::::new(); + assert_eq!(a.len(), 0); + assert!(a.is_empty()); + assert_eq!(&*a, &[]); + } + + #[test] + pub fn push_stack() { + let mut a = TinyVec::new(); + a.push(42u8); + assert_eq!(a.len(), 1); + assert!(!a.is_empty()); + assert_eq!(&*a, &[42]); + + let mut a = TinyVec::new(); + a.push([42u8, 43]); + assert_eq!(a.len(), 1); + assert!(!a.is_empty()); + assert_eq!(&*a, &[[42, 43]]); + } + + #[test] + pub fn extend_stack() { + let values = (0..STACK_LEN as u8).collect_vec(); + let mut a = TinyVec::::new(); + a.extend_from_slice(&values); + assert_eq!(&*a, &values); + + let mut a = TinyVec::new(); + a.push(values[0]); + a.extend_from_slice(&values[1..]); + assert_eq!(&*a, &values); + + let values = [[43u8, 45], [46, 47]]; + let mut a = TinyVec::new(); + a.extend_from_slice(&values); + assert_eq!(&*a, &values); + + let mut a = TinyVec::new(); + a.push(values[0]); + a.extend_from_slice(&values[1..]); + assert_eq!(&*a, &values); + } + + #[test] + pub fn extend_spill() { + let values = (0..STACK_LEN as u8 + 1).collect_vec(); + let mut a = TinyVec::::new(); + a.extend_from_slice(&values); + assert_eq!(&*a, &values); + + let mut a = TinyVec::new(); + a.push(values[0]); + a.extend_from_slice(&values[1..]); + assert_eq!(&*a, &values); + + let values = [ + [43u8, 45, 46, 47], + [48, 49, 50, 51], + [52, 53, 54, 55], + [56, 57, 58, 59], + ]; + let mut a = TinyVec::new(); + a.extend_from_slice(&values); + assert_eq!(&*a, &values); + + let mut a = TinyVec::new(); + a.push(values[0]); + a.extend_from_slice(&values[1..]); + assert_eq!(&*a, &values); + } + + #[test] + pub fn extend_heap() { + let values = (0..127).collect_vec(); + let mut a = TinyVec::::new(); + a.extend_from_slice(&values[0..10]); + a.extend_from_slice(&values[10..]); + assert_eq!(&*a, values); + } + + #[test] + pub fn insert_stack() { + let mut a = TinyVec::<[u8; 2]>::new(); + a.push([1, 2]); + a.push([3, 4]); + a.insert_at(1, [5, 6]); + assert_eq!(&*a, &[[1, 2], [5, 6], [3, 4]]); + } + + #[test] + pub fn insert_heap() { + let mut values = vec![[0, 0]; 16]; + + let mut a = TinyVec::<[u8; 2]>::new(); + a.extend_from_slice(&values); + + values.insert(1, [5, 6]); + a.insert_at(1, [5, 6]); + + assert_eq!(&*a, &values); + } + + #[test] + pub fn insert_spill() { + let mut values = vec![[0, 0]; 7]; + + let mut a = TinyVec::<[u8; 2]>::new(); + a.extend_from_slice(&values); + + values.insert(1, [5, 6]); + a.insert_at(1, [5, 6]); + + assert_eq!(&*a, &values); + } + + #[test] + pub fn push_spill() { + let values = (0..STACK_LEN as u8 + 1).collect_vec(); + + let mut a = TinyVec::new(); + for &i in &values { + a.push(i); + } + + assert_eq!(a.len(), values.len()); + assert!(!a.is_empty()); + assert_eq!(&*a, &values); + } + + #[test] + pub fn into_iter() { + let values = (0..50u8).collect_vec(); + let mut a = TinyVec::new(); + a.extend_from_slice(&values); + + assert_eq!(values, a.into_iter().collect_vec()); + } + + #[test] + pub fn into_ref_iter() { + let values = (0..50u8).collect_vec(); + let mut a = TinyVec::new(); + a.extend_from_slice(&values); + + assert_eq!(values, (&a).into_iter().collect_vec()); + } +}