copy a view with non-trivial strides along with its underlying container
I have a need to copy a view along with its underlying container. Could someone show me the right way to do it?
My current code doesn't propagate the strides info to the view expression. The code crashed when I printed the new view out.
template <class T, class... S>
auto copy_view_to_new_container(const xt::xview<T, S...>& view) {
const auto& container = view.expression();
auto new_container = xt::eval(container);
auto slices = view.slices();
auto new_view = xt::view(new_container, std::get<S>(slices)...);
return std::make_pair(std::move(new_container), std::move(new_view));
}
TEST(gpu_proxy, dtype_float_view1) {
xt::xarray<double> array = xt::arange<double>(100).reshape({10, 10});
auto view = xt::view(array, xt::range(2, 8), xt::range(3, 7));
auto [new_container, new_view] = copy_view_to_new_container(view);
std::cout << new_container << "\n";
std::cout << new_view << "\n"; // core dump here.
}
The above code crashed at xview.hpp at the function of compute_strides_impl(). When I printed out xview's m_e, I noticed that m_strides and m_backstrides are not properly initialized. It seems to be the case that the view does not have trivial_strides, so the initialization of m_strides are skipped in xview constructor.
static static_layout = xt::layout_type::row_major}, <xt::xaccessible<xt::xarray_container<xt::uvector<double, std::allocator<double> >, (xt::layout_type)1, xt::svector<unsigned long, 4ul, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag> >> = {<xt::xconst_accessible<xt::xarray_container<xt::uvector<double, std::allocator<double> >, (xt::layout_type)1, xt::svector<unsigned long, 4ul, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag> >> = {<No data fields>}, <No data fields>},
static static_layout = xt::layout_type::row_major, static contiguous_layout = true},
m_shape = {
static alignment = 8,
m_allocator = {<__gnu_cxx::new_allocator<unsigned long>> = {<No data fields>}, <No data fields>},
m_begin = 0xffffffff000003e8, m_end = 0x4b00000003, m_capacity = 0x0, m_data = {0, 0,
140737337425920, 9}},
m_strides = {static alignment = 8,
m_allocator = {<__gnu_cxx::new_allocator<long>> = {<No data fields>}, <No data fields>},
m_begin = 0x0, m_end = 0x0, m_capacity = 0x0, m_data = {0, 0, 0, 6}},
m_backstrides = {
static alignment = 8,
m_allocator = {<__gnu_cxx::new_allocator<long>> = {<No data fields>}, <No data fields>},
m_begin = 0x1, m_end = 0x0, m_capacity = 0x4b00000003, m_data = {-4294966296, 36, 0,
140737488342728}},
You code does not compile. I had to update it to the following:
template <class T, class... S, size_t... I>
auto copy_view_to_new_container(const xt::xview<T, S...>& view, std::index_sequence<I...>) {
const auto& container = view.expression();
xt::xarray<float> new_container = xt::eval(container);
auto slices = view.slices();
auto new_view = xt::view(new_container, std::get<I>(slices)...);
return std::make_pair(std::move(new_container), std::move(new_view));
}
TEST(gpu_proxy, dtype_float_view1) {
xt::xarray<double> array = xt::arange<double>(100);
array.reshape({10, 10});
auto view = xt::view(array, xt::range(2, 8), xt::range(3, 7));
auto [new_container, new_view] = copy_view_to_new_container(view, std::make_index_sequence<2>());
std::cout << new_container << "\n";
std::cout << new_view << "\n"; // core dump here.
}
The issue you're encountering here is new_container is captured by reference. It's life time is bound to the code of copy_view_to_new_container you then move new_container this means that new_view now has a dangling reference which when called results in a segmentation fault.
I'm not really sure what you're trying to accomplish to be honest.