diff --git a/2023/day1/Cargo.toml b/2023/day1/Cargo.toml index 29b7c0f..cdf0b0d 100644 --- a/2023/day1/Cargo.toml +++ b/2023/day1/Cargo.toml @@ -7,3 +7,8 @@ edition = "2021" [dependencies] helper.workspace = true +divan.workspace = true + +[[bench]] +name = "benches" +harness = false diff --git a/2023/day1/benches/benches.rs b/2023/day1/benches/benches.rs new file mode 100644 index 0000000..0c2dbb5 --- /dev/null +++ b/2023/day1/benches/benches.rs @@ -0,0 +1,3 @@ +fn main() { + day1::bench(); +} diff --git a/2023/day1/src/lib.rs b/2023/day1/src/lib.rs new file mode 100644 index 0000000..d1941de --- /dev/null +++ b/2023/day1/src/lib.rs @@ -0,0 +1,83 @@ +use std::mem::MaybeUninit; + +use helper::{Day, Variants}; + +mod branchless; +mod naive; +mod no_lines; +mod vectorized; +mod zero_alloc; + +pub fn main() { + helper::main::(include_str!("../input.txt")); +} + +struct Day1; + +helper::define_variants! { + day => crate::Day1; + part1 { + basic => crate::part1; + } + part2 { + naive => crate::naive::part2; + zero_alloc => crate::zero_alloc::part2; + branchless => |i| unsafe { crate::branchless::part2(i) }; + no_lines => |i| unsafe { crate::no_lines::part2(i) }; + vectorized => |i| unsafe { crate::vectorized::part2(i) }; + } +} + +impl Day for Day1 { + fn pad_input(input: &str) -> std::borrow::Cow { + let mut input = input.to_owned(); + input.reserve(10); // enough to read u64 + unsafe { + input + .as_mut_vec() + .spare_capacity_mut() + .fill(MaybeUninit::new(0)) + }; + std::borrow::Cow::Owned(input) + } + fn part1() -> Variants { + part1_variants!(construct_variants) + } + + fn part2() -> Variants { + part2_variants!(construct_variants) + } +} + +fn part1(input: &str) -> u64 { + let sum = input + .lines() + .map(|line| { + let mut chars = line.chars().filter(|c| c.is_ascii_digit()); + let first = chars.next().unwrap(); + let last = chars.next_back().unwrap_or(first); + + [first, last] + .into_iter() + .collect::() + .parse::() + .unwrap() + }) + .sum::(); + + sum +} + +helper::tests! { + day1 Day1; + part1 { + "../input_small1.txt" => 142; + "../input.txt" => 54632; + } + part2 { + "../input_small2.txt" => 281; + "../input.txt" => 54019; + } +} + +helper::benchmarks! {} diff --git a/2023/day1/src/main.rs b/2023/day1/src/main.rs index 59fb8db..424c64a 100644 --- a/2023/day1/src/main.rs +++ b/2023/day1/src/main.rs @@ -1,75 +1,3 @@ -use std::mem::MaybeUninit; - -use helper::{Day, Variant, Variants}; - -mod branchless; -mod naive; -mod no_lines; -mod vectorized; -mod zero_alloc; - fn main() { - helper::main::(include_str!("../input.txt")); -} - -struct Day1; - -impl Day for Day1 { - fn pad_input(input: &str) -> std::borrow::Cow { - let mut input = input.to_owned(); - input.reserve(10); // enough to read u64 - unsafe { - input - .as_mut_vec() - .spare_capacity_mut() - .fill(MaybeUninit::new(0)) - }; - std::borrow::Cow::Owned(input) - } - fn part1() -> Variants { - Variants::basic(part1) - } - - fn part2() -> Variants { - Variants { - variants: vec![ - Variant::new("naive", naive::part2), - Variant::new("zero_alloc", zero_alloc::part2), - Variant::new("branchless", |i| unsafe { branchless::part2(i) }), - Variant::new("no_lines", |i| unsafe { no_lines::part2(i) }), - Variant::new("vectorized", |i| unsafe { vectorized::part2(i) }), - ], - } - } -} - -fn part1(input: &str) -> u64 { - let sum = input - .lines() - .map(|line| { - let mut chars = line.chars().filter(|c| c.is_ascii_digit()); - let first = chars.next().unwrap(); - let last = chars.next_back().unwrap_or(first); - - [first, last] - .into_iter() - .collect::() - .parse::() - .unwrap() - }) - .sum::(); - - sum -} - -helper::tests! { - day1 Day1; - part1 { - "../input_small1.txt" => 142; - "../input.txt" => 54632; - } - part2 { - "../input_small2.txt" => 281; - "../input.txt" => 54019; - } + day1::main(); } diff --git a/2023/day2/Cargo.toml b/2023/day2/Cargo.toml index d489eaf..7238c2a 100644 --- a/2023/day2/Cargo.toml +++ b/2023/day2/Cargo.toml @@ -8,3 +8,8 @@ edition = "2021" [dependencies] nom.workspace = true helper.workspace = true +divan.workspace = true + +[[bench]] +name = "benches" +harness = false diff --git a/2023/day2/benches/benches.rs b/2023/day2/benches/benches.rs new file mode 100644 index 0000000..96855df --- /dev/null +++ b/2023/day2/benches/benches.rs @@ -0,0 +1,3 @@ +fn main() { + day2::bench(); +} diff --git a/2023/day2/src/lib.rs b/2023/day2/src/lib.rs new file mode 100644 index 0000000..f125185 --- /dev/null +++ b/2023/day2/src/lib.rs @@ -0,0 +1,113 @@ +use helper::Day; +use nom::{ + branch::alt, + bytes::complete::tag, + combinator::{all_consuming, map}, + multi::separated_list0, + sequence::{preceded, tuple}, + Finish, IResult, +}; + +pub fn main() { + helper::main::(include_str!("../input.txt")); +} + +struct Day2; + +helper::define_variants! { + day => crate::Day2; + part1 { + basic => crate::part1; + } + part2 { + basic => crate::part2; + } +} + +impl Day for Day2 { + fn part1() -> helper::Variants { + part1_variants!(construct_variants) + } + + fn part2() -> helper::Variants { + part2_variants!(construct_variants) + } +} + +#[derive(Debug, Clone, Copy)] +enum Color { + Red = 0, + Green = 1, + Blue = 2, +} + +fn parse_line(line: &str) -> (u64, Vec>) { + let parse_color = |i| -> IResult<&str, Color> { + alt(( + map(tag("blue"), |_| Color::Blue), + map(tag("red"), |_| Color::Red), + map(tag("green"), |_| Color::Green), + ))(i) + }; + let parse_cubes = tuple((helper::integer, preceded(tag(" "), parse_color))); + let parse_round = separated_list0(tag(", "), parse_cubes); + let parse_game = separated_list0(tag("; "), parse_round); + let parse_line = tuple(( + preceded(tag("Game "), helper::integer), + preceded(tag(": "), parse_game), + )); + + all_consuming(parse_line)(line).finish().unwrap().1 +} + +fn part1(input: &str) -> u64 { + const MAX: [u64; 3] = [12, 13, 14]; + + input + .lines() + .filter_map(|line| { + let line = parse_line(line); + for round in line.1 { + for (amount, color) in round { + if MAX[color as usize] < amount { + return None; + } + } + } + + Some(line.0) + }) + .sum() +} + +fn part2(input: &str) -> u64 { + input + .lines() + .map(|line| { + let line = parse_line(line); + let mut min = [0, 0, 0]; + for round in line.1 { + for (amount, color) in round { + min[color as usize] = min[color as usize].max(amount); + } + } + + let power = min[0] * min[1] * min[2]; + power + }) + .sum() +} + +helper::tests! { + day2 Day2; + part1 { + small => 8; + default => 1931; + } + part2 { + small => 2286; + default => 83105; + } +} + +helper::benchmarks! {} diff --git a/2023/day2/src/main.rs b/2023/day2/src/main.rs index 9345ff9..4192bc2 100644 --- a/2023/day2/src/main.rs +++ b/2023/day2/src/main.rs @@ -1,101 +1,3 @@ -use helper::{Day, Variants}; -use nom::{ - branch::alt, - bytes::complete::tag, - combinator::{all_consuming, map}, - multi::separated_list0, - sequence::{preceded, tuple}, - Finish, IResult, -}; - fn main() { - helper::main::(include_str!("../input.txt")); -} - -struct Day2; - -impl Day for Day2 { - fn part1() -> helper::Variants { - Variants::basic(part1) - } - - fn part2() -> helper::Variants { - Variants::basic(part2) - } -} - -#[derive(Debug, Clone, Copy)] -enum Color { - Red = 0, - Green = 1, - Blue = 2, -} - -fn parse_line(line: &str) -> (u64, Vec>) { - let parse_color = |i| -> IResult<&str, Color> { - alt(( - map(tag("blue"), |_| Color::Blue), - map(tag("red"), |_| Color::Red), - map(tag("green"), |_| Color::Green), - ))(i) - }; - let parse_cubes = tuple((helper::integer, preceded(tag(" "), parse_color))); - let parse_round = separated_list0(tag(", "), parse_cubes); - let parse_game = separated_list0(tag("; "), parse_round); - let parse_line = tuple(( - preceded(tag("Game "), helper::integer), - preceded(tag(": "), parse_game), - )); - - all_consuming(parse_line)(line).finish().unwrap().1 -} - -fn part1(input: &str) -> u64 { - const MAX: [u64; 3] = [12, 13, 14]; - - input - .lines() - .filter_map(|line| { - let line = parse_line(line); - for round in line.1 { - for (amount, color) in round { - if MAX[color as usize] < amount { - return None; - } - } - } - - Some(line.0) - }) - .sum() -} - -fn part2(input: &str) -> u64 { - input - .lines() - .map(|line| { - let line = parse_line(line); - let mut min = [0, 0, 0]; - for round in line.1 { - for (amount, color) in round { - min[color as usize] = min[color as usize].max(amount); - } - } - - let power = min[0] * min[1] * min[2]; - power - }) - .sum() -} - -helper::tests! { - day2 Day2; - part1 { - small => 8; - default => 1931; - } - part2 { - small => 2286; - default => 83105; - } + day2::main(); } diff --git a/2023/day3/Cargo.toml b/2023/day3/Cargo.toml index 97e23df..b7639d6 100644 --- a/2023/day3/Cargo.toml +++ b/2023/day3/Cargo.toml @@ -8,3 +8,8 @@ edition = "2021" [dependencies] nom.workspace = true helper.workspace = true +divan.workspace = true + +[[bench]] +name = "benches" +harness = false diff --git a/2023/day3/benches/benches.rs b/2023/day3/benches/benches.rs new file mode 100644 index 0000000..423f516 --- /dev/null +++ b/2023/day3/benches/benches.rs @@ -0,0 +1,3 @@ +fn main() { + day3::bench(); +} diff --git a/2023/day3/src/main.rs b/2023/day3/src/lib.rs similarity index 90% rename from 2023/day3/src/main.rs rename to 2023/day3/src/lib.rs index 4fc1a06..0938779 100644 --- a/2023/day3/src/main.rs +++ b/2023/day3/src/lib.rs @@ -1,20 +1,30 @@ use std::collections::HashMap; -use helper::{Day, Variants}; +use helper::Day; -fn main() { +pub fn main() { helper::main::(include_str!("../input.txt")); } struct Day3; +helper::define_variants! { + day => crate::Day3; + part1 { + basic => crate::part1; + } + part2 { + basic => crate::part2; + } +} + impl Day for Day3 { - fn part1() -> Variants { - Variants::basic(part1) + fn part1() -> helper::Variants { + part1_variants!(construct_variants) } - fn part2() -> Variants { - Variants::basic(part2) + fn part2() -> helper::Variants { + part2_variants!(construct_variants) } } @@ -128,3 +138,5 @@ helper::tests! { default => 81939900; } } + +helper::benchmarks! {} diff --git a/2023/day3/src/mainrs b/2023/day3/src/mainrs new file mode 100644 index 0000000..3b5b9bb --- /dev/null +++ b/2023/day3/src/mainrs @@ -0,0 +1,3 @@ +fn main() { + day3::main(); +} diff --git a/Cargo.lock b/Cargo.lock index 8f6605b..96d1c39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -47,9 +47,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "clap" version = "4.4.10" @@ -69,6 +75,7 @@ dependencies = [ "anstyle", "clap_lex", "strsim", + "terminal_size", ] [[package]] @@ -83,10 +90,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "condtype" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" + [[package]] name = "day1" version = "0.1.0" dependencies = [ + "divan", "helper", ] @@ -94,6 +108,7 @@ dependencies = [ name = "day2" version = "0.1.0" dependencies = [ + "divan", "helper", "nom", ] @@ -102,18 +117,65 @@ dependencies = [ name = "day3" version = "0.1.0" dependencies = [ + "divan", "helper", "nom", ] +[[package]] +name = "divan" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763cb39ba91195b15997d344ee282302799871b4ff5ddf4b6538ab1d2d1bb1a5" +dependencies = [ + "clap", + "condtype", + "divan-macros", + "regex-lite", +] + +[[package]] +name = "divan-macros" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de02c6e6def5706c2aca32c3e3261625000f8effc4d4c37f9d750262a6b9ca56" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "helper" version = "0.1.0" dependencies = [ "clap", + "divan", "nom", ] +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + [[package]] name = "memchr" version = "2.6.4" @@ -136,12 +198,76 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "proc-macro2" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex-lite" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" + +[[package]] +name = "rustix" +version = "0.38.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "utf8parse" version = "0.2.1" @@ -154,7 +280,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -163,13 +298,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -178,38 +328,80 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml index 57f5d6d..da5d22f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ debug = 1 [workspace.dependencies] helper = { path = "./helper" } nom = "7.1.3" +divan = "0.1.4" diff --git a/helper/Cargo.toml b/helper/Cargo.toml index 4615d6b..d3f0e56 100644 --- a/helper/Cargo.toml +++ b/helper/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] clap = { version = "4.4.10", features = ["string"] } +divan.workspace = true nom.workspace = true diff --git a/helper/src/lib.rs b/helper/src/lib.rs index 2620d7d..4a73d5e 100644 --- a/helper/src/lib.rs +++ b/helper/src/lib.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use nom::{character::complete::digit1, combinator::map, IResult}; pub use self::cmd::main; +pub use divan; pub type Solution = fn(&str) -> u64; @@ -65,6 +66,75 @@ pub fn test_part2(inputs: &[(&str, u64)]) { } } +#[macro_export] +macro_rules! define_variants { + ( + day => $day:ty; + part1 { + $( $name1:ident => $func1:expr; )* + } + part2 { + $( $name2:ident => $func2:expr; )* + } + ) => { + macro_rules! part1_variants { + ($macro:ident) => { + $crate::$macro! { $day; $( ($name1, $func1) ),* } + }; + } + macro_rules! part2_variants { + ($macro:ident) => { + $crate::$macro! { $day; $( ($name2, $func2) ),* } + }; + } + }; +} + +#[macro_export] +macro_rules! construct_variants { + ( $day:ty; $( ($name:ident, $func:expr) ),*) => { + $crate::Variants { + variants: vec![$( + $crate::Variant::new(stringify!($name), $func) + ),*] + } + }; +} + +#[macro_export] +macro_rules! benchmarks { + () => { + #[::divan::bench_group(sample_count = 1_000)] + mod bench { + mod part1 { + part1_variants! { _define_benchmarks } + } + mod part2 { + part2_variants! { _define_benchmarks } + } + } + + pub fn bench() { + divan::main(); + } + }; +} + +#[macro_export] +macro_rules! _define_benchmarks { + ($day:ty; $( ($name:ident, $func:expr) ),*) => { + $( + #[::divan::bench] + fn $name(bencher: ::divan::Bencher) { + let input = include_str!("../input.txt"); + let input = <$day as $crate::Day>::pad_input(input); + + bencher.with_inputs(|| input.as_ref()).bench_values($func); + } + )* + }; +} + #[macro_export] macro_rules! tests { (