crunchy-0.2.2/.gitignore010064400017500001750000000000361333427171000133770ustar0000000000000000target/ **/*.rs.bk Cargo.lock crunchy-0.2.2/Cargo.toml.orig010064400017500001750000000005651346424311000143020ustar0000000000000000[package] name = "crunchy" version = "0.2.2" authors = ["Vurich "] description = "Crunchy unroller: deterministically unroll constant loops" license = "MIT" build = "build.rs" [dependencies] [features] "std" = [] "limit_64" = [] "limit_128" = [] "limit_256" = [] "limit_512" = [] "limit_1024" = [] "limit_2048" = [] "default" = ["limit_128"] crunchy-0.2.2/Cargo.toml0000644000000015620000000000000105510ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "crunchy" version = "0.2.2" authors = ["Vurich "] build = "build.rs" description = "Crunchy unroller: deterministically unroll constant loops" license = "MIT" [dependencies] [features] default = ["limit_128"] limit_1024 = [] limit_128 = [] limit_2048 = [] limit_256 = [] limit_512 = [] limit_64 = [] std = [] crunchy-0.2.2/README.md010064400017500001750000000017511333427171000126730ustar0000000000000000# Crunchy The crunchy unroller - deterministically unroll constant loops. For number "crunching". The Rust optimizer will unroll constant loops that don't use the loop variable, like this: ```rust for _ in 0..100 { println!("Hello!"); } ``` However, using the loop variable will cause it to never unroll the loop. This is unfortunate because it means that you can't constant-fold the loop variable, and if you end up stomping on the registers it will have to do a load for each iteration. This crate ensures that your code is unrolled and const-folded. It only works on literals, unfortunately, but there's a work-around: ```rust debug_assert_eq!(MY_CONSTANT, 100); unroll! { for i in 0..100 { println!("Iteration {}", i); } } ``` This means that your tests will catch if you redefine the constant. To default maximum number of loops to unroll is `64`, but that can be easily increased using the cargo features: * `limit_128` * `limit_256` * `limit_512` * `limit_1024` * `limit_2048`crunchy-0.2.2/build.rs010064400017500001750000000147071346424310300130650ustar0000000000000000use std::env; use std::fs::File; use std::io::Write; use std::path::Path; const LOWER_LIMIT: usize = 16; fn main() { let limit = if cfg!(feature="limit_2048") { 2048 } else if cfg!(feature="limit_1024") { 1024 } else if cfg!(feature="limit_512") { 512 } else if cfg!(feature="limit_256") { 256 } else if cfg!(feature="limit_128") { 128 } else { 64 }; let out_dir = env::var("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("lib.rs"); let mut f = File::create(&dest_path).unwrap(); let mut output = String::new(); output.push_str(r#" /// Unroll the given for loop /// /// Example: /// /// ```ignore /// unroll! { /// for i in 0..5 { /// println!("Iteration {}", i); /// } /// } /// ``` /// /// will expand into: /// /// ```ignore /// { println!("Iteration {}", 0); } /// { println!("Iteration {}", 1); } /// { println!("Iteration {}", 2); } /// { println!("Iteration {}", 3); } /// { println!("Iteration {}", 4); } /// ``` #[macro_export] macro_rules! unroll { (for $v:ident in 0..0 $c:block) => {}; (for $v:ident < $max:tt in ($start:tt..$end:tt).step_by($val:expr) {$($c:tt)*}) => { { let step = $val; let start = $start; let end = start + ($end - start) / step; unroll! { for val < $max in start..end { let $v: usize = ((val - start) * step) + start; $($c)* } } } }; (for $v:ident in ($start:tt..$end:tt).step_by($val:expr) {$($c:tt)*}) => { unroll! { for $v < $end in ($start..$end).step_by($val) {$($c)*} } }; (for $v:ident in ($start:tt..$end:tt) {$($c:tt)*}) => { unroll!{ for $v in $start..$end {$($c)*} } }; (for $v:ident in $start:tt..$end:tt {$($c:tt)*}) => { #[allow(non_upper_case_globals)] #[allow(unused_comparisons)] { unroll!(@$v, 0, $end, { if $v >= $start {$($c)*} } ); } }; (for $v:ident < $max:tt in $start:tt..$end:tt $c:block) => { #[allow(non_upper_case_globals)] { let range = $start..$end; assert!( $max >= range.end, "`{}` out of range `{:?}`", stringify!($max), range, ); unroll!( @$v, 0, $max, { if $v >= range.start && $v < range.end { $c } } ); } }; (for $v:ident in 0..$end:tt {$($statement:tt)*}) => { #[allow(non_upper_case_globals)] { unroll!(@$v, 0, $end, {$($statement)*}); } }; "#); for i in 0..limit + 1 { output.push_str(format!(" (@$v:ident, $a:expr, {}, $c:block) => {{\n", i).as_str()); if i <= LOWER_LIMIT { output.push_str(format!(" {{ const $v: usize = $a; $c }}\n").as_str()); for a in 1..i { output.push_str(format!(" {{ const $v: usize = $a + {}; $c }}\n", a).as_str()); } } else { let half = i / 2; if i % 2 == 0 { output.push_str(format!(" unroll!(@$v, $a, {0}, $c);\n", half).as_str()); output.push_str(format!(" unroll!(@$v, $a + {0}, {0}, $c);\n", half).as_str()); } else { if half > 1 { output.push_str(format!(" unroll!(@$v, $a, {}, $c);\n", i - 1).as_str()) } output.push_str(format!(" {{ const $v: usize = $a + {}; $c }}\n", i - 1).as_str()); } } output.push_str(" };\n\n"); } output.push_str("}\n\n"); output.push_str(format!(r#" #[cfg(all(test, feature = "std"))] mod tests {{ #[test] fn invalid_range() {{ let mut a: Vec = vec![]; unroll! {{ for i in (5..4) {{ a.push(i); }} }} assert_eq!(a, vec![]); }} #[test] fn start_at_one_with_step() {{ let mut a: Vec = vec![]; unroll! {{ for i in (2..4).step_by(1) {{ a.push(i); }} }} assert_eq!(a, vec![2, 3]); }} #[test] fn start_at_one() {{ let mut a: Vec = vec![]; unroll! {{ for i in 1..4 {{ a.push(i); }} }} assert_eq!(a, vec![1, 2, 3]); }} #[test] fn test_all() {{ {{ let a: Vec = vec![]; unroll! {{ for i in 0..0 {{ a.push(i); }} }} assert_eq!(a, (0..0).collect::>()); }} {{ let mut a: Vec = vec![]; unroll! {{ for i in 0..1 {{ a.push(i); }} }} assert_eq!(a, (0..1).collect::>()); }} {{ let mut a: Vec = vec![]; unroll! {{ for i in 0..{0} {{ a.push(i); }} }} assert_eq!(a, (0..{0}).collect::>()); }} {{ let mut a: Vec = vec![]; let start = {0} / 4; let end = start * 3; unroll! {{ for i < {0} in start..end {{ a.push(i); }} }} assert_eq!(a, (start..end).collect::>()); }} {{ let mut a: Vec = vec![]; unroll! {{ for i in (0..{0}).step_by(2) {{ a.push(i); }} }} assert_eq!(a, (0..{0} / 2).map(|x| x * 2).collect::>()); }} {{ let mut a: Vec = vec![]; let start = {0} / 4; let end = start * 3; unroll! {{ for i < {0} in (start..end).step_by(2) {{ a.push(i); }} }} assert_eq!(a, (start..end).filter(|x| x % 2 == 0).collect::>()); }} }} }} "#, limit).as_str()); f.write_all(output.as_bytes()).unwrap(); } crunchy-0.2.2/src/lib.rs010064400017500001750000000023021333427171000133100ustar0000000000000000//! The crunchy unroller - deterministically unroll constant loops. For number "crunching". //! //! The Rust optimizer will unroll constant loops that don't use the loop variable, like this: //! //! ```ignore //! for _ in 0..100 { //! println!("Hello!"); //! } //! ``` //! //! However, using the loop variable will cause it to never unroll the loop. This is unfortunate because it means that you can't //! constant-fold the loop variable, and if you end up stomping on the registers it will have to do a load for each iteration. //! This crate ensures that your code is unrolled and const-folded. It only works on literals, //! unfortunately, but there's a work-around: //! //! ```ignore //! debug_assert_eq!(MY_CONSTANT, 100); //! unroll! { //! for i in 0..100 { //! println!("Iteration {}", i); //! } //! } //! ``` //! This means that your tests will catch if you redefine the constant. //! //! To default maximum number of loops to unroll is `64`, but that can be easily increased using the cargo features: //! //! * `limit_128` //! * `limit_256` //! * `limit_512` //! * `limit_1024` //! * `limit_2048` #![cfg_attr(not(feature = "std"), no_std)] include!(concat!(env!("OUT_DIR"), "/lib.rs")); crunchy-0.2.2/.cargo_vcs_info.json0000644000000001120000000000000125410ustar00{ "git": { "sha1": "1bf90cf2d0a8cfcb2c5592275a23ab028dff6468" } }