|
8 | 8 | ****************************************************************************/ |
9 | 9 |
|
10 | 10 | #include <iterator> |
| 11 | +#include <memory> |
11 | 12 | #include <type_traits> |
12 | 13 | #include <vector> |
13 | 14 |
|
14 | 15 | #include "xtensor/containers/xarray.hpp" |
15 | 16 | #include "xtensor/containers/xtensor.hpp" |
16 | 17 | #include "xtensor/core/xassign.hpp" |
17 | 18 | #include "xtensor/core/xnoalias.hpp" |
| 19 | +#include "xtensor/generators/xbuilder.hpp" |
18 | 20 | #include "xtensor/misc/xmanipulation.hpp" |
19 | 21 |
|
20 | 22 | #include "test_common.hpp" |
21 | 23 | #include "test_common_macros.hpp" |
22 | 24 |
|
| 25 | +namespace |
| 26 | +{ |
| 27 | + template <class T> |
| 28 | + struct counting_allocator : std::allocator<T> |
| 29 | + { |
| 30 | + using value_type = T; |
| 31 | + inline static std::size_t allocations = 0; |
| 32 | + |
| 33 | + template <class U> |
| 34 | + struct rebind |
| 35 | + { |
| 36 | + using other = counting_allocator<U>; |
| 37 | + }; |
| 38 | + |
| 39 | + counting_allocator() = default; |
| 40 | + |
| 41 | + template <class U> |
| 42 | + counting_allocator(const counting_allocator<U>&) |
| 43 | + { |
| 44 | + } |
| 45 | + |
| 46 | + T* allocate(std::size_t n) |
| 47 | + { |
| 48 | + ++allocations; |
| 49 | + return std::allocator<T>::allocate(n); |
| 50 | + } |
| 51 | + }; |
| 52 | + |
| 53 | + struct reverse_reader |
| 54 | + { |
| 55 | + using value_type = int; |
| 56 | + const xt::xarray<int>& source; |
| 57 | + |
| 58 | + int operator()(std::size_t i) const |
| 59 | + { |
| 60 | + return source(source.size() - 1 - i); |
| 61 | + } |
| 62 | + |
| 63 | + template <class It> |
| 64 | + int element(It first, It) const |
| 65 | + { |
| 66 | + return (*this)(*first); |
| 67 | + } |
| 68 | + }; |
| 69 | +} |
| 70 | + |
23 | 71 | // a dummy shape *not derived* from std::vector but compatible |
24 | 72 | template <class T> |
25 | 73 | class my_vector |
@@ -137,6 +185,57 @@ class my_vector |
137 | 185 | namespace xt |
138 | 186 | { |
139 | 187 |
|
| 188 | +#ifndef XTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS |
| 189 | + TEST(xassign, independent_generator_reuses_storage) |
| 190 | + { |
| 191 | + using allocator = counting_allocator<double>; |
| 192 | + using array = xtensor<double, 1, layout_type::row_major, allocator>; |
| 193 | + array a = array::from_shape({16}); |
| 194 | + |
| 195 | + allocator::allocations = 0; |
| 196 | + a = arange<double>(16); |
| 197 | + EXPECT_EQ(allocator::allocations, 0u); |
| 198 | + for (std::size_t i = 0; i < a.size(); ++i) |
| 199 | + { |
| 200 | + EXPECT_EQ(a(i), double(i)); |
| 201 | + } |
| 202 | + |
| 203 | + allocator::allocations = 0; |
| 204 | + a = linspace<double>(0., 15., 16); |
| 205 | + EXPECT_EQ(allocator::allocations, 0u); |
| 206 | + for (std::size_t i = 0; i < a.size(); ++i) |
| 207 | + { |
| 208 | + EXPECT_EQ(a(i), double(i)); |
| 209 | + } |
| 210 | + } |
| 211 | +#endif |
| 212 | + |
| 213 | + TEST(xassign, independent_generator_resizes) |
| 214 | + { |
| 215 | + xarray<double> a = {{-1., -1.}, {-1., -1.}}; |
| 216 | + a = arange<double>(5); |
| 217 | + EXPECT_EQ(a.dimension(), 1u); |
| 218 | + EXPECT_EQ(a.size(), 5u); |
| 219 | + EXPECT_EQ(a(4), 4.); |
| 220 | + |
| 221 | + a = arange<double>(0); |
| 222 | + EXPECT_EQ(a.size(), 0u); |
| 223 | + a = linspace<double>(2., 4., 3); |
| 224 | + EXPECT_EQ(a, (xarray<double>{2., 3., 4.})); |
| 225 | + } |
| 226 | + |
| 227 | + TEST(xassign, reading_generators_keep_overlap_protection) |
| 228 | + { |
| 229 | + xarray<int> a = {1, 2, 3, 4}; |
| 230 | + auto reverse = detail::make_xgenerator(reverse_reader{a}, {4}); |
| 231 | + static_assert(!is_memory_independent<decltype(reverse)>::value); |
| 232 | + a = reverse; |
| 233 | + EXPECT_EQ(a, (xarray<int>{4, 3, 2, 1})); |
| 234 | + |
| 235 | + a = concatenate(xtuple(a, a)); |
| 236 | + EXPECT_EQ(a, (xarray<int>{4, 3, 2, 1, 4, 3, 2, 1})); |
| 237 | + } |
| 238 | + |
140 | 239 | template <class T, class C_T> |
141 | 240 | struct rebind_container<T, my_vector<C_T>> |
142 | 241 | { |
@@ -173,5 +272,7 @@ namespace xt |
173 | 272 | { |
174 | 273 | auto a = xt::xtensor<float, 1>::from_shape({2}); |
175 | 274 | XT_ASSERT_THROW(a = xt::expand_dims(a, 0), std::runtime_error); |
| 275 | + auto b = xt::xtensor<float, 2>::from_shape({2, 2}); |
| 276 | + XT_ASSERT_THROW(b = arange<float>(4), std::runtime_error); |
176 | 277 | } |
177 | 278 | } |
0 commit comments