From b6debb11595213baab82e9aa0d1658feae2cbdc7 Mon Sep 17 00:00:00 2001 From: SOFe Date: Sun, 1 Dec 2024 18:40:51 +0800 Subject: [PATCH] add more implementations of d1 --- Cargo.lock | 515 +++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 12 ++ benches/main.rs | 4 + src/all.rs | 195 +++++++++++++++++ src/all/d1.jq | 10 + src/{ => all}/d1.rs | 60 +++++- src/lib.rs | 4 + src/main.rs | 111 +--------- 8 files changed, 790 insertions(+), 121 deletions(-) create mode 100644 benches/main.rs create mode 100644 src/all.rs create mode 100644 src/all/d1.jq rename src/{ => all}/d1.rs (55%) create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 21fe385..18bf130 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,39 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "0.6.18" @@ -77,8 +110,13 @@ name = "aoc2024" version = "0.1.0" dependencies = [ "anyhow", + "bitvec", "clap", + "criterion", + "jq-rs", + "paste", "reqwest", + "simd-json", ] [[package]] @@ -93,6 +131,15 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "autotools" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941527c41b0fc0dd48511a8154cd5fc7e29200a0ff8b7203c5d777dbc795cf" +dependencies = [ + "cc", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -120,6 +167,18 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -132,6 +191,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.2" @@ -147,6 +212,33 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.5.21" @@ -209,6 +301,73 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "displaydoc" version = "0.2.5" @@ -220,6 +379,12 @@ dependencies = [ "syn", ] +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -251,6 +416,15 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -281,6 +455,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures-channel" version = "0.3.31" @@ -338,8 +518,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -367,6 +549,36 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "halfbrown" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8588661a8607108a5ca69cab034063441a0413a0b041c13618a7dd348021ef6f" +dependencies = [ + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -379,6 +591,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "http" version = "1.1.0" @@ -637,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -646,18 +864,65 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jq-rs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9cfaeae42ef96b227ab787558cc7bbd5f1dfe96b4df7c63f92853017751b0e4" +dependencies = [ + "jq-sys", +] + +[[package]] +name = "jq-src" +version = "0.4.1" +source = "git+https://github.com/SOF3/jq-src?rev=refs/tags/jq-1.7.1#5174594962520e1f2c956408a419f68b85af621a" +dependencies = [ + "autotools", +] + +[[package]] +name = "jq-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b65b7e54bd2fffc8cb20cbcf19f40d3158dab5cf5b5adb1f65f9b35eba4c48" +dependencies = [ + "jq-src", + "pkg-config", +] + [[package]] name = "js-sys" version = "0.3.74" @@ -741,6 +1006,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.5" @@ -756,6 +1030,12 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + [[package]] name = "openssl" version = "0.10.68" @@ -800,6 +1080,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -824,11 +1110,39 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -842,6 +1156,81 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "reqwest" version = "0.12.9" @@ -965,6 +1354,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.27" @@ -1047,6 +1445,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-json" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2bcf6c6e164e81bc7a5d49fc6988b3d515d9e8c07457d7b74ffb9324b9cd40" +dependencies = [ + "getrandom", + "halfbrown", + "ref-cast", + "serde", + "serde_json", + "simdutf8", + "value-trait", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "slab" version = "0.4.9" @@ -1098,9 +1517,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -1148,6 +1567,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.14.0" @@ -1171,6 +1596,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tokio" version = "1.41.1" @@ -1253,9 +1688,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "untrusted" @@ -1292,12 +1727,40 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "value-trait" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9170e001f458781e92711d2ad666110f153e4e50bfd5cbd02db6547625714187" +dependencies = [ + "float-cmp", + "halfbrown", + "itoa", + "ryu", +] + [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1391,6 +1854,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "windows-registry" version = "0.2.0" @@ -1515,6 +1987,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "yoke" version = "0.7.5" @@ -1539,6 +2020,26 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerofrom" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 8b3c4b6..f6eb759 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,17 @@ edition = "2021" [dependencies] anyhow = "1.0.93" +bitvec = "1.0.1" clap = { version = "4.5.21", features = ["derive"] } +criterion = "0.5.1" +jq-rs = { version = "0.4.1", features = ["bundled"] } +paste = "1.0.15" reqwest = { version = "0.12.9", features = ["blocking"] } +simd-json = "0.14.3" + +[patch.crates-io] +jq-src = { git = "https://github.com/SOF3/jq-src", rev = "refs/tags/jq-1.7.1" } + +[[bench]] +name = "main" +harness = false diff --git a/benches/main.rs b/benches/main.rs new file mode 100644 index 0000000..22407cd --- /dev/null +++ b/benches/main.rs @@ -0,0 +1,4 @@ +use criterion::*; + +criterion_group!(benches, aoc2024::bench); +criterion_main!(benches); diff --git a/src/all.rs b/src/all.rs new file mode 100644 index 0000000..8586802 --- /dev/null +++ b/src/all.rs @@ -0,0 +1,195 @@ +use std::path::PathBuf; +use std::time::Instant; +use std::{env, fmt, fs, io}; + +use anyhow::Context; +use clap::{Parser, ValueEnum}; +use criterion::{BatchSize, Criterion, Bencher}; + +macro_rules! main { + ( + $(day $day:literal { + $(part $part:literal $impls:tt)* + })* + ) => { + $( + paste::paste! { + mod []; + } + )* + + pub fn run(args: Args) -> anyhow::Result<()> { + let variant = args.variant.as_str(); + match args.day { + $( + $day => match args.part { + $( + $part => { + let input = load_input(args.mode, $day)?; + + let output = main!(@impl variant, &input, $impls); + + println!("{output}"); + + Ok(()) + }, + )* + _ => anyhow::bail!("Unimplemented part"), + }, + )* + _ => anyhow::bail!("Unimplemented day"), + } + } + + pub fn bench(c: &mut Criterion) { + fn try_unwrap(f: impl FnOnce() -> Result) -> R { + f().unwrap() + } + + $($( + { + let mut group = c.benchmark_group(concat!("Day ", $day, " Part ", $part)); + main!(@bench group, $day, $impls); + group.finish(); + } + )*)* + } + }; + (@impl $variant:ident, $input:expr, { + $($name:literal => $fn:expr,)* + }) => { + match $variant { + $($name => call($fn, $input),)* + _ => anyhow::bail!("Unknown variant implementation"), + } + }; + (@bench $group:ident, $day:literal, { + $($name:literal => $fn:expr,)* + }) => { + $( + { + let mut f = try_unwrap(move || anyhow::Ok($fn)); + $group.bench_function($name, move |b| { + call_benched(b, $day, &mut f); + }); + } + )* + }; +} + +macro_rules! jq { + ($file:literal, $function:literal) => {{ + let mut program = + jq_rs::compile(concat!(include_str!(concat!("all/", $file)), "\n", $function)) + .map_err(|err| anyhow::anyhow!("compile {}: {err}", $file))?; + move |data: JsonString| -> String { + let output = program.run(data.0.as_str()).expect("jq program error"); + output + } + }}; +} + +fn call(mut f: impl FnMut(In) -> Out, input: &str) -> String { + let start_time = Instant::now(); + let parsed = Parse::parse(input); + let duration = Instant::now() - start_time; + eprintln!("Parse time: {}ms", duration.as_secs_f32() * 1000.); + + let start_time = Instant::now(); + let output = f(parsed); + let duration = Instant::now() - start_time; + eprintln!("Execution time: {}ms", duration.as_secs_f32() * 1000.); + + output.to_string() +} + +fn call_benched(b: &mut Bencher, day: u32, f: impl FnMut(In) -> Out) { + let input = load_input(Mode::Private, day).unwrap(); + let parsed: In = Parse::parse(&input); + b.iter_batched( + || parsed.clone(), + f, + BatchSize::LargeInput, + ); +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +enum Mode { + Sample, + Private, +} + +#[derive(Parser)] +pub struct Args { + mode: Mode, + day: u32, + part: u32, + #[clap(default_value = "")] + variant: String, +} + +main! { + day 1 { + part 1 { + "zip" => d1::p1_zip, + "jq" => jq!("d1.jq", "d1q1"), + } + part 2 { + "hash" => d1::p2_hash, + "sorted" => d1::p2_sorted, + "count" => d1::p2_count, + "bitvec" => d1::p2_bitvec, + } + } +} + +fn load_input(mode: Mode, day: u32) -> anyhow::Result { + let dir = env::var("CARGO_MANIFEST_DIR").context("need cargo run")?; + let path = PathBuf::from(dir).join("input").join(format!( + "d{day}.{}.input.txt", + match mode { + Mode::Sample => "sample", + Mode::Private => "private", + } + )); + + if let Mode::Private = mode { + let exists = + fs::exists(&path).with_context(|| format!("test {} existence", path.display()))?; + if !exists { + eprintln!("Downloading day {day} input"); + + let session_cookie = env::var("AOC_SESSION") + .context("private file missing and AOC_SESSION env var missing")?; + + let client = reqwest::blocking::Client::new(); + let data = client + .get(format!("https://adventofcode.com/2024/day/{day}/input")) + .header("Cookie", format!("session={session_cookie}")) + .send() + .context("request aoc private input")?; + let input = io::read_to_string(data).context("read aoc private input")?; + fs::write(&path, &input).context("write aoc private input to cache")?; + } + } + + fs::read_to_string(&path).with_context(|| format!("read file {}", path.display())) +} + +pub trait Parse: Clone { + fn parse(input: &str) -> Self; +} + +impl Parse for String { + fn parse(input: &str) -> Self { input.to_string() } +} + +#[derive(Clone)] +struct JsonString(String); + +impl Parse for JsonString { + fn parse(input: &str) -> Self { + let value = simd_json::json!(input); + Self(simd_json::to_string(&value).unwrap()) + } +} diff --git a/src/all/d1.jq b/src/all/d1.jq new file mode 100644 index 0000000..2b0658a --- /dev/null +++ b/src/all/d1.jq @@ -0,0 +1,10 @@ +def d1q1: + split("\n") | + map( + split(" ") | + map(tonumber?) | + select(length == 2) | + .[0] - .[1] | abs + ) | + add +; diff --git a/src/d1.rs b/src/all/d1.rs similarity index 55% rename from src/d1.rs rename to src/all/d1.rs index a6a6a64..5e57293 100644 --- a/src/d1.rs +++ b/src/all/d1.rs @@ -1,11 +1,16 @@ -use std::{fmt, iter}; +use std::{collections::HashMap, fmt, iter}; -struct Input { +use bitvec::vec::BitVec; + +use crate::Parse; + +#[derive(Clone)] +pub struct Input { left: Vec, right: Vec, } -impl Input { +impl Parse for Input { fn parse(input: &str) -> Self { let (left, right): (Vec<_>, Vec<_>) = input .lines() @@ -19,9 +24,7 @@ impl Input { } } -pub fn p1(input: &str) -> impl fmt::Display { - let Input { mut left, mut right } = Input::parse(input); - +pub fn p1_zip(Input { mut left, mut right }: Input) -> impl fmt::Display { left.sort_unstable(); right.sort_unstable(); @@ -65,9 +68,16 @@ fn unique(iter: impl IntoIterator) -> impl Iterator impl fmt::Display { - let Input { mut left, mut right } = Input::parse(input); +pub fn p2_hash(Input { left, right }: Input) -> impl fmt::Display { + let mut counts = HashMap::::new(); + for item in right { + *counts.entry(item).or_default() += 1; + } + + left.into_iter().map(|item| item * counts.get(&item).copied().unwrap_or_default()).sum::() +} +pub fn p2_sorted(Input { mut left, mut right }: Input) -> impl fmt::Display { left.sort_unstable(); right.sort_unstable(); @@ -93,3 +103,37 @@ pub fn p2_sorted(input: &str) -> impl fmt::Display { output } + +pub fn p2_count(Input { left, right }: Input) -> impl fmt::Display { + fn collect_buckets(items: Vec) -> Vec { + let mut output = vec![0u32; 100000]; + for item in items { + output[item as usize] += 1; + } + output + } + + let left = collect_buckets(left); + let right = collect_buckets(right); + + iter::zip(left, right).enumerate().map(|(i, (l, r))| (i as u32) * l * r).sum::() +} + +pub fn p2_bitvec(Input { left, right }: Input) -> impl fmt::Display { + fn collect_buckets(items: Vec) -> (BitVec, Vec) { + let mut presence: BitVec = iter::repeat(false).take(100000).collect(); + let mut output = vec![0u32; 100000]; + for item in items { + presence.set(item as usize, true); + output[item as usize] += 1; + } + (presence, output) + } + + let (left_presence, left) = collect_buckets(left); + let (right_presence, right) = collect_buckets(right); + + let presence = left_presence & right_presence; + + presence.iter_ones().map(|i| left[i] * right[i] * (i as u32)).sum::() +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d3887b2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,4 @@ +mod all; +pub use all::bench; +pub use all::run; +use all::Parse; diff --git a/src/main.rs b/src/main.rs index 8023eb0..ee35cd4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,111 +1,10 @@ -use std::path::PathBuf; -use std::time::Instant; -use std::{env, fmt, fs, io}; +use clap::Parser; -use anyhow::Context; -use clap::{Parser, ValueEnum}; - -mod d1; - -macro_rules! main { - ( - $args:ident; - $(day $day:literal part $part:literal: $impls:tt;)* - ) => { - let variant = $args.variant.as_str(); - match ($args.day, $args.part) { - $( - ($day, $part) => { - let input = load_input($args.mode, $day)?; - - let start_time = Instant::now(); - let output = main!(@impl variant, &input, $impls); - let end_time = Instant::now(); - eprintln!("Execution time: {}ns", (end_time - start_time).as_nanos()); - - println!("{output}"); - } - )* - _ => anyhow::bail!("Unimplemented day/part"), - } - }; - (@impl $variant:ident, $input:expr, { - _ => $path:path, - }) => { - call($path, $input) - }; - (@impl $variant:ident, $input:expr, { - $($name:literal => $path:path,)* - }) => { - match $variant { - $($name => call($path, $input),)* - _ => anyhow::bail!("Unknown variant implementation"), - } - }; -} - -fn call(f: impl Fn(&str) -> Out, input: &str) -> Out { f(input) } - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -enum Mode { - Sample, - Private, -} +mod all; +use all::Parse; fn main() -> anyhow::Result<()> { - #[derive(Parser)] - struct Args { - mode: Mode, - day: u32, - part: u32, - #[clap(default_value = "")] - variant: String, - } - - let args = Args::parse(); - - main! { - args; - day 1 part 1: { - _ => d1::p1, - }; - day 1 part 2: { - "sorted" => d1::p2_sorted, - }; - } - - Ok(()) -} - -fn load_input(mode: Mode, day: u32) -> anyhow::Result { - let dir = env::var("CARGO_MANIFEST_DIR").context("need cargo run")?; - let path = PathBuf::from(dir).join("input").join(format!( - "d{day}.{}.input.txt", - match mode { - Mode::Sample => "sample", - Mode::Private => "private", - } - )); - - if let Mode::Private = mode { - let exists = - fs::exists(&path).with_context(|| format!("test {} existence", path.display()))?; - if !exists { - eprintln!("Downloading day {day} input"); - - let session_cookie = env::var("AOC_SESSION") - .context("private file missing and AOC_SESSION env var missing")?; - - let client = reqwest::blocking::Client::new(); - let data = client - .get(format!("https://adventofcode.com/2024/day/{day}/input")) - .header("Cookie", format!("session={session_cookie}")) - .send() - .context("request aoc private input")?; - let input = io::read_to_string(data).context("read aoc private input")?; - fs::write(&path, &input).context("write aoc private input to cache")?; - } - } + let args = all::Args::parse(); - fs::read_to_string(&path).with_context(|| format!("read file {}", path.display())) + all::run(args) }