diff --git a/src/util/indirect.hpp b/src/util/indirect.hpp index 5a9bb5b4d693ab6b14eec4e1cfea1a6d827d1484..1e4dbba8ebe212da1b56c7709011a10efe793d69 100644 --- a/src/util/indirect.hpp +++ b/src/util/indirect.hpp @@ -8,6 +8,8 @@ * Implemented as a transform view of the index map. */ +#include <utility> + #include <util/deduce_return.hpp> #include <util/transform.hpp> #include <util/meta.hpp> @@ -23,8 +25,9 @@ namespace impl { struct indirect_accessor { using reference = typename util::sequence_traits<Data>::reference; - Data& data; - indirect_accessor(Data& data): data(data) {} + Data data; + template <typename X> + indirect_accessor(X&& data): data(std::forward<X>(data)) {} template <typename I> reference operator()(const I& i) const { return data[i]; } @@ -33,11 +36,11 @@ namespace impl { template <typename RASeq, typename Seq> auto indirect_view(RASeq& data, const Seq& index_map) -DEDUCED_RETURN_TYPE(transform_view(index_map, impl::indirect_accessor<RASeq>(data))); +DEDUCED_RETURN_TYPE(transform_view(index_map, impl::indirect_accessor<RASeq&>(data))); template <typename RASeq, typename Seq> -auto indirect_view(const RASeq& data, const Seq& index_map) -DEDUCED_RETURN_TYPE(transform_view(index_map, impl::indirect_accessor<const RASeq>(data))); +auto indirect_view(RASeq&& data, const Seq& index_map) +DEDUCED_RETURN_TYPE(transform_view(index_map, impl::indirect_accessor<RASeq>(std::move(data)))); } // namespace util } // namespace mc diff --git a/tests/unit/test_transform.cpp b/tests/unit/test_transform.cpp index 33d1522e413f6d9e6939b6a78e2dee01dd1118e3..ab48a1cdf244a75d7cf69c2bdadf07a3b549e55c 100644 --- a/tests/unit/test_transform.cpp +++ b/tests/unit/test_transform.cpp @@ -9,6 +9,8 @@ #include <util/span.hpp> #include <util/transform.hpp> +#include "common.hpp" + using namespace nest::mc; TEST(transform, transform_view) { @@ -99,6 +101,45 @@ TEST(indirect, fwd_index) { EXPECT_EQ(expected, result); } +TEST(indirect, nocopy) { + const testing::nocopy<double> data[6] = {10., 11., 12., 13., 14., 15.}; + unsigned map_reverse[6] = {5, 4, 3, 2, 1, 0}; + auto reversed = util::indirect_view(data, map_reverse); + + std::vector<double> expected = {15., 14., 13., 12., 11., 10.}; + std::vector<double> result; + for (auto& elem: reversed) { result.push_back(elem.value); } + EXPECT_EQ(expected, result); + + unsigned map_evens[3] = {0, 2, 4}; + auto even_reversed = util::indirect_view(reversed, map_evens); + + expected = {15., 13., 11.}; + result.clear(); + for (auto& elem: even_reversed) { result.push_back(elem.value); } + EXPECT_EQ(expected, result); +} + +TEST(indirect, nomove) { + testing::nomove<double> data[6]; + for (unsigned i=0; i<util::size(data); ++i) data[i].value = 10.+i; + unsigned map_reverse[6] = {5, 4, 3, 2, 1, 0}; + auto reversed = util::indirect_view(data, map_reverse); + + std::vector<double> expected = {15., 14., 13., 12., 11., 10.}; + std::vector<double> result; + for (auto& elem: reversed) { result.push_back(elem.value); } + EXPECT_EQ(expected, result); + + unsigned map_evens[3] = {0, 2, 4}; + auto even_reversed = util::indirect_view(reversed, map_evens); + + expected = {15., 13., 11.}; + result.clear(); + for (auto& elem: even_reversed) { result.push_back(elem.value); } + EXPECT_EQ(expected, result); +} + TEST(indirect, modifying) { unsigned map1[] = {0, 2, 4, 1, 3, 0}; unsigned map2[] = {0, 1, 1, 1, 2};