Можно ли написать макрос ржавчины, который транспонирует матрицу? - PullRequest
0 голосов
/ 16 апреля 2020

В настоящее время я работаю над оптимизацией корзины jpeg декодера ржавчины с использованием SIMD. Чтобы избежать длинных повторений в коде, я хотел бы написать макрос, который генерирует следующий код транспонирования матрицы:

s = [
        i32x8::new(s[0].extract(0),s[1].extract(0),s[2].extract(0),s[3].extract(0),s[4].extract(0),s[5].extract(0),s[6].extract(0),s[7].extract(0), ),
        i32x8::new(s[0].extract(1),s[1].extract(1),s[2].extract(1),s[3].extract(1),s[4].extract(1),s[5].extract(1),s[6].extract(1),s[7].extract(1), ),
        i32x8::new(s[0].extract(2),s[1].extract(2),s[2].extract(2),s[3].extract(2),s[4].extract(2),s[5].extract(2),s[6].extract(2),s[7].extract(2), ),
        i32x8::new(s[0].extract(3),s[1].extract(3),s[2].extract(3),s[3].extract(3),s[4].extract(3),s[5].extract(3),s[6].extract(3),s[7].extract(3), ),
        i32x8::new(s[0].extract(4),s[1].extract(4),s[2].extract(4),s[3].extract(4),s[4].extract(4),s[5].extract(4),s[6].extract(4),s[7].extract(4), ),
        i32x8::new(s[0].extract(5),s[1].extract(5),s[2].extract(5),s[3].extract(5),s[4].extract(5),s[5].extract(5),s[6].extract(5),s[7].extract(5), ),
        i32x8::new(s[0].extract(6),s[1].extract(6),s[2].extract(6),s[3].extract(6),s[4].extract(6),s[5].extract(6),s[6].extract(6),s[7].extract(6), ),
        i32x8::new(s[0].extract(7),s[1].extract(7),s[2].extract(7),s[3].extract(7),s[4].extract(7),s[5].extract(7),s[6].extract(7),s[7].extract(7), ),
];

Макрос должен иметь возможность генерировать код для матрицы разных размеров (4 или 8).

Я пробовал несколько разных подходов, но мне так и не удалось заставить макрос повторить n раз шаблон из n элементов.

Самым логичным для меня было бы:

macro_rules! square {
    (($($x:tt),*), ($($y:tt),*)) => {
        [
            $([ 
                $( s[$x].extract($y) ),* 
            ]),*
        ]
    };
    ($($x:expr),*) => { square!( ($($x),*) , ($($x),*) ) };
}

, но с ошибкой

error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth

1 Ответ

1 голос
/ 16 апреля 2020

Вы можете сделать это, но вам нужно будет обработать внешнее повторение посредством рекурсии:

macro_rules! square {
    (@row [$($acc:expr),*] [$($before:expr),*] $current:expr $(, $after:expr)*) => {
        square!(@row
            [ $($acc,)*
              stringify!($(s[$current].extract ($before),)*
                         s[$current].extract ($current)
                         $(, s[$current].extract ($after))*) ]
            [ $($before,)* $current ]
            $($after),*)
    };
    (@row [$($acc:tt)*] [$($before:expr),*]) => { vec![ $($acc)* ] };
    ($($r:expr),*) => {
        square!(@row [] [] $($r),*)
    };
}

Детская площадка

Я назвал stringify! так что код будет компилироваться на площадке без зависимостей. Вам нужно будет заменить их в соответствии с вашими потребностями (возможно, просто удалите вызов stringify! и замените s на идентификатор, передаваемый макросу).

Идея накопления значений в $acc и вывод их всех сразу в конце рекурсии называется шаблоном накопления pu sh вниз . Если вы не знакомы с этой концепцией, она подробно описана в небольшой книге макросов Rust .

...