Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I create a macro that unrolls loops?

Tags:

macros

rust

I'm trying to write some fast matrix code in Rust and to do this needs to ensure that loops are unrolled. Is there a way to create a compile-time for-loop? E.g: I want

unroll_loop!(f, a, 3);

to generate

f(a, 0);
f(a, 1);
f(a, 2);
like image 359
yong Avatar asked Jun 17 '15 09:06

yong


1 Answers

Well, sort of.

macro_rules! unroll {
    (0, |$i:ident| $s:stmt) => {};
    (1, |$i:ident| $s:stmt) => {{ let $i: usize = 0; $s; }};
    (2, |$i:ident| $s:stmt) => {{ unroll!(1, |$i| $s); let $i: usize = 1; $s; }};
    (3, |$i:ident| $s:stmt) => {{ unroll!(2, |$i| $s); let $i: usize = 2; $s; }};
    (4, |$i:ident| $s:stmt) => {{ unroll!(3, |$i| $s); let $i: usize = 3; $s; }};
    // ...
}

fn main() {
    unroll!(3, |i| println!("i: {}", i));
}

You might be tempted to ask "why don't you just use unroll!($i-1, |$i| $s) for the recursive case?". This is because macros cannot do math. In fact, they cannot do any form of evaluation whatsoever. You are basically limited to symbolic manipulation.

Macros also cannot interact with types or values in any way, which means the following does not work, and cannot be made to work:

const N: usize = 3;
unroll!(N, |i| println!("i: {}", i));

So, you can do this, but only for literal integers, and you have to write an explicit case in the macro for every integer to want to be able to use.

like image 114
DK. Avatar answered Nov 15 '22 21:11

DK.