2

I have a two-dimensional native C array which was read as shorts, and I wish to map a boost::multi_array_ref onto part of it, but express this as floats. Is there a way to set the stride in bytes (rather than multiples of the data size)?

hochl
  • 12,524
  • 10
  • 53
  • 87
DAmann
  • 174
  • 7
  • 1
    What do you want to achieve? Type punning like that is undefined behaviour unless you employ unions and adhere to the laws governing them. I suppose you really want to just convert the data from short to floats? – sehe May 01 '12 at 20:48
  • Indeed - the data is stored on disk as shorts, but we are deprecating that and operating on floats, so we have a conversion from short to float. The data is not even homogenous, and it would have been nice to start with a byte array, then create a reference to part of it as a view ref of floats, and another part as a view ref of shorts. – DAmann May 10 '12 at 20:12

1 Answers1

0

It is really too much to ask for an array library to support strides in bytes. Even if the alignment problems are somehow solved, there are still a lot of problems with manipulating subviews and pointer arithmetic.

If you really need to manipulate byte strides, I recommend having an array of chars (or std::byte) and only leaving the reinterpretation of the bytes for the end.

This can be done with Boost.MultiArray, but it is easier if you use a library that does the reinterpret dirty work for you. For example Multi

#include <multi/array.hpp>  // from https://gitlab.com/correaa/boost-multi/-/blob/master/test/element_transformed.cpp

namespace multi = boost::multi;

int main() { 

    auto n = 4, m = 3;

    std::vector<float> fake_data(n*m);
    fake_data[0] = 1.0F;
    fake_data[1] = 2.0F;

    auto custom_stride = sizeof(float);  // can be different for disk-encoded data

    multi::array_ref<char, 2> A({n, m*custom_stride}, reinterpret_cast<char*>(fake_data.data()));

    auto const& B = A.rotated().strided(custom_stride).unrotated();  // create a strided by on CHAR!

    auto [Bn, Bm] = sizes(B);
    assert( Bn == 4 and Bm == 3 );

    {  // you can do this with any library. Boost.MultiArray for example
        assert(  reinterpret_cast<float const&>(B[0][1]) ==  fake_data[1]  );

        assert( &reinterpret_cast<float const&>(B[0][1]) == &fake_data[1]  );
    }
    {  // with this library you can make it a bit more automatic
        auto const& C = B.element_transformed([](auto const& c) -> decltype(auto) {return reinterpret_cast<float const&>(c);});
    
        auto [Cn, Cm] = sizes(C);
        assert( Cn == 4 and Cm == 3 );

        assert(  C[0][1] ==  fake_data[1]  );

        assert( &C[0][1] == &fake_data[1]  );
    }
}

https://godbolt.org/z/hnjxor19T

alfC
  • 14,261
  • 4
  • 67
  • 118