blob: 3502076fcdd1e99ff029da11a080fbac2fc4d1ed [file] [log] [blame]
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001///////////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4//
5// This code is licensed under the MIT License (MIT).
6//
7// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13// THE SOFTWARE.
14//
15///////////////////////////////////////////////////////////////////////////////
16
17#pragma once
18
Treb Connell51da1362015-09-24 18:08:34 -070019#ifndef GSL_ARRAY_VIEW_H
20#define GSL_ARRAY_VIEW_H
21
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070022#include <new>
23#include <stdexcept>
24#include <cstddef>
25#include <cstdint>
26#include <limits>
27#include <type_traits>
28#include <utility>
29#include <array>
30#include <iterator>
Kern Handac4f9b872015-09-25 17:01:29 -070031#include <algorithm>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070032#include "fail_fast.h"
33
Neil MacIntoshd5316802015-09-30 21:54:08 -070034#ifdef _MSC_VER
35
36// No MSVC does constexpr fully yet
Gabriel Dos Reis6554e832015-09-28 05:10:44 -070037#pragma push_macro("constexpr")
38#define constexpr /* nothing */
Neil MacIntoshd5316802015-09-30 21:54:08 -070039
40
41// VS 2013 workarounds
42#if _MSC_VER <= 1800
43
44// noexcept is not understood
45#ifndef GSL_THROWS_FOR_TESTING
46#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070047#endif
48
Neil MacIntoshd5316802015-09-30 21:54:08 -070049// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070050#pragma warning(push)
51#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
Neil MacIntoshd5316802015-09-30 21:54:08 -070052
Neil MacIntosh9a297122015-09-14 15:11:07 -070053#endif // _MSC_VER <= 1800
54
Neil MacIntoshd5316802015-09-30 21:54:08 -070055#endif // _MSC_VER
56
57// In order to test the library, we need it to throw exceptions that we can catch
58#ifdef GSL_THROWS_FOR_TESTING
59#define noexcept /* nothing */
60#endif // GSL_THROWS_FOR_TESTING
61
62
Neil MacIntoshef626fd2015-09-29 16:41:37 -070063namespace gsl {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070064
65/*
66** begin definitions of index and bounds
67*/
68namespace details
69{
70 template <typename SizeType>
71 struct SizeTypeTraits
72 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -070073 static const SizeType max_value = std::is_signed<SizeType>::value ? static_cast<typename std::make_unsigned<SizeType>::type>(-1) / 2 : static_cast<SizeType>(-1);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070074 };
75
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070076 template <typename T>
77 class arrow_proxy
78 {
79 public:
80 explicit arrow_proxy(T t)
81 : val(t)
82 {}
Neil MacIntoshd5316802015-09-30 21:54:08 -070083 const T operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070084 {
85 return val;
86 }
Neil MacIntoshd5316802015-09-30 21:54:08 -070087 const T* operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070088 {
89 return &val;
90 }
91 private:
92 T val;
93 };
94}
95
Kern Handae1570262015-09-25 00:42:38 -070096template <size_t Rank, typename ValueType = size_t>
Anna Gringauzedb384972015-10-05 12:34:23 -070097class index final
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070098{
Anna Gringauzedb384972015-10-05 12:34:23 -070099 static_assert(std::is_integral<ValueType>::value, "ValueType must be an integral type!");
100 static_assert(Rank > 0, "Rank must be greater than 0!");
101
Kern Handae1570262015-09-25 00:42:38 -0700102 template <size_t OtherRank, typename OtherValueType>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700103 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -0700104
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700105public:
Anna Gringauzedb384972015-10-05 12:34:23 -0700106 static const size_t rank = Rank;
107 using value_type = std::remove_reference_t<ValueType>;
108 using reference = std::add_lvalue_reference_t<value_type>;
109 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700110
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700111 constexpr index() noexcept
112 {}
113
Anna Gringauzedb384972015-10-05 12:34:23 -0700114 constexpr index(const value_type(&values)[Rank]) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700115 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700116 std::copy(values, values + Rank, elems);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700117 }
118
Anna Gringauzedb384972015-10-05 12:34:23 -0700119 // Preconditions: il.size() == rank
120 constexpr index(std::initializer_list<value_type> il) noexcept
121 {
122 fail_fast_assert(il.size() == Rank, "The size of the initializer list must match the rank of the array");
123 std::copy(begin(il), end(il), elems);
124 }
125
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700126 constexpr index(const index& other) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700127
128 // copy from index over smaller domain
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700129 template <typename OtherValueType,
130 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value <= details::SizeTypeTraits<value_type>::max_value),
131 typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
132 constexpr index(const index<Rank, OtherValueType>& other) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700133 {
134 std::copy(other.elems, other.elems + Rank, elems);
135 }
136
137 // copy from index over larger domain
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700138 template <typename OtherValueType,
139 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value > details::SizeTypeTraits<value_type>::max_value),
140 typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
141 constexpr index(const index<Rank, OtherValueType>& other, void* ptr = 0) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700142 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700143 bool ok = std::accumulate(other.elems, other.elems + Rank, true,
144 [&](bool b, OtherValueType val) { return b && (val <= static_cast<OtherValueType>(details::SizeTypeTraits<value_type>::max_value)); }
145 );
Anna Gringauzedb384972015-10-05 12:34:23 -0700146
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700147 fail_fast_assert(ok, "other value must fit in the new domain");
148 std::transform(other.elems, other.elems + rank, elems, [&](OtherValueType val) { return static_cast<value_type>(val); });
Anna Gringauzedb384972015-10-05 12:34:23 -0700149 }
150
151 constexpr index& operator=(const index& rhs) noexcept = default;
152
153 // Preconditions: component_idx < rank
154 constexpr reference operator[](size_t component_idx)
155 {
156 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
157 return elems[component_idx];
158 }
159
160 // Preconditions: component_idx < rank
161 constexpr const_reference operator[](size_t component_idx) const noexcept
162 {
163 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
164 return elems[component_idx];
165 }
166
167 constexpr bool operator==(const index& rhs) const noexcept
168 {
169 return std::equal(elems, elems + rank, rhs.elems);
170 }
171
172 constexpr bool operator!=(const index& rhs) const noexcept
173 {
174 return !(this == rhs);
175 }
176
177 constexpr index operator+() const noexcept
178 {
179 return *this;
180 }
181
182 constexpr index operator-() const noexcept
183 {
184 index ret = *this;
185 std::transform(ret, ret + rank, ret, std::negate<ValueType>{});
186 return ret;
187 }
188
189 constexpr index operator+(const index& rhs) const noexcept
190 {
191 index ret = *this;
192 ret += rhs;
193 return ret;
194 }
195
196 constexpr index operator-(const index& rhs) const noexcept
197 {
198 index ret = *this;
199 ret -= rhs;
200 return ret;
201 }
202
203 constexpr index& operator+=(const index& rhs) noexcept
204 {
205 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<ValueType>{});
206 return *this;
207 }
208
209 constexpr index& operator-=(const index& rhs) noexcept
210 {
211 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<ValueType>{});
212 return *this;
213 }
214
215 constexpr index operator*(value_type v) const noexcept
216 {
217 index ret = *this;
218 ret *= v;
219 return ret;
220 }
221
222 constexpr index operator/(value_type v) const noexcept
223 {
224 index ret = *this;
225 ret /= v;
226 return ret;
227 }
228
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700229 friend constexpr index operator*(value_type v, const index& rhs) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700230 {
231 return rhs * v;
232 }
233
234 constexpr index& operator*=(value_type v) noexcept
235 {
236 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies<ValueType>{}(x, v); });
237 return *this;
238 }
239
240 constexpr index& operator/=(value_type v) noexcept
241 {
242 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<ValueType>{}(x, v); });
243 return *this;
244 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700245
Anna Gringauzedb384972015-10-05 12:34:23 -0700246private:
247 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700248};
249
250template <typename ValueType>
251class index<1, ValueType>
252{
Kern Handae1570262015-09-25 00:42:38 -0700253 template <size_t, typename OtherValueType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700254 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -0700255
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700256public:
Kern Handae1570262015-09-25 00:42:38 -0700257 static const size_t rank = 1;
Anna Gringauzedb384972015-10-05 12:34:23 -0700258 using value_type = std::remove_reference_t<ValueType>;
259 using reference = std::add_lvalue_reference_t<value_type>;
260 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700261
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700262 constexpr index() noexcept : value(0)
Anna Gringauzedb384972015-10-05 12:34:23 -0700263 {}
264
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700265 constexpr index(value_type e) noexcept : value(e)
Anna Gringauzedb384972015-10-05 12:34:23 -0700266 {}
267
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700268 constexpr index(const value_type(&values)[1]) noexcept : index(values[0])
269 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700270
Anna Gringauzedb384972015-10-05 12:34:23 -0700271 constexpr index(const index &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700272
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700273 template <typename OtherValueType,
274 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value <= details::SizeTypeTraits<value_type>::max_value),
275 typename Other = std::enable_if_t<Enabled, index<1, OtherValueType>>>
276 constexpr index(const index<1, OtherValueType>& other) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700277 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700278 value = static_cast<ValueType>(other.value);
279 }
280
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700281 template <typename OtherValueType,
282 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value > details::SizeTypeTraits<value_type>::max_value),
283 typename Other = std::enable_if_t<Enabled, index<1, OtherValueType>>>
284 constexpr index(const index<1, OtherValueType>& other, void* ptr=0) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700285 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700286 fail_fast_assert(other.value <= static_cast<OtherValueType>(details::SizeTypeTraits<value_type>::max_value));
Anna Gringauzedb384972015-10-05 12:34:23 -0700287 value = static_cast<value_type>(other.value);
288 }
289
Anna Gringauzedb384972015-10-05 12:34:23 -0700290 // Preconditions: component_idx < 1
291 constexpr reference operator[](value_type component_idx) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700292 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700293 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700294 (void)(component_idx);
295 return value;
296 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700297 // Preconditions: component_idx < 1
298 constexpr const_reference operator[](value_type component_idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700299 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700300 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700301 (void)(component_idx);
302 return value;
303 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700304 constexpr bool operator==(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700305 {
306 return value == rhs.value;
307 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700308 constexpr bool operator!=(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700309 {
310 return !(*this == rhs);
311 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700312 constexpr index operator+() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700313 {
314 return *this;
315 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700316 constexpr index operator-() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700317 {
318 return index(-value);
319 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700320 constexpr index operator+(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700321 {
322 return index(value + rhs.value);
323 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700324 constexpr index operator-(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700325 {
326 return index(value - rhs.value);
327 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700328 constexpr index& operator+=(const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700329 {
330 value += rhs.value;
331 return *this;
332 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700333 constexpr index& operator-=(const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700334 {
335 value -= rhs.value;
336 return *this;
337 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700338 constexpr index& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700339 {
340 ++value;
341 return *this;
342 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700343 constexpr index operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700344 {
345 index ret = *this;
346 ++(*this);
347 return ret;
348 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700349 constexpr index& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700350 {
351 --value;
352 return *this;
353 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700354 constexpr index operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700355 {
356 index ret = *this;
357 --(*this);
358 return ret;
359 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700360 constexpr index operator*(value_type v) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700361 {
362 return index(value * v);
363 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700364 constexpr index operator/(value_type v) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700365 {
366 return index(value / v);
367 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700368 constexpr index& operator*=(value_type v) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700369 {
370 value *= v;
371 return *this;
372 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700373 constexpr index& operator/=(value_type v) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700374 {
375 value /= v;
376 return *this;
377 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700378 friend constexpr index operator*(value_type v, const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700379 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700380 return{ rhs * v };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700381 }
382private:
383 value_type value;
384};
385
386#ifndef _MSC_VER
387
388struct static_bounds_dynamic_range_t
389{
390 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
391 constexpr operator T() const noexcept
392 {
393 return static_cast<T>(-1);
394 }
395
396 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
397 constexpr bool operator ==(T other) const noexcept
398 {
399 return static_cast<T>(-1) == other;
400 }
401
402 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
403 constexpr bool operator !=(T other) const noexcept
404 {
405 return static_cast<T>(-1) != other;
406 }
407
408};
409
410template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
411constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
412{
413 return right == left;
414}
415
416template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
417constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
418{
419 return right != left;
420}
421
422constexpr static_bounds_dynamic_range_t dynamic_range{};
423#else
424const char dynamic_range = -1;
425#endif
426
427struct generalized_mapping_tag {};
428struct contiguous_mapping_tag : generalized_mapping_tag {};
429
430namespace details
431{
432 template <typename SizeType, SizeType Fact1, SizeType Fact2, SizeType ConstBound>
433 struct StaticSizeHelperImpl
434 {
435 static_assert(static_cast<size_t>(Fact1) * static_cast<size_t>(Fact2) <= SizeTypeTraits<SizeType>::max_value, "Value out of the range of SizeType");
436 static const SizeType value = Fact1 * Fact2;
437 };
438
439 template <typename SizeType, SizeType Fact1, SizeType ConstBound>
440 struct StaticSizeHelperImpl<SizeType, Fact1, ConstBound, ConstBound>
441 {
442 static const SizeType value = ConstBound;
443 };
444
445 template <typename SizeType, SizeType Fact2, SizeType ConstBound>
446 struct StaticSizeHelperImpl<SizeType, ConstBound, Fact2, ConstBound>
447 {
448 static const SizeType value = ConstBound;
449 };
450
451 template <typename SizeType, SizeType ConstBound>
452 struct StaticSizeHelperImpl<SizeType, ConstBound, ConstBound, ConstBound>
453 {
454 static const SizeType value = static_cast<SizeType>(ConstBound);
455 };
456
457 template <typename SizeType, SizeType Fact1, SizeType Fact2>
458 struct StaticSizeHelper
459 {
460 static const SizeType value = StaticSizeHelperImpl<SizeType, static_cast<SizeType>(Fact1), static_cast<SizeType>(Fact2), static_cast<SizeType>(dynamic_range)>::value;
461 };
462
463
464 template <size_t Left, size_t Right>
465 struct LessThan
466 {
467 static const bool value = Left < Right;
468 };
469
470 template <typename SizeType, size_t... Ranges>
471 struct BoundsRanges {
Kern Handae1570262015-09-25 00:42:38 -0700472 static const size_t Depth = 0;
473 static const size_t DynamicNum = 0;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700474 static const SizeType CurrentRange = 1;
475 static const SizeType TotalSize = 1;
476
477 BoundsRanges (const BoundsRanges &) = default;
478
479 // TODO : following signature is for work around VS bug
480 template <typename OtherType>
Kosov Eugene3402b922015-09-28 21:20:02 +0300481 BoundsRanges (const OtherType &, bool /* firstLevel */) {}
galikcab9bda2015-09-19 07:52:30 +0100482 BoundsRanges(const SizeType * const) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700483 BoundsRanges() = default;
484
485
Kern Handae1570262015-09-25 00:42:38 -0700486 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700487 void serialize(T &) const {
488 }
Kern Handae1570262015-09-25 00:42:38 -0700489 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700490 SizeType linearize(const T &) const {
491 return 0;
492 }
Kern Handae1570262015-09-25 00:42:38 -0700493 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700494 ptrdiff_t contains(const T &) const {
495 return 0;
496 }
497
Neil MacIntoshd5316802015-09-30 21:54:08 -0700498 size_t totalSize() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700499 return TotalSize;
500 }
501
Neil MacIntoshd5316802015-09-30 21:54:08 -0700502 bool operator == (const BoundsRanges &) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700503 {
504 return true;
505 }
506 };
507
508 template <typename SizeType, size_t... RestRanges>
509 struct BoundsRanges <SizeType, dynamic_range, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
510 using Base = BoundsRanges <SizeType, RestRanges... >;
Kern Handae1570262015-09-25 00:42:38 -0700511 static const size_t Depth = Base::Depth + 1;
512 static const size_t DynamicNum = Base::DynamicNum + 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700513 static const SizeType CurrentRange = dynamic_range;
514 static const SizeType TotalSize = dynamic_range;
515 const SizeType m_bound;
516
517 BoundsRanges (const BoundsRanges &) = default;
518 BoundsRanges(const SizeType * const arr) : Base(arr + 1), m_bound(static_cast<SizeType>(*arr * this->Base::totalSize()))
519 {
520 fail_fast_assert(0 <= *arr);
521 fail_fast_assert(*arr * this->Base::totalSize() <= details::SizeTypeTraits<SizeType>::max_value);
522 }
523 BoundsRanges() : m_bound(0) {}
524
525 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
Kosov Eugene3402b922015-09-28 21:20:02 +0300526 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool /* firstLevel */ = true) :
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700527 Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false), m_bound (static_cast<SizeType>(other.totalSize()))
528 {
529 }
530
Kern Handae1570262015-09-25 00:42:38 -0700531 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700532 void serialize(T & arr) const {
533 arr[Dim] = elementNum();
534 this->Base::template serialize<T, Dim + 1>(arr);
535 }
Kern Handae1570262015-09-25 00:42:38 -0700536 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700537 SizeType linearize(const T & arr) const {
538 const size_t index = this->Base::totalSize() * arr[Dim];
539 fail_fast_assert(index < static_cast<size_t>(m_bound));
540 return static_cast<SizeType>(index) + this->Base::template linearize<T, Dim + 1>(arr);
541 }
542
Kern Handae1570262015-09-25 00:42:38 -0700543 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700544 ptrdiff_t contains(const T & arr) const {
545 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
546 if (last == -1)
547 return -1;
548 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
549 return static_cast<size_t>(cur) < static_cast<size_t>(m_bound) ? cur + last : -1;
550 }
551
Neil MacIntoshd5316802015-09-30 21:54:08 -0700552 size_t totalSize() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700553 return m_bound;
554 }
555
Neil MacIntoshd5316802015-09-30 21:54:08 -0700556 SizeType elementNum() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700557 return static_cast<SizeType>(totalSize() / this->Base::totalSize());
558 }
559
Neil MacIntoshd5316802015-09-30 21:54:08 -0700560 SizeType elementNum(size_t dim) const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700561 if (dim > 0)
562 return this->Base::elementNum(dim - 1);
563 else
564 return elementNum();
565 }
566
Neil MacIntoshd5316802015-09-30 21:54:08 -0700567 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700568 {
569 return m_bound == rhs.m_bound && static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
570 }
571 };
572
573 template <typename SizeType, size_t CurRange, size_t... RestRanges>
574 struct BoundsRanges <SizeType, CurRange, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
575 using Base = BoundsRanges <SizeType, RestRanges... >;
Kern Handae1570262015-09-25 00:42:38 -0700576 static const size_t Depth = Base::Depth + 1;
577 static const size_t DynamicNum = Base::DynamicNum;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700578 static const SizeType CurrentRange = static_cast<SizeType>(CurRange);
579 static const SizeType TotalSize = StaticSizeHelper<SizeType, Base::TotalSize, CurrentRange>::value;
580 static_assert (CurRange <= SizeTypeTraits<SizeType>::max_value, "CurRange must be smaller than SizeType limits");
581
582 BoundsRanges (const BoundsRanges &) = default;
583 BoundsRanges(const SizeType * const arr) : Base(arr) { }
584 BoundsRanges() = default;
585
586 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
587 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false)
588 {
589 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
590 }
591
Kern Handae1570262015-09-25 00:42:38 -0700592 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700593 void serialize(T & arr) const {
594 arr[Dim] = elementNum();
595 this->Base::template serialize<T, Dim + 1>(arr);
596 }
597
Kern Handae1570262015-09-25 00:42:38 -0700598 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700599 SizeType linearize(const T & arr) const {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700600 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700601 return static_cast<SizeType>(this->Base::totalSize()) * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
602 }
603
Kern Handae1570262015-09-25 00:42:38 -0700604 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700605 ptrdiff_t contains(const T & arr) const {
606 if (static_cast<size_t>(arr[Dim]) >= CurrentRange)
607 return -1;
608 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
609 if (last == -1)
610 return -1;
611 return static_cast<ptrdiff_t>(this->Base::totalSize() * arr[Dim]) + last;
612 }
613
Neil MacIntoshd5316802015-09-30 21:54:08 -0700614 size_t totalSize() const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700615 return CurrentRange * this->Base::totalSize();
616 }
617
Neil MacIntoshd5316802015-09-30 21:54:08 -0700618 SizeType elementNum() const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700619 return CurrentRange;
620 }
621
Neil MacIntoshd5316802015-09-30 21:54:08 -0700622 SizeType elementNum(size_t dim) const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700623 if (dim > 0)
624 return this->Base::elementNum(dim - 1);
625 else
626 return elementNum();
627 }
628
Neil MacIntoshd5316802015-09-30 21:54:08 -0700629 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700630 {
631 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
632 }
633 };
634
635 template <typename SourceType, typename TargetType, size_t Rank>
636 struct BoundsRangeConvertible2;
637
638 // TODO: I have to rewrite BoundsRangeConvertible into following way to workaround VS 2013 bugs
639 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
640 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
641
642 template <size_t Rank, typename SourceType, typename TargetType>
643 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
644
645 template <typename SourceType, typename TargetType, size_t Rank>
646 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
647 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
648 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
649 {};
650
651 template <typename SourceType, typename TargetType>
652 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
653
654 template <typename SourceType, typename TargetType, size_t Rank = TargetType::Depth>
655 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
656 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
657 && (!LessThan<size_t(SourceType::CurrentRange), size_t(TargetType::CurrentRange)>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
658 {};
659 template <typename SourceType, typename TargetType>
660 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
661
662 template <typename TypeChain>
663 struct TypeListIndexer
664 {
665 const TypeChain & obj;
666 TypeListIndexer(const TypeChain & obj) :obj(obj){}
Kern Handae1570262015-09-25 00:42:38 -0700667 template<size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700668 const TypeChain & getObj(std::true_type)
669 {
670 return obj;
671 }
Kern Handae1570262015-09-25 00:42:38 -0700672 template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700673 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
674 {
675 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
676 }
Kern Handae1570262015-09-25 00:42:38 -0700677 template <size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700678 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
679 {
680 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
681 }
682 };
683
684 template <typename TypeChain>
685 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
686 {
687 return TypeListIndexer<TypeChain>(obj);
688 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700689
690 template <size_t Rank, typename ValueType, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1, ValueType>>>
691 constexpr Ret shift_left(const index<Rank, ValueType>& other) noexcept
692 {
693 Ret ret;
694 for (size_t i = 0; i < Rank - 1; ++i)
695 {
696 ret[i] = other[i + 1];
697 }
698 return ret;
699 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700700}
701
702template <typename IndexType>
703class bounds_iterator;
704
705template <typename SizeType, size_t... Ranges>
706class static_bounds {
707public:
Kosov Eugene3402b922015-09-28 21:20:02 +0300708 static_bounds(const details::BoundsRanges<SizeType, Ranges...> &) {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700709 }
710};
711
712template <typename SizeType, size_t FirstRange, size_t... RestRanges>
713class static_bounds<SizeType, FirstRange, RestRanges...>
714{
715 using MyRanges = details::BoundsRanges <SizeType, FirstRange, RestRanges... >;
716 static_assert(std::is_integral<SizeType>::value
717 && details::SizeTypeTraits<SizeType>::max_value <= SIZE_MAX, "SizeType must be an integral type and its numeric limits must be smaller than SIZE_MAX");
718
719 MyRanges m_ranges;
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700720 constexpr static_bounds(const MyRanges & range) : m_ranges(range) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700721
722 template <typename SizeType2, size_t... Ranges2>
723 friend class static_bounds;
724public:
Kern Handae1570262015-09-25 00:42:38 -0700725 static const size_t rank = MyRanges::Depth;
726 static const size_t dynamic_rank = MyRanges::DynamicNum;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700727 static const SizeType static_size = static_cast<SizeType>(MyRanges::TotalSize);
728
729 using size_type = SizeType;
730 using index_type = index<rank, size_type>;
731 using iterator = bounds_iterator<index_type>;
732 using const_iterator = bounds_iterator<index_type>;
733 using difference_type = ptrdiff_t;
734 using sliced_type = static_bounds<SizeType, RestRanges...>;
735 using mapping_type = contiguous_mapping_tag;
736public:
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700737 constexpr static_bounds(const static_bounds &) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700738
739 template <typename OtherSizeType, size_t... Ranges, typename Dummy = std::enable_if_t<
740 details::BoundsRangeConvertible<details::BoundsRanges<OtherSizeType, Ranges...>, details::BoundsRanges <SizeType, FirstRange, RestRanges... >>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700741 constexpr static_bounds(const static_bounds<OtherSizeType, Ranges...> &other):
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700742 m_ranges(other.m_ranges)
743 {
744 }
745
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700746 constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700747 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700748 fail_fast_assert(MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
749 fail_fast_assert(m_ranges.totalSize() <= details::SizeTypeTraits<size_type>::max_value, "Size of the range is larger than the max element of the size type");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700750 }
751
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700752 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700753
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700754 constexpr static_bounds & operator = (const static_bounds & otherBounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700755 {
756 new(&m_ranges) MyRanges (otherBounds.m_ranges);
757 return *this;
758 }
759
Neil MacIntoshd5316802015-09-30 21:54:08 -0700760 constexpr sliced_type slice() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700761 {
762 return sliced_type{static_cast<const details::BoundsRanges<SizeType, RestRanges...> &>(m_ranges)};
763 }
764
Neil MacIntoshd5316802015-09-30 21:54:08 -0700765 constexpr size_type stride() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700766 {
767 return rank > 1 ? slice().size() : 1;
768 }
769
Neil MacIntoshd5316802015-09-30 21:54:08 -0700770 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700771 {
772 return static_cast<size_type>(m_ranges.totalSize());
773 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700774
Neil MacIntoshd5316802015-09-30 21:54:08 -0700775 constexpr size_type total_size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700776 {
777 return static_cast<size_type>(m_ranges.totalSize());
778 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700779
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700780 constexpr size_type linearize(const index_type & idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700781 {
782 return m_ranges.linearize(idx);
783 }
784
Neil MacIntoshd5316802015-09-30 21:54:08 -0700785 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700786 {
787 return m_ranges.contains(idx) != -1;
788 }
789
Neil MacIntoshd5316802015-09-30 21:54:08 -0700790 constexpr size_type operator[](size_t index) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700791 {
792 return m_ranges.elementNum(index);
793 }
794
Kern Handae1570262015-09-25 00:42:38 -0700795 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700796 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700797 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700798 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700799 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
800 }
801
Neil MacIntoshd5316802015-09-30 21:54:08 -0700802 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700803 {
Anna Gringauzefdf86432015-10-14 10:46:22 -0700804 size_type extents[rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700805 m_ranges.serialize(extents);
Anna Gringauzedb384972015-10-05 12:34:23 -0700806 return{ extents };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700807 }
808
809 template <typename OtherSizeTypes, size_t... Ranges>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700810 constexpr bool operator == (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700811 {
812 return this->size() == rhs.size();
813 }
814
815 template <typename OtherSizeTypes, size_t... Ranges>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700816 constexpr bool operator != (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700817 {
818 return !(*this == rhs);
819 }
820
Neil MacIntoshd5316802015-09-30 21:54:08 -0700821 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700822 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700823 return const_iterator(*this);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700824 }
825
Neil MacIntoshd5316802015-09-30 21:54:08 -0700826 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700827 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700828 return const_iterator(*this, this->index_bounds());
829 }
830};
831
Kern Handae1570262015-09-25 00:42:38 -0700832template <size_t Rank, typename SizeType = size_t>
Anna Gringauzedb384972015-10-05 12:34:23 -0700833class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700834{
Kern Handae1570262015-09-25 00:42:38 -0700835 template <size_t OtherRank, typename OtherSizeType>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700836 friend class strided_bounds;
837
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700838public:
Anna Gringauzedb384972015-10-05 12:34:23 -0700839 static const size_t rank = Rank;
Anna Gringauzefdf86432015-10-14 10:46:22 -0700840 using reference = SizeType&;
841 using const_reference = const SizeType&;
842 using size_type = SizeType;
843 using difference_type = SizeType;
844 using value_type = SizeType;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700845 using index_type = index<rank, size_type>;
846 using iterator = bounds_iterator<index_type>;
847 using const_iterator = bounds_iterator<index_type>;
848 static const int dynamic_rank = rank;
849 static const size_t static_size = dynamic_range;
850 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
851 using mapping_type = generalized_mapping_tag;
Anna Gringauzedb384972015-10-05 12:34:23 -0700852 constexpr strided_bounds(const strided_bounds &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700853
854 template <typename OtherSizeType>
Anna Gringauzedb384972015-10-05 12:34:23 -0700855 constexpr strided_bounds(const strided_bounds<rank, OtherSizeType> &other) noexcept
856 : m_extents(other.extents), m_strides(other.strides)
857 {}
858 constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept
859 : m_extents(extents), m_strides(strides)
860 {}
Neil MacIntoshd5316802015-09-30 21:54:08 -0700861 constexpr index_type strides() const noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700862 {
863 return m_strides;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700864 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700865 constexpr size_type total_size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700866 {
867 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700868 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700869 {
870 ret += (m_extents[i] - 1) * m_strides[i];
871 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700872 return ret + 1;
873 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700874 constexpr size_type size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700875 {
876 size_type ret = 1;
Kern Handae1570262015-09-25 00:42:38 -0700877 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700878 {
879 ret *= m_extents[i];
880 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700881 return ret;
882 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700883 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700884 {
Kern Handae1570262015-09-25 00:42:38 -0700885 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700886 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700887 if (idx[i] < 0 || idx[i] >= m_extents[i])
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700888 return false;
889 }
890 return true;
891 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700892 constexpr size_type linearize(const index_type & idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700893 {
894 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700895 for (size_t i = 0; i < rank; i++)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700896 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700897 fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700898 ret += idx[i] * m_strides[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700899 }
900 return ret;
901 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700902 constexpr size_type stride() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700903 {
904 return m_strides[0];
905 }
906 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700907 constexpr sliced_type slice() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700908 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700909 return{ details::shift_left(m_extents), details::shift_left(m_strides) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700910 }
Kern Handae1570262015-09-25 00:42:38 -0700911 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700912 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700913 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700914 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
Anna Gringauzedb384972015-10-05 12:34:23 -0700915 return m_extents[Dim];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700916 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700917 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700918 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700919 return m_extents;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700920 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700921 const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700922 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700923 return const_iterator{ *this };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700924 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700925 const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700926 {
927 return const_iterator{ *this, index_bounds() };
928 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700929private:
Anna Gringauzedb384972015-10-05 12:34:23 -0700930 index_type m_extents;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700931 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700932};
933
934template <typename T>
935struct is_bounds : std::integral_constant<bool, false> {};
936template <typename SizeType, size_t... Ranges>
937struct is_bounds<static_bounds<SizeType, Ranges...>> : std::integral_constant<bool, true> {};
Kern Handae1570262015-09-25 00:42:38 -0700938template <size_t Rank, typename SizeType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700939struct is_bounds<strided_bounds<Rank, SizeType>> : std::integral_constant<bool, true> {};
940
941template <typename IndexType>
942class bounds_iterator
943 : public std::iterator<std::random_access_iterator_tag,
944 IndexType,
945 ptrdiff_t,
946 const details::arrow_proxy<IndexType>,
947 const IndexType>
948{
949private:
950 using Base = std::iterator <std::random_access_iterator_tag, IndexType, ptrdiff_t, const details::arrow_proxy<IndexType>, const IndexType>;
951public:
Kern Handae1570262015-09-25 00:42:38 -0700952 static const size_t rank = IndexType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700953 using typename Base::reference;
954 using typename Base::pointer;
955 using typename Base::difference_type;
956 using typename Base::value_type;
957 using index_type = value_type;
Anna Gringauzedb384972015-10-05 12:34:23 -0700958 using index_size_type = typename IndexType::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700959 template <typename Bounds>
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700960 explicit bounds_iterator(const Bounds& bnd, value_type curr = value_type{}) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700961 : boundary(bnd.index_bounds())
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700962 , curr(std::move(curr))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700963 {
964 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
965 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700966 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700967 {
968 return curr;
969 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700970 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700971 {
972 return details::arrow_proxy<value_type>{ curr };
973 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700974 bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700975 {
Kern Handae1570262015-09-25 00:42:38 -0700976 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700977 {
978 if (++curr[i] < boundary[i])
979 {
980 return *this;
981 }
982 else
983 {
984 curr[i] = 0;
985 }
986 }
987 // If we're here we've wrapped over - set to past-the-end.
Kern Handae1570262015-09-25 00:42:38 -0700988 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700989 {
990 curr[i] = boundary[i];
991 }
992 return *this;
993 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700994 bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700995 {
996 auto ret = *this;
997 ++(*this);
998 return ret;
999 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001000 bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001001 {
Neil MacIntoshfb913932015-09-27 16:25:43 -07001002 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001003 {
1004 if (curr[i]-- > 0)
1005 {
1006 return *this;
1007 }
1008 else
1009 {
1010 curr[i] = boundary[i] - 1;
1011 }
1012 }
1013 // If we're here the preconditions were violated
1014 // "pre: there exists s such that r == ++s"
1015 fail_fast_assert(false);
1016 return *this;
1017 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001018 bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001019 {
1020 auto ret = *this;
1021 --(*this);
1022 return ret;
1023 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001024 bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001025 {
1026 bounds_iterator ret{ *this };
1027 return ret += n;
1028 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001029 bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001030 {
1031 auto linear_idx = linearize(curr) + n;
1032 value_type stride;
1033 stride[rank - 1] = 1;
Kern Handae1570262015-09-25 00:42:38 -07001034 for (size_t i = rank - 1; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001035 {
1036 stride[i] = stride[i + 1] * boundary[i + 1];
1037 }
Kern Handae1570262015-09-25 00:42:38 -07001038 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001039 {
1040 curr[i] = linear_idx / stride[i];
1041 linear_idx = linear_idx % stride[i];
1042 }
1043 return *this;
1044 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001045 bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001046 {
1047 bounds_iterator ret{ *this };
1048 return ret -= n;
1049 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001050 bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001051 {
1052 return *this += -n;
1053 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001054 difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001055 {
1056 return linearize(curr) - linearize(rhs.curr);
1057 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001058 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001059 {
1060 return *(*this + n);
1061 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001062 bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001063 {
1064 return curr == rhs.curr;
1065 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001066 bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001067 {
1068 return !(*this == rhs);
1069 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001070 bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001071 {
Kern Handae1570262015-09-25 00:42:38 -07001072 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001073 {
1074 if (curr[i] < rhs.curr[i])
1075 return true;
1076 }
1077 return false;
1078 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001079 bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001080 {
1081 return !(rhs < *this);
1082 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001083 bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001084 {
1085 return rhs < *this;
1086 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001087 bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001088 {
1089 return !(rhs > *this);
1090 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001091 void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001092 {
1093 std::swap(boundary, rhs.boundary);
1094 std::swap(curr, rhs.curr);
1095 }
1096private:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001097 index_size_type linearize(const value_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001098 {
1099 // TODO: Smarter impl.
1100 // Check if past-the-end
1101 bool pte = true;
Kern Handae1570262015-09-25 00:42:38 -07001102 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001103 {
1104 if (idx[i] != boundary[i])
1105 {
1106 pte = false;
1107 break;
1108 }
1109 }
1110 index_size_type multiplier = 1;
1111 index_size_type res = 0;
1112 if (pte)
1113 {
1114 res = 1;
Kern Handae1570262015-09-25 00:42:38 -07001115 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001116 {
1117 res += (idx[i] - 1) * multiplier;
1118 multiplier *= boundary[i];
1119 }
1120 }
1121 else
1122 {
Kern Handae1570262015-09-25 00:42:38 -07001123 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001124 {
1125 res += idx[i] * multiplier;
1126 multiplier *= boundary[i];
1127 }
1128 }
1129 return res;
1130 }
1131 value_type boundary;
1132 value_type curr;
1133};
1134
1135template <typename SizeType>
1136class bounds_iterator<index<1, SizeType>>
1137 : public std::iterator<std::random_access_iterator_tag,
1138 index<1, SizeType>,
1139 ptrdiff_t,
1140 const details::arrow_proxy<index<1, SizeType>>,
1141 const index<1, SizeType>>
1142{
1143 using Base = std::iterator<std::random_access_iterator_tag, index<1, SizeType>, ptrdiff_t, const details::arrow_proxy<index<1, SizeType>>, const index<1, SizeType>>;
1144
1145public:
1146 using typename Base::reference;
1147 using typename Base::pointer;
1148 using typename Base::difference_type;
1149 using typename Base::value_type;
1150 using index_type = value_type;
Anna Gringauzedb384972015-10-05 12:34:23 -07001151 using index_size_type = typename index_type::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001152
1153 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001154 explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001155 : curr( std::move(curr) )
1156 {}
Neil MacIntoshd5316802015-09-30 21:54:08 -07001157 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001158 {
1159 return curr;
1160 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001161 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001162 {
1163 return details::arrow_proxy<value_type>{ curr };
1164 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001165 bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001166 {
1167 ++curr;
1168 return *this;
1169 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001170 bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001171 {
1172 auto ret = *this;
1173 ++(*this);
1174 return ret;
1175 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001176 bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001177 {
1178 curr--;
1179 return *this;
1180 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001181 bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001182 {
1183 auto ret = *this;
1184 --(*this);
1185 return ret;
1186 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001187 bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001188 {
1189 bounds_iterator ret{ *this };
1190 return ret += n;
1191 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001192 bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001193 {
1194 curr += n;
1195 return *this;
1196 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001197 bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001198 {
1199 bounds_iterator ret{ *this };
1200 return ret -= n;
1201 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001202 bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001203 {
1204 return *this += -n;
1205 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001206 difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001207 {
1208 return curr[0] - rhs.curr[0];
1209 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001210 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001211 {
1212 return curr + n;
1213 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001214 bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001215 {
1216 return curr == rhs.curr;
1217 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001218 bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001219 {
1220 return !(*this == rhs);
1221 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001222 bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001223 {
1224 return curr[0] < rhs.curr[0];
1225 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001226 bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001227 {
1228 return !(rhs < *this);
1229 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001230 bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001231 {
1232 return rhs < *this;
1233 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001234 bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001235 {
1236 return !(rhs > *this);
1237 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001238 void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001239 {
1240 std::swap(curr, rhs.curr);
1241 }
1242private:
1243 value_type curr;
1244};
1245
1246template <typename IndexType>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001247bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001248{
1249 return rhs + n;
1250}
1251
1252/*
1253** begin definitions of basic_array_view
1254*/
1255namespace details
1256{
1257 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001258 constexpr std::enable_if_t<std::is_same<typename Bounds::mapping_type, generalized_mapping_tag>::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001259 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001260 return bnd.strides();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001261 }
1262
Neil MacIntosh99746e22015-09-27 16:53:58 -07001263 // Make a stride vector from bounds, assuming contiguous memory.
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001264 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001265 constexpr std::enable_if_t<std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001266 {
1267 auto extents = bnd.index_bounds();
Anna Gringauzefdf86432015-10-14 10:46:22 -07001268 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001269
1270 stride[Bounds::rank - 1] = 1;
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001271 for (size_t i = 1; i < Bounds::rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -07001272 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001273 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
Anna Gringauzedb384972015-10-05 12:34:23 -07001274 }
1275 return{ stride };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001276 }
1277
1278 template <typename BoundsSrc, typename BoundsDest>
1279 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1280 {
1281 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1282 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1283 static_assert(BoundsDest::static_size == dynamic_range || BoundsSrc::static_size == dynamic_range || BoundsDest::static_size == BoundsSrc::static_size, "The source bounds must have same size as dest bounds");
1284 fail_fast_assert(src.size() == dest.size());
1285 }
1286
1287
1288} // namespace details
1289
1290template <typename ArrayView>
1291class contiguous_array_view_iterator;
1292template <typename ArrayView>
1293class general_array_view_iterator;
1294enum class byte : std::uint8_t {};
1295
1296template <typename ValueType, typename BoundsType>
1297class basic_array_view
1298{
1299public:
Kern Handae1570262015-09-25 00:42:38 -07001300 static const size_t rank = BoundsType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001301 using bounds_type = BoundsType;
1302 using size_type = typename bounds_type::size_type;
1303 using index_type = typename bounds_type::index_type;
1304 using value_type = ValueType;
1305 using pointer = ValueType*;
1306 using reference = ValueType&;
1307 using iterator = std::conditional_t<std::is_same<typename BoundsType::mapping_type, contiguous_mapping_tag>::value, contiguous_array_view_iterator<basic_array_view>, general_array_view_iterator<basic_array_view>>;
1308 using const_iterator = std::conditional_t<std::is_same<typename BoundsType::mapping_type, contiguous_mapping_tag>::value, contiguous_array_view_iterator<basic_array_view<const ValueType, BoundsType>>, general_array_view_iterator<basic_array_view<const ValueType, BoundsType>>>;
1309 using reverse_iterator = std::reverse_iterator<iterator>;
1310 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1311 using sliced_type = std::conditional_t<rank == 1, value_type, basic_array_view<value_type, typename BoundsType::sliced_type>>;
1312
1313private:
1314 pointer m_pdata;
1315 bounds_type m_bounds;
1316
1317public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001318 constexpr bounds_type bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001319 {
1320 return m_bounds;
1321 }
Kern Handae1570262015-09-25 00:42:38 -07001322 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001323 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001324 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001325 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001326 return m_bounds.template extent<Dim>();
1327 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001328 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001329 {
1330 return m_bounds.size();
1331 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001332 constexpr reference operator[](const index_type& idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001333 {
1334 return m_pdata[m_bounds.linearize(idx)];
1335 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001336 constexpr pointer data() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001337 {
1338 return m_pdata;
1339 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001340 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001341 constexpr Ret operator[](size_type idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001342 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001343 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001344 const size_type ridx = idx * m_bounds.stride();
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001345
1346 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001347 return Ret {m_pdata + ridx, m_bounds.slice()};
1348 }
1349
Neil MacIntoshd5316802015-09-30 21:54:08 -07001350 constexpr operator bool () const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001351 {
1352 return m_pdata != nullptr;
1353 }
1354
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001355 constexpr iterator begin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001356 {
1357 return iterator {this, true};
1358 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001359 constexpr iterator end() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001360 {
1361 return iterator {this};
1362 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001363 constexpr const_iterator cbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001364 {
1365 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), true};
1366 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001367 constexpr const_iterator cend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001368 {
1369 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this)};
1370 }
1371
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001372 constexpr reverse_iterator rbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001373 {
1374 return reverse_iterator {end()};
1375 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001376 constexpr reverse_iterator rend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001377 {
1378 return reverse_iterator {begin()};
1379 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001380 constexpr const_reverse_iterator crbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001381 {
1382 return const_reverse_iterator {cend()};
1383 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001384 constexpr const_reverse_iterator crend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001385 {
1386 return const_reverse_iterator {cbegin()};
1387 }
1388
1389 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001390 constexpr bool operator== (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001391 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001392 return m_bounds.size() == other.m_bounds.size() &&
1393 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001394 }
1395
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001396 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001397 constexpr bool operator!= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001398 {
1399 return !(*this == other);
1400 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001401
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001402 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001403 constexpr bool operator< (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001404 {
1405 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1406 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001407
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001408 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001409 constexpr bool operator<= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001410 {
1411 return !(other < *this);
1412 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001413
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001414 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001415 constexpr bool operator> (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001416 {
1417 return (other < *this);
1418 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001419
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001420 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001421 constexpr bool operator>= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001422 {
1423 return !(*this < other);
1424 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001425
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001426public:
1427 template <typename OtherValueType, typename OtherBounds,
1428 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value
1429 && std::is_convertible<OtherBounds, bounds_type>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001430 constexpr basic_array_view(const basic_array_view<OtherValueType, OtherBounds> & other ) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001431 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
1432 {
1433 }
1434protected:
1435
Neil MacIntoshd5316802015-09-30 21:54:08 -07001436 constexpr basic_array_view(pointer data, bounds_type bound) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001437 : m_pdata(data)
1438 , m_bounds(std::move(bound))
1439 {
1440 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1441 }
1442 template <typename T>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001443 constexpr basic_array_view(T *data, std::enable_if_t<std::is_same<value_type, std::remove_all_extents_t<T>>::value, bounds_type> bound) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001444 : m_pdata(reinterpret_cast<pointer>(data))
1445 , m_bounds(std::move(bound))
1446 {
1447 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1448 }
1449 template <typename DestBounds>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001450 constexpr basic_array_view<value_type, DestBounds> as_array_view(const DestBounds &bounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001451 {
1452 details::verifyBoundsReshape(m_bounds, bounds);
1453 return {m_pdata, bounds};
1454 }
1455private:
1456
1457 friend iterator;
1458 friend const_iterator;
1459 template <typename ValueType2, typename BoundsType2>
1460 friend class basic_array_view;
1461};
1462
1463template <size_t DimSize = dynamic_range>
1464struct dim
1465{
1466 static const size_t value = DimSize;
1467};
1468template <>
1469struct dim<dynamic_range>
1470{
1471 static const size_t value = dynamic_range;
1472 const size_t dvalue;
1473 dim(size_t size) : dvalue(size) {}
1474};
1475
1476template <typename ValueTypeOpt, size_t FirstDimension = dynamic_range, size_t... RestDimensions>
1477class array_view;
Kern Handae1570262015-09-25 00:42:38 -07001478template <typename ValueTypeOpt, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001479class strided_array_view;
1480
1481namespace details
1482{
1483 template <typename T, typename = std::true_type>
1484 struct ArrayViewTypeTraits
1485 {
1486 using value_type = T;
1487 using size_type = size_t;
1488 };
1489
1490 template <typename Traits>
1491 struct ArrayViewTypeTraits<Traits, typename std::is_reference<typename Traits::array_view_traits &>::type>
1492 {
1493 using value_type = typename Traits::array_view_traits::value_type;
1494 using size_type = typename Traits::array_view_traits::size_type;
1495 };
1496
1497 template <typename T, typename SizeType, size_t... Ranks>
1498 struct ArrayViewArrayTraits {
1499 using type = array_view<T, Ranks...>;
1500 using value_type = T;
1501 using bounds_type = static_bounds<SizeType, Ranks...>;
1502 using pointer = T*;
1503 using reference = T&;
1504 };
1505 template <typename T, typename SizeType, size_t N, size_t... Ranks>
1506 struct ArrayViewArrayTraits<T[N], SizeType, Ranks...> : ArrayViewArrayTraits<T, SizeType, Ranks..., N> {};
1507
1508 template <typename BoundsType>
1509 BoundsType newBoundsHelperImpl(size_t totalSize, std::true_type) // dynamic size
1510 {
1511 fail_fast_assert(totalSize <= details::SizeTypeTraits<typename BoundsType::size_type>::max_value);
1512 return BoundsType{static_cast<typename BoundsType::size_type>(totalSize)};
1513 }
1514 template <typename BoundsType>
1515 BoundsType newBoundsHelperImpl(size_t totalSize, std::false_type) // static size
1516 {
1517 fail_fast_assert(BoundsType::static_size == totalSize);
1518 return {};
1519 }
1520 template <typename BoundsType>
1521 BoundsType newBoundsHelper(size_t totalSize)
1522 {
1523 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1524 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1525 }
1526
1527 struct Sep{};
1528
1529 template <typename T, typename... Args>
1530 T static_as_array_view_helper(Sep, Args... args)
1531 {
1532 return T{static_cast<typename T::size_type>(args)...};
1533 }
1534 template <typename T, typename Arg, typename... Args>
1535 std::enable_if_t<!std::is_same<Arg, dim<dynamic_range>>::value && !std::is_same<Arg, Sep>::value, T> static_as_array_view_helper(Arg, Args... args)
1536 {
1537 return static_as_array_view_helper<T>(args...);
1538 }
1539 template <typename T, typename... Args>
1540 T static_as_array_view_helper(dim<dynamic_range> val, Args ... args)
1541 {
1542 return static_as_array_view_helper<T>(args..., val.dvalue);
1543 }
1544
1545 template <typename SizeType, typename ...Dimensions>
1546 struct static_as_array_view_static_bounds_helper
1547 {
1548 using type = static_bounds<SizeType, (Dimensions::value)...>;
1549 };
1550
1551 template <typename T>
1552 struct is_array_view_oracle : std::false_type
1553 {};
1554 template <typename ValueType, size_t FirstDimension, size_t... RestDimensions>
1555 struct is_array_view_oracle<array_view<ValueType, FirstDimension, RestDimensions...>> : std::true_type
1556 {};
Kern Handae1570262015-09-25 00:42:38 -07001557 template <typename ValueType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001558 struct is_array_view_oracle<strided_array_view<ValueType, Rank>> : std::true_type
1559 {};
1560 template <typename T>
1561 struct is_array_view : is_array_view_oracle<std::remove_cv_t<T>>
1562 {};
1563
1564}
1565
1566
1567template <typename ValueType, typename SizeType>
1568struct array_view_options
1569{
1570 struct array_view_traits
1571 {
1572 using value_type = ValueType;
1573 using size_type = SizeType;
1574 };
1575};
1576
1577template <typename ValueTypeOpt, size_t FirstDimension, size_t... RestDimensions>
1578class array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
1579 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>
1580{
1581 template <typename ValueTypeOpt2, size_t FirstDimension2, size_t... RestDimensions2>
1582 friend class array_view;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001583 using Base = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001584 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001585
1586public:
1587 using typename Base::bounds_type;
1588 using typename Base::size_type;
1589 using typename Base::pointer;
1590 using typename Base::value_type;
1591 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001592 using typename Base::iterator;
1593 using typename Base::const_iterator;
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001594 using typename Base::reference;
Neil MacIntosh383dc502015-09-14 15:41:40 -07001595 using Base::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001596
1597public:
1598 // basic
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001599 constexpr array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001600 {
1601 }
1602
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001603 constexpr array_view(std::nullptr_t) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001604 {
1605 }
1606
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001607 constexpr array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001608 {
1609 fail_fast_assert(size == 0);
1610 }
1611
1612 // default
1613 template <size_t DynamicRank = bounds_type::dynamic_rank, typename Dummy = std::enable_if_t<DynamicRank != 0>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001614 constexpr array_view() : Base(nullptr, bounds_type())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001615 {
1616 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001617
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001618 // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
1619 template <typename T, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001620 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type (*)[], typename Base::value_type (*)[]>::value
1621 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001622 constexpr array_view(T * const & data, size_type size) : Base(data, typename Helper::bounds_type{size})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001623 {
1624 }
1625
1626 // from n-dimensions static array
1627 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, N>,
1628 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], typename Base::value_type(*)[]>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001629 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001630 constexpr array_view (T (&arr)[N]) : Base(arr, typename Helper::bounds_type())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001631 {
1632 }
1633
1634 // from n-dimensions static array with size
1635 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
1636 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], typename Base::value_type(*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001637 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value >>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001638 constexpr array_view(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{ size })
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001639 {
1640 fail_fast_assert(size <= N);
1641 }
1642
1643 // from std array
1644 template <size_t N, typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<size_type, N>, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001645 constexpr array_view (std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<size_type, N>())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001646 {
1647 }
1648
1649 template <size_t N, typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<size_type, N>, typename Base::bounds_type>::value && std::is_const<value_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001650 constexpr array_view (const std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<size_type, N>())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001651 {
1652 }
1653
1654
1655 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1656 template <typename Ptr,
1657 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
1658 && details::LessThan<Base::bounds_type::dynamic_rank, 2>::value>> // remove literal 0 case
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001659 constexpr array_view (pointer begin, Ptr end) : Base(begin, details::newBoundsHelper<typename Base::bounds_type>(static_cast<pointer>(end) - begin))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001660 {
1661 }
1662
1663 // from containers. It must has .size() and .data() two function signatures
1664 template <typename Cont, typename DataType = typename Cont::value_type, typename SizeType = typename Cont::size_type,
1665 typename Dummy = std::enable_if_t<!details::is_array_view<Cont>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001666 && std::is_convertible<DataType (*)[], typename Base::value_type (*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001667 && std::is_convertible<static_bounds<SizeType, dynamic_range>, typename Base::bounds_type>::value
1668 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001669 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001670 constexpr array_view (Cont& cont) : Base(static_cast<pointer>(cont.data()), details::newBoundsHelper<typename Base::bounds_type>(cont.size()))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001671 {
1672
1673 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001674
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001675 constexpr array_view(const array_view &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001676
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001677 // convertible
1678 template <typename OtherValueTypeOpt, size_t... OtherDimensions,
1679 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>,
1680 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type, OtherDimensions...>>,
1681 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1682 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001683 constexpr array_view(const array_view<OtherValueTypeOpt, OtherDimensions...> &av) : Base(static_cast<const typename array_view<OtherValueTypeOpt, OtherDimensions...>::Base &>(av)) {} // static_cast is required
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001684
1685 // reshape
1686 template <typename... Dimensions2>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001687 constexpr array_view<ValueTypeOpt, Dimensions2::value...> as_array_view(Dimensions2... dims)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001688 {
1689 static_assert(sizeof...(Dimensions2) > 0, "the target array_view must have at least one dimension.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001690 using BoundsType = typename array_view<ValueTypeOpt, (Dimensions2::value)...>::bounds_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001691 auto tobounds = details::static_as_array_view_helper<BoundsType>(dims..., details::Sep{});
1692 details::verifyBoundsReshape(this->bounds(), tobounds);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001693 return {this->data(), tobounds};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001694 }
1695
1696 // to bytes array
1697 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001698 constexpr auto as_bytes() const noexcept ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001699 array_view<array_view_options<const byte, size_type>, static_cast<size_t>(details::StaticSizeHelper<size_type, Base::bounds_type::static_size, sizeof(value_type)>::value)>
1700 {
1701 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001702 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001703 }
1704
1705 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001706 constexpr auto as_writeable_bytes() const noexcept ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001707 array_view<array_view_options<byte, size_type>, static_cast<size_t>(details::StaticSizeHelper<size_type, Base::bounds_type::static_size, sizeof(value_type)>::value)>
1708 {
1709 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001710 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001711 }
1712
Anna Gringauze18cd9802015-09-14 16:34:26 -07001713
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001714 // from bytes array
1715 template<typename U, bool IsByte = std::is_same<value_type, const byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001716 constexpr auto as_array_view() const noexcept -> array_view<const U, (Base::bounds_type::dynamic_rank == 0 ? Base::bounds_type::static_size / sizeof(U) : static_cast<size_type>(dynamic_range))>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001717 {
1718 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1719 "Target type must be standard layout and its size must match the byte array size");
1720 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001721 return { reinterpret_cast<const U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001722 }
1723
1724 template<typename U, bool IsByte = std::is_same<value_type, byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001725 constexpr auto as_array_view() const noexcept -> array_view<U, (Base::bounds_type::dynamic_rank == 0 ? Base::bounds_type::static_size / sizeof(U) : static_cast<size_type>(dynamic_range))>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001726 {
1727 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1728 "Target type must be standard layout and its size must match the byte array size");
1729 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001730 return { reinterpret_cast<U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001731 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001732
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001733 // section on linear space
1734 template<size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001735 constexpr array_view<ValueTypeOpt, Count> first() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001736 {
1737 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1738 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size()); // ensures we only check condition when needed
Anna Gringauze18cd9802015-09-14 16:34:26 -07001739 return { this->data(), Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001740 }
1741
Neil MacIntoshd5316802015-09-30 21:54:08 -07001742 constexpr array_view<ValueTypeOpt, dynamic_range> first(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001743 {
1744 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001745 return { this->data(), count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001746 }
1747
1748 template<size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001749 constexpr array_view<ValueTypeOpt, Count> last() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001750 {
1751 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1752 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001753 return { this->data() + this->size() - Count, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001754 }
1755
Neil MacIntoshd5316802015-09-30 21:54:08 -07001756 constexpr array_view<ValueTypeOpt, dynamic_range> last(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001757 {
1758 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001759 return { this->data() + this->size() - count, count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001760 }
1761
1762 template<size_t Offset, size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001763 constexpr array_view<ValueTypeOpt, Count> sub() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001764 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001765 static_assert(bounds_type::static_size == dynamic_range || ((Offset == 0 || Offset <= bounds_type::static_size) && Offset + Count <= bounds_type::static_size), "Index is out of bound");
1766 fail_fast_assert(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
Anna Gringauze18cd9802015-09-14 16:34:26 -07001767 return { this->data() + Offset, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001768 }
1769
Neil MacIntoshd5316802015-09-30 21:54:08 -07001770 constexpr array_view<ValueTypeOpt, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001771 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001772 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1773 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001774 }
1775
1776 // size
Neil MacIntoshd5316802015-09-30 21:54:08 -07001777 constexpr size_type length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001778 {
1779 return this->size();
1780 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001781 constexpr size_type used_length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001782 {
1783 return length();
1784 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001785 constexpr size_type bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001786 {
1787 return sizeof(value_type) * this->size();
1788 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001789 constexpr size_type used_bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001790 {
1791 return bytes();
1792 }
1793
1794 // section
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001795 constexpr strided_array_view<ValueTypeOpt, rank> section(index_type origin, index_type extents) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001796 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001797 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001798 return{ &this->operator[](origin), size, strided_bounds<rank, size_type> {extents, details::make_stride(Base::bounds())} };
1799 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001800
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001801 constexpr reference operator[](const index_type& idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001802 {
1803 return Base::operator[](idx);
1804 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001805
Anna Gringauze1a864982015-09-14 18:55:06 -07001806 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001807 constexpr array_view<ValueTypeOpt, RestDimensions...> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001808 {
1809 auto ret = Base::operator[](idx);
1810 return{ ret.data(), ret.bounds() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001811 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001812
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001813 using Base::operator==;
1814 using Base::operator!=;
1815 using Base::operator<;
1816 using Base::operator<=;
1817 using Base::operator>;
1818 using Base::operator>=;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001819};
1820
1821template <typename T, size_t... Dimensions>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001822constexpr auto as_array_view(T * const & ptr, dim<Dimensions>... args) -> array_view<std::remove_all_extents_t<T>, Dimensions...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001823{
1824 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), details::static_as_array_view_helper<static_bounds<size_t, Dimensions...>>(args..., details::Sep{})};
1825}
1826
1827template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001828constexpr auto as_array_view (T * arr, size_t len) -> typename details::ArrayViewArrayTraits<T, size_t, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001829{
1830 return {arr, len};
1831}
1832
1833template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001834constexpr auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits<T, size_t, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001835{
1836 return {arr};
1837}
1838
1839template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001840constexpr array_view<const T, N> as_array_view(const std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001841{
1842 return {arr};
1843}
1844
1845template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001846constexpr array_view<const T, N> as_array_view(const std::array<T, N> &&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001847
1848template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001849constexpr array_view<T, N> as_array_view(std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001850{
1851 return {arr};
1852}
1853
1854template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001855constexpr array_view<T, dynamic_range> as_array_view(T *begin, T *end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001856{
1857 return {begin, end};
1858}
1859
1860template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001861constexpr auto as_array_view(Cont &arr) -> std::enable_if_t<!details::is_array_view<std::decay_t<Cont>>::value,
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001862 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
1863{
1864 return {arr.data(), arr.size()};
1865}
1866
1867template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001868constexpr auto as_array_view(Cont &&arr) -> std::enable_if_t<!details::is_array_view<std::decay_t<Cont>>::value,
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001869 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
1870
Kern Handae1570262015-09-25 00:42:38 -07001871template <typename ValueTypeOpt, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001872class strided_array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>
1873{
1874 using Base = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001875
Kern Handae1570262015-09-25 00:42:38 -07001876 template<typename OtherValueOpt, size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001877 friend class strided_array_view;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001878public:
1879 using Base::rank;
1880 using typename Base::bounds_type;
1881 using typename Base::size_type;
1882 using typename Base::pointer;
1883 using typename Base::value_type;
1884 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001885 using typename Base::iterator;
1886 using typename Base::const_iterator;
Anna Gringauze9dac1782015-09-14 19:08:03 -07001887 using typename Base::reference;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001888
1889 // from static array of size N
1890 template<size_type N>
1891 strided_array_view(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds))
1892 {
1893 fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries");
1894 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001895
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001896 // from raw data
1897 strided_array_view(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001898 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001899 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001900 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001901
1902 // from array view
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001903 template <size_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001904 strided_array_view(array_view<ValueTypeOpt, Dimensions...> av, bounds_type bounds) : Base(av.data(), std::move(bounds))
1905 {
1906 fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries");
1907 }
1908
1909 // convertible
1910 template <typename OtherValueTypeOpt,
1911 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>,
1912 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type>>,
1913 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1914 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001915 constexpr strided_array_view(const strided_array_view<OtherValueTypeOpt, Rank> &av): Base(static_cast<const typename strided_array_view<OtherValueTypeOpt, Rank>::Base &>(av)) // static_cast is required
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001916 {
1917 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001918
1919 // convert from bytes
Anna Gringauze1a864982015-09-14 18:55:06 -07001920 template <typename OtherValueType>
1921 strided_array_view<typename std::enable_if<std::is_same<value_type, const byte>::value, OtherValueType>::type, rank> as_strided_array_view() const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001922 {
1923 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
1924 auto d = sizeof(OtherValueType) / sizeof(value_type);
1925
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001926 size_type size = this->bounds().total_size() / d;
1927 return{ (OtherValueType*)this->data(), size, bounds_type{ resize_extent(this->bounds().index_bounds(), d), resize_stride(this->bounds().strides(), d)} };
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001928 }
1929
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001930 strided_array_view section(index_type origin, index_type extents) const
1931 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001932 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001933 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}};
1934 }
1935
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001936 constexpr reference operator[](const index_type& idx) const
Anna Gringauze9dac1782015-09-14 19:08:03 -07001937 {
1938 return Base::operator[](idx);
1939 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001940
1941 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001942 constexpr strided_array_view<value_type, rank-1> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001943 {
1944 auto ret = Base::operator[](idx);
1945 return{ ret.data(), ret.bounds().total_size(), ret.bounds() };
1946 }
1947
1948private:
1949 static index_type resize_extent(const index_type& extent, size_t d)
1950 {
1951 fail_fast_assert(extent[rank - 1] >= d && (extent[rank-1] % d == 0), "The last dimension of the array needs to contain a multiple of new type elements");
1952
1953 index_type ret = extent;
1954 ret[rank - 1] /= d;
1955
1956 return ret;
1957 }
1958
1959 template <bool Enabled = (rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Kosov Eugene3402b922015-09-28 21:20:02 +03001960 static index_type resize_stride(const index_type& strides, size_t , void * = 0)
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001961 {
1962 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1963
1964 return strides;
1965 }
1966
1967 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
1968 static index_type resize_stride(const index_type& strides, size_t d)
1969 {
1970 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1971 fail_fast_assert(strides[rank - 2] >= d && (strides[rank - 2] % d == 0), "The strides must have contiguous chunks of memory that can contain a multiple of new type elements");
1972
Neil MacIntosh99746e22015-09-27 16:53:58 -07001973 for (size_t i = rank - 1; i > 0; --i)
1974 fail_fast_assert((strides[i-1] >= strides[i]) && (strides[i-1] % strides[i] == 0), "Only strided arrays with regular strides can be resized");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001975
1976 index_type ret = strides / d;
1977 ret[rank - 1] = 1;
1978
1979 return ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001980 }
1981};
1982
1983template <typename ArrayView>
1984class contiguous_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
1985{
1986 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
1987public:
1988 using typename Base::reference;
1989 using typename Base::pointer;
1990 using typename Base::difference_type;
1991private:
1992 template <typename ValueType, typename Bounds>
1993 friend class basic_array_view;
1994 pointer m_pdata;
1995 const ArrayView * m_validator;
1996 void validateThis() const
1997 {
Neil MacIntosh383dc502015-09-14 15:41:40 -07001998 fail_fast_assert(m_pdata >= m_validator->m_pdata && m_pdata < m_validator->m_pdata + m_validator->size(), "iterator is out of range of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001999 }
2000 contiguous_array_view_iterator (const ArrayView *container, bool isbegin = false) :
2001 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) { }
2002public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07002003 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002004 {
2005 validateThis();
2006 return *m_pdata;
2007 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002008 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002009 {
2010 validateThis();
2011 return m_pdata;
2012 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002013 contiguous_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002014 {
2015 ++m_pdata;
2016 return *this;
2017 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002018 contiguous_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002019 {
2020 auto ret = *this;
2021 ++(*this);
2022 return ret;
2023 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002024 contiguous_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002025 {
2026 --m_pdata;
2027 return *this;
2028 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002029 contiguous_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002030 {
2031 auto ret = *this;
2032 --(*this);
2033 return ret;
2034 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002035 contiguous_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002036 {
2037 contiguous_array_view_iterator ret{ *this };
2038 return ret += n;
2039 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002040 contiguous_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002041 {
2042 m_pdata += n;
2043 return *this;
2044 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002045 contiguous_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002046 {
2047 contiguous_array_view_iterator ret{ *this };
2048 return ret -= n;
2049 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002050 contiguous_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002051 {
2052 return *this += -n;
2053 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002054 difference_type operator-(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002055 {
2056 fail_fast_assert(m_validator == rhs.m_validator);
2057 return m_pdata - rhs.m_pdata;
2058 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002059 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002060 {
2061 return *(*this + n);
2062 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002063 bool operator==(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002064 {
2065 fail_fast_assert(m_validator == rhs.m_validator);
2066 return m_pdata == rhs.m_pdata;
2067 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002068 bool operator!=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002069 {
2070 return !(*this == rhs);
2071 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002072 bool operator<(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002073 {
2074 fail_fast_assert(m_validator == rhs.m_validator);
2075 return m_pdata < rhs.m_pdata;
2076 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002077 bool operator<=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002078 {
2079 return !(rhs < *this);
2080 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002081 bool operator>(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002082 {
2083 return rhs < *this;
2084 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002085 bool operator>=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002086 {
2087 return !(rhs > *this);
2088 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002089 void swap(contiguous_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002090 {
2091 std::swap(m_pdata, rhs.m_pdata);
2092 std::swap(m_validator, rhs.m_validator);
2093 }
2094};
2095
2096template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07002097contiguous_array_view_iterator<ArrayView> operator+(typename contiguous_array_view_iterator<ArrayView>::difference_type n, const contiguous_array_view_iterator<ArrayView>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002098{
2099 return rhs + n;
2100}
2101
2102template <typename ArrayView>
2103class general_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
2104{
2105 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
2106public:
2107 using typename Base::reference;
2108 using typename Base::pointer;
2109 using typename Base::difference_type;
2110 using typename Base::value_type;
2111private:
2112 template <typename ValueType, typename Bounds>
2113 friend class basic_array_view;
2114 const ArrayView * m_container;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07002115 typename ArrayView::bounds_type::iterator m_itr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002116 general_array_view_iterator(const ArrayView *container, bool isbegin = false) :
2117 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
2118 {
2119 }
2120public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07002121 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002122 {
2123 return (*m_container)[*m_itr];
2124 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002125 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002126 {
2127 return &(*m_container)[*m_itr];
2128 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002129 general_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002130 {
2131 ++m_itr;
2132 return *this;
2133 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002134 general_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002135 {
2136 auto ret = *this;
2137 ++(*this);
2138 return ret;
2139 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002140 general_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002141 {
2142 --m_itr;
2143 return *this;
2144 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002145 general_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002146 {
2147 auto ret = *this;
2148 --(*this);
2149 return ret;
2150 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002151 general_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002152 {
2153 general_array_view_iterator ret{ *this };
2154 return ret += n;
2155 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002156 general_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002157 {
2158 m_itr += n;
2159 return *this;
2160 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002161 general_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002162 {
2163 general_array_view_iterator ret{ *this };
2164 return ret -= n;
2165 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002166 general_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002167 {
2168 return *this += -n;
2169 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002170 difference_type operator-(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002171 {
2172 fail_fast_assert(m_container == rhs.m_container);
2173 return m_itr - rhs.m_itr;
2174 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002175 value_type operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002176 {
2177 return (*m_container)[m_itr[n]];;
2178 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002179 bool operator==(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002180 {
2181 fail_fast_assert(m_container == rhs.m_container);
2182 return m_itr == rhs.m_itr;
2183 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002184 bool operator !=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002185 {
2186 return !(*this == rhs);
2187 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002188 bool operator<(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002189 {
2190 fail_fast_assert(m_container == rhs.m_container);
2191 return m_itr < rhs.m_itr;
2192 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002193 bool operator<=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002194 {
2195 return !(rhs < *this);
2196 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002197 bool operator>(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002198 {
2199 return rhs < *this;
2200 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002201 bool operator>=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002202 {
2203 return !(rhs > *this);
2204 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002205 void swap(general_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002206 {
2207 std::swap(m_itr, rhs.m_itr);
2208 std::swap(m_container, rhs.m_container);
2209 }
2210};
2211
2212template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07002213general_array_view_iterator<ArrayView> operator+(typename general_array_view_iterator<ArrayView>::difference_type n, const general_array_view_iterator<ArrayView>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002214{
2215 return rhs + n;
2216}
2217
Neil MacIntoshef626fd2015-09-29 16:41:37 -07002218} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002219
Neil MacIntoshd5316802015-09-30 21:54:08 -07002220#ifdef _MSC_VER
2221
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002222#undef constexpr
2223#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002224
Neil MacIntoshd5316802015-09-30 21:54:08 -07002225#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002226#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07002227
2228#ifndef GSL_THROWS_FOR_TESTING
2229#pragma undef noexcept
2230#endif // GSL_THROWS_FOR_TESTING
2231
Neil MacIntosh9a297122015-09-14 15:11:07 -07002232#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002233
Neil MacIntoshd5316802015-09-30 21:54:08 -07002234#endif // _MSC_VER
2235
2236#if defined(GSL_THROWS_FOR_TESTING)
2237#undef noexcept
2238#endif // GSL_THROWS_FOR_TESTING
2239
Treb Connell51da1362015-09-24 18:08:34 -07002240
2241#endif // GSL_ARRAY_VIEW_H