N-wymiarowy widok na macierz w C++

Jakiś czas temu napisałem prosty widok na macierz. Postanowiłem go trochę rozszerzyć i napisać przekombinowany widok na macierz n-wymiarową. Kodu jest trochę więcej niż poprzednio, więc nie zamieszczę całości w treści posta (jest dostępny tutaj), ale tylko zamieszczę efekty.

Użycie

Zaczynając od przykładowego kodu z poprzedniego posta:

vector<double> data{1,2,3,4,5,6,7,8,9,10,11,12};
 
simple_2d_matrix_view<double> m(data.data(), 2, 6);
 
for(size_t i = 0; i < m.height(); ++i) {
	for(size_t j = 0; j < m.width(); ++j) {
		cout << m(i, j) << " ";
	}
	cout << "\n";
}

Po minimalnej modyfikacji:

vector<double> data{1,2,3,4,5,6,7,8,9,10,11,12};
 
kq::matrix_2d_view<double> m(data.data(), 2, 6);
 
for(size_t y = 0; y < m.height(); ++y) {
    for(size_t x = 0; x < m.width(); ++x) {
        cout << m(y, x) << " ";
    }
    cout << "\n";
}

Wyjście:

1 2
3 4
5 6
7 8
9 10
11 12

Przy czym, po dodaniu obsługi iteratorów, można to zapisać ładniej:

for(auto const& row : m) {
    for(auto const& val : row) {
        cout << val << " ";
    }
    cout << '\n';
}

lub:

for(auto const& row : m) {
    copy(row.begin(), row.end(), ostream_iterator<double>(cout, " "));
    cout << '\n';
}

Wyjście pozostanie bez zmian.

Wydajność

gcc i clang optymalizują całą abstrakcję do zera. Link do compiler explorera.

template<typename T>
void sink(T);
 
void foo()
{
    std::array<int, 12> arr{1,2,3,4,5,6,7,8,9,10,11,12};
    kq::matrix_view<const int, 2> v{arr.data(), 3, 4};
    for(auto const& row : v)
        for(auto elem : row)
            sink(elem);
}

Kompiluje się do:

foo():                                # @foo()
        push    rax
        mov     edi, 1
        call    void sink<int>(int)
        mov     edi, 2
        call    void sink<int>(int)
        mov     edi, 3
        call    void sink<int>(int)
        mov     edi, 4
        call    void sink<int>(int)
        mov     edi, 5
        call    void sink<int>(int)
        mov     edi, 6
        call    void sink<int>(int)
        mov     edi, 7
        call    void sink<int>(int)
        mov     edi, 8
        call    void sink<int>(int)
        mov     edi, 9
        call    void sink<int>(int)
        mov     edi, 10
        call    void sink<int>(int)
        mov     edi, 11
        call    void sink<int>(int)
        mov     edi, 12
        call    void sink<int>(int)
        pop     rax
        ret

Leave a Reply

Your email address will not be published.