Home > OS >  Arithmetic inferral conditions/constraints for const generic arraysize
Arithmetic inferral conditions/constraints for const generic arraysize

Time:04-26

I have this function splitting up a vector into two vectors of the odd and even elements:

pub fn odd_even<T>(x: Vec<T>, upto: usize) -> (Vec<T>, Vec<T>)
where T: Copy
{
    let mut odd = Vec::new();
    let mut even = Vec::new();
    let oddeven: [&mut Vec<T>; 2] = [&mut odd, &mut even];
    for n in 0..upto
    {
        oddeven[n%2].push(x[n]);
    }
    return (odd, even);
}

This works fine and works with dynamically sized vectors.

However, i'm considering using const generic length arrays for this. The following code generates compiler errors for the constraints (or whatever you call it?) for LEN_ODD and LEN_EVEN, because LEN is a constant, but it should communicate the idea. I'm not even sure if the language allows me to do this kind of stuff, but i'd like to know if it's possible.

Is there a way to say that LEN_ODD and LEN_EVEN must be of a certain value in correspondance to LEN, so that the values for these two constants can be inferred automatically by the compiler? Maybe it's a dumb idea, but i would like to try. The code will be used for an implementation of the fast fourier transform, where performance is cruical. Maybe macros would be a better way to implement this?

fn odd_even<T, const LEN: usize, const LEN_ODD: usize, const LEN_EVEN: usize>
(x: [T; LEN]) -> ([T; LEN_ODD], [T; LEN_EVEN])
where
T: Default, T: Copy,
LEN_ODD == LEN << 1, // this line is invalid
LEN_EVEN == (LEN   1) << 1 // this line is also invalid
{
    let mut odd: [T; LEN_ODD] = [Default::default(); LEN_ODD];
    let mut even: [T; LEN_EVEN] = [Default::default(); LEN_EVEN];

    let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
    for n in 0..LEN
    {
        oddeven[n%2][n << 1] = x[n];
    }
    return (odd, even);
}

I'm new to rust, and don't have much experience with languages that use pointers explicitly. There may be a solution there that i have completely missed just referencing the first element of the arrays, however then the length of the arrays would not be constrained by the compiler, which could easily get confusing. At that point you might as well use vectors, right?

Using assertions, the compiler will still not inferr LEN_ODD and LEN_EVEN:

fn odd_even<T, const LEN: usize, const LEN_ODD: usize, const LEN_EVEN: usize>
(x: [T; LEN]) -> ([T; LEN_ODD], [T; LEN_EVEN])
where
T: Default, T: Copy
{
    assert_eq!(LEN_ODD, LEN << 1);
    assert_eq!(LEN_EVEN, (LEN   1) << 1);

    let mut odd: [T; LEN_ODD] = [Default::default(); LEN_ODD];
    let mut even: [T; LEN_EVEN] = [Default::default(); LEN_EVEN];

    let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
    for n in 0..LEN
    {
        oddeven[n%2][n << 1] = x[n];
    }
    return (odd, even);
}

The final function above can successfully be called as such:

odd_even::<usize, 4, 2, 2>([0, 2, 3, 5]); // -> [2, 5], [0, 3]

However the lengths must be specified, and will not be inferred. What i'm looking for is a way to tell the compiler how to inferr them.

CodePudding user response:

Doing arithmetic on const generics requires the generic_const_exprs feature. Here's a working implementation of your code with the feature enabled:

#![feature(generic_const_exprs)]
#![allow(incomplete_features)]

fn main() {
    let _: ([u32; 2], [u32; 2]) = dbg!(odd_even([0, 2, 3, 5]));
    let _: ([u32; 2], [u32; 3]) = dbg!(odd_even([0, 2, 3, 5, 6]));
}

fn odd_even<T, const LEN: usize>(x: [T; LEN]) -> ([T; LEN / 2], [T; (LEN   1) / 2])
where
    T: Default,
    T: Copy,
{
    let mut odd = [Default::default(); LEN / 2];
    let mut even = [Default::default(); (LEN   1) / 2];

    let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];

    for n in 0..LEN {
        oddeven[1 - n % 2][n / 2] = x[n];
    }

    return (odd, even);
}

Output:

[src/main.rs:5] odd_even([0, 2, 3, 5]) = (
    [
        2,
        5,
    ],
    [
        0,
        3,
    ],
)
[src/main.rs:6] odd_even([0, 2, 3, 5, 6]) = (
    [
        2,
        5,
    ],
    [
        0,
        3,
        6,
    ],
)

Playground

  • Related