blob: fb103c9f3a3242f864fdc6df7e2dea9c0c96bb38 [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
19#include <new>
20#include <stdexcept>
21#include <cstddef>
22#include <cstdint>
23#include <limits>
24#include <type_traits>
25#include <utility>
26#include <array>
27#include <iterator>
28#include "fail_fast.h"
29
30#ifndef _MSC_VER
31#define _CONSTEXPR constexpr
32#else
33#define _CONSTEXPR
34#endif
35
36#pragma push_macro("_NOEXCEPT")
37
38#ifndef _NOEXCEPT
39
40#ifdef SAFER_CPP_TESTING
41#define _NOEXCEPT
42#else
43#define _NOEXCEPT noexcept
44#endif
45
46#else // _NOEXCEPT
47
48#ifdef SAFER_CPP_TESTING
49#undef _NOEXCEPT
50#define _NOEXCEPT
51#endif
52
53#endif // _NOEXCEPT
54
galikcab9bda2015-09-19 07:52:30 +010055#if _MSC_VER
Neil MacIntosh9a297122015-09-14 15:11:07 -070056#if _MSC_VER <= 1800
57#pragma warning(push)
58#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
59#endif // _MSC_VER <= 1800
galikcab9bda2015-09-19 07:52:30 +010060#endif
Neil MacIntosh9a297122015-09-14 15:11:07 -070061
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070062namespace Guide {
63
64/*
65** begin definitions of index and bounds
66*/
67namespace details
68{
69 template <typename SizeType>
70 struct SizeTypeTraits
71 {
72 static const size_t max_value = std::is_signed<SizeType>::value ? static_cast<typename std::make_unsigned<SizeType>::type>(-1) / 2 : static_cast<SizeType>(-1);
73 };
74
75
76 template <typename ConcreteType, typename ValueType, unsigned int Rank>
77 class coordinate_facade
78 {
79 static_assert(std::is_integral<ValueType>::value
80 && sizeof(ValueType) <= sizeof(size_t), "ValueType must be unsigned integral type!");
81 static_assert(Rank > 0, "Rank must be greater than 0!");
82
83 template <typename OtherConcreteType, typename OtherValueType, unsigned int OtherRank>
84 friend class coordinate_facade;
85 public:
86 using reference = ValueType&;
87 using const_reference = const ValueType&;
88 using value_type = ValueType;
89 static const unsigned int rank = Rank;
90 _CONSTEXPR coordinate_facade() _NOEXCEPT
91 {
92 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -070093 }
94 _CONSTEXPR coordinate_facade(const value_type(&values)[rank]) _NOEXCEPT
95 {
96 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070097 for (unsigned int i = 0; i < rank; ++i)
Anna Gringauze17ed5c32015-08-30 23:30:15 -070098 elems[i] = values[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070099 }
100 _CONSTEXPR coordinate_facade(value_type e0) _NOEXCEPT
101 {
102 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
103 static_assert(rank == 1, "This constructor can only be used with rank == 1.");
104 elems[0] = e0;
105 }
106 // Preconditions: il.size() == rank
107 _CONSTEXPR coordinate_facade(std::initializer_list<value_type> il)
108 {
109 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700110 fail_fast_assert(il.size() == rank, "The size of the initializer list must match the rank of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700111 for (unsigned int i = 0; i < rank; ++i)
112 {
113 elems[i] = begin(il)[i];
114 }
115 }
116
117 _CONSTEXPR coordinate_facade(const coordinate_facade & other) = default;
118
119 template <typename OtherConcreteType, typename OtherValueType>
120 _CONSTEXPR coordinate_facade(const coordinate_facade<OtherConcreteType, OtherValueType, Rank> & other)
121 {
122 for (unsigned int i = 0; i < rank; ++i)
123 {
124 fail_fast_assert(static_cast<size_t>(other.elems[i]) <= SizeTypeTraits<value_type>::max_value);
125 elems[i] = static_cast<value_type>(other.elems[i]);
126 }
127 }
128 protected:
129 coordinate_facade& operator=(const coordinate_facade& rhs) = default;
130 // Preconditions: component_idx < rank
131 _CONSTEXPR reference operator[](unsigned int component_idx)
132 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700133 fail_fast_assert(component_idx < rank, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700134 return elems[component_idx];
135 }
136 // Preconditions: component_idx < rank
137 _CONSTEXPR const_reference operator[](unsigned int component_idx) const
138 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700139 fail_fast_assert(component_idx < rank, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700140 return elems[component_idx];
141 }
142 _CONSTEXPR bool operator==(const ConcreteType& rhs) const _NOEXCEPT
143 {
144 for (unsigned int i = 0; i < rank; ++i)
145 {
146 if (elems[i] != rhs.elems[i])
147 return false;
148 }
149 return true;
150 }
151 _CONSTEXPR bool operator!=(const ConcreteType& rhs) const _NOEXCEPT
152 {
153 return !(to_concrete() == rhs);
154 }
155 _CONSTEXPR ConcreteType operator+() const _NOEXCEPT
156 {
157 return to_concrete();
158 }
159 _CONSTEXPR ConcreteType operator-() const
160 {
161 ConcreteType ret = to_concrete();
162 for (unsigned int i = 0; i < rank; ++i)
163 ret.elems[i] = -ret.elems[i];
164 return ret;
165 }
166 _CONSTEXPR ConcreteType operator+(const ConcreteType& rhs) const
167 {
168 ConcreteType ret = to_concrete();
169 ret += rhs;
170 return ret;
171 }
172 _CONSTEXPR ConcreteType operator-(const ConcreteType& rhs) const
173 {
174 ConcreteType ret = to_concrete();
175 ret -= rhs;
176 return ret;
177 }
178 _CONSTEXPR ConcreteType& operator+=(const ConcreteType& rhs)
179 {
180 for (unsigned int i = 0; i < rank; ++i)
181 elems[i] += rhs.elems[i];
182 return to_concrete();
183 }
184 _CONSTEXPR ConcreteType& operator-=(const ConcreteType& rhs)
185 {
186 for (unsigned int i = 0; i < rank; ++i)
187 elems[i] -= rhs.elems[i];
188 return to_concrete();
189 }
190 _CONSTEXPR ConcreteType& operator++()
191 {
192 static_assert(rank == 1, "This operator can only be used with rank == 1.");
193 ++elems[0];
194 return to_concrete();
195 }
196 _CONSTEXPR ConcreteType operator++(int)
197 {
198 static_assert(rank == 1, "This operator can only be used with rank == 1.");
199 ConcreteType ret = to_concrete();
200 ++(*this);
201 return ret;
202 }
203 _CONSTEXPR ConcreteType& operator--()
204 {
205 static_assert(rank == 1, "This operator can only be used with rank == 1.");
206 --elems[0];
207 return to_concrete();
208 }
209 _CONSTEXPR ConcreteType operator--(int)
210 {
211 static_assert(rank == 1, "This operator can only be used with rank == 1.");
212 ConcreteType ret = to_concrete();
213 --(*this);
214 return ret;
215 }
216 _CONSTEXPR ConcreteType operator*(value_type v) const
217 {
218 ConcreteType ret = to_concrete();
219 ret *= v;
220 return ret;
221 }
222 _CONSTEXPR ConcreteType operator/(value_type v) const
223 {
224 ConcreteType ret = to_concrete();
225 ret /= v;
226 return ret;
227 }
228 friend _CONSTEXPR ConcreteType operator*(value_type v, const ConcreteType& rhs)
229 {
230 return rhs * v;
231 }
232 _CONSTEXPR ConcreteType& operator*=(value_type v)
233 {
234 for (unsigned int i = 0; i < rank; ++i)
235 elems[i] *= v;
236 return to_concrete();
237 }
238 _CONSTEXPR ConcreteType& operator/=(value_type v)
239 {
240 for (unsigned int i = 0; i < rank; ++i)
241 elems[i] /= v;
242 return to_concrete();
243 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700244 value_type elems[rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700245 private:
246 _CONSTEXPR const ConcreteType& to_concrete() const _NOEXCEPT
247 {
248 return static_cast<const ConcreteType&>(*this);
249 }
250 _CONSTEXPR ConcreteType& to_concrete() _NOEXCEPT
251 {
252 return static_cast<ConcreteType&>(*this);
253 }
254 };
255 template <typename T>
256 class arrow_proxy
257 {
258 public:
259 explicit arrow_proxy(T t)
260 : val(t)
261 {}
262 const T operator*() const _NOEXCEPT
263 {
264 return val;
265 }
266 const T* operator->() const _NOEXCEPT
267 {
268 return &val;
269 }
270 private:
271 T val;
272 };
273}
274
275template <unsigned int Rank, typename ValueType = size_t>
276class index : private details::coordinate_facade<index<Rank, ValueType>, ValueType, Rank>
277{
278 using Base = details::coordinate_facade<index<Rank, ValueType>, ValueType, Rank>;
279 friend Base;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700280 template <unsigned int OtherRank, typename OtherValueType>
281 friend class index;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700282public:
283 using Base::rank;
284 using reference = typename Base::reference;
285 using const_reference = typename Base::const_reference;
286 using size_type = typename Base::value_type;
287 using value_type = typename Base::value_type;
288 _CONSTEXPR index() _NOEXCEPT : Base(){}
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700289 _CONSTEXPR index(const value_type (&values)[rank]) _NOEXCEPT : Base(values) {}
290 _CONSTEXPR index(std::initializer_list<value_type> il) : Base(il) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700291
292 _CONSTEXPR index(const index &) = default;
293
294 template <typename OtherValueType>
295 _CONSTEXPR index(const index<Rank, OtherValueType> &other) : Base(other)
296 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700297 }
298 _CONSTEXPR static index shift_left(const index<rank+1, value_type>& other) _NOEXCEPT
299 {
Anna Gringauze1a864982015-09-14 18:55:06 -0700300 value_type (&arr)[rank] = (value_type(&)[rank])(*(other.elems + 1));
301 return index(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700302 }
303
304 using Base::operator[];
305 using Base::operator==;
306 using Base::operator!=;
307 using Base::operator+;
308 using Base::operator-;
309 using Base::operator+=;
310 using Base::operator-=;
311 using Base::operator++;
312 using Base::operator--;
313 using Base::operator*;
314 using Base::operator/;
315 using Base::operator*=;
316 using Base::operator/=;
317};
318
319template <typename ValueType>
320class index<1, ValueType>
321{
322 template <unsigned int, typename OtherValueType>
323 friend class index;
324public:
325 static const unsigned int rank = 1;
326 using reference = ValueType&;
327 using const_reference = const ValueType&;
328 using size_type = ValueType;
329 using value_type = ValueType;
330
331 _CONSTEXPR index() _NOEXCEPT : value(0)
332 {
333 }
334 _CONSTEXPR index(value_type e0) _NOEXCEPT : value(e0)
335 {
336 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700337 _CONSTEXPR index(const value_type(&values)[1]) _NOEXCEPT : index(values[0])
338 {
339 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700340 // Preconditions: il.size() == rank
341 _CONSTEXPR index(std::initializer_list<value_type> il)
342 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700343 fail_fast_assert(il.size() == rank, "Size of the initializer list must match the rank of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700344 value = begin(il)[0];
345 }
346
347 _CONSTEXPR index(const index &) = default;
348
349 template <typename OtherValueType>
350 _CONSTEXPR index(const index<1, OtherValueType> & other)
351 {
352 fail_fast_assert(other.value <= details::SizeTypeTraits<ValueType>::max_value);
353 value = static_cast<ValueType>(other.value);
354 }
355
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700356 _CONSTEXPR static index shift_left(const index<rank + 1, value_type>& other) _NOEXCEPT
357 {
358 return other.elems[1];
359 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700360 // Preconditions: component_idx < rank
361 _CONSTEXPR reference operator[](size_type component_idx) _NOEXCEPT
362 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700363 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700364 (void)(component_idx);
365 return value;
366 }
367 // Preconditions: component_idx < rank
368 _CONSTEXPR const_reference operator[](size_type component_idx) const _NOEXCEPT
369 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700370 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700371 (void)(component_idx);
372 return value;
373 }
374 _CONSTEXPR bool operator==(const index& rhs) const _NOEXCEPT
375 {
376 return value == rhs.value;
377 }
378 _CONSTEXPR bool operator!=(const index& rhs) const _NOEXCEPT
379 {
380 return !(*this == rhs);
381 }
382 _CONSTEXPR index operator+() const _NOEXCEPT
383 {
384 return *this;
385 }
386 _CONSTEXPR index operator-() const _NOEXCEPT
387 {
388 return index(-value);
389 }
390 _CONSTEXPR index operator+(const index& rhs) const _NOEXCEPT
391 {
392 return index(value + rhs.value);
393 }
394 _CONSTEXPR index operator-(const index& rhs) const _NOEXCEPT
395 {
396 return index(value - rhs.value);
397 }
398 _CONSTEXPR index& operator+=(const index& rhs) _NOEXCEPT
399 {
400 value += rhs.value;
401 return *this;
402 }
403 _CONSTEXPR index& operator-=(const index& rhs) _NOEXCEPT
404 {
405 value -= rhs.value;
406 return *this;
407 }
408 _CONSTEXPR index& operator++() _NOEXCEPT
409 {
410 ++value;
411 return *this;
412 }
413 _CONSTEXPR index operator++(int) _NOEXCEPT
414 {
415 index ret = *this;
416 ++(*this);
417 return ret;
418 }
419 _CONSTEXPR index& operator--() _NOEXCEPT
420 {
421 --value;
422 return *this;
423 }
424 _CONSTEXPR index operator--(int) _NOEXCEPT
425 {
426 index ret = *this;
427 --(*this);
428 return ret;
429 }
430 _CONSTEXPR index operator*(value_type v) const _NOEXCEPT
431 {
432 return index(value * v);
433 }
434 _CONSTEXPR index operator/(value_type v) const _NOEXCEPT
435 {
436 return index(value / v);
437 }
438 _CONSTEXPR index& operator*=(value_type v) _NOEXCEPT
439 {
440 value *= v;
441 return *this;
442 }
443 _CONSTEXPR index& operator/=(value_type v) _NOEXCEPT
444 {
445 value /= v;
446 return *this;
447 }
448 friend _CONSTEXPR index operator*(value_type v, const index& rhs) _NOEXCEPT
449 {
450 return index(rhs * v);
451 }
452private:
453 value_type value;
454};
455
456#ifndef _MSC_VER
457
458struct static_bounds_dynamic_range_t
459{
460 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
461 constexpr operator T() const noexcept
462 {
463 return static_cast<T>(-1);
464 }
465
466 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
467 constexpr bool operator ==(T other) const noexcept
468 {
469 return static_cast<T>(-1) == other;
470 }
471
472 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
473 constexpr bool operator !=(T other) const noexcept
474 {
475 return static_cast<T>(-1) != other;
476 }
477
478};
479
480template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
481constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
482{
483 return right == left;
484}
485
486template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
487constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
488{
489 return right != left;
490}
491
492constexpr static_bounds_dynamic_range_t dynamic_range{};
493#else
494const char dynamic_range = -1;
495#endif
496
497struct generalized_mapping_tag {};
498struct contiguous_mapping_tag : generalized_mapping_tag {};
499
500namespace details
501{
502 template <typename SizeType, SizeType Fact1, SizeType Fact2, SizeType ConstBound>
503 struct StaticSizeHelperImpl
504 {
505 static_assert(static_cast<size_t>(Fact1) * static_cast<size_t>(Fact2) <= SizeTypeTraits<SizeType>::max_value, "Value out of the range of SizeType");
506 static const SizeType value = Fact1 * Fact2;
507 };
508
509 template <typename SizeType, SizeType Fact1, SizeType ConstBound>
510 struct StaticSizeHelperImpl<SizeType, Fact1, ConstBound, ConstBound>
511 {
512 static const SizeType value = ConstBound;
513 };
514
515 template <typename SizeType, SizeType Fact2, SizeType ConstBound>
516 struct StaticSizeHelperImpl<SizeType, ConstBound, Fact2, ConstBound>
517 {
518 static const SizeType value = ConstBound;
519 };
520
521 template <typename SizeType, SizeType ConstBound>
522 struct StaticSizeHelperImpl<SizeType, ConstBound, ConstBound, ConstBound>
523 {
524 static const SizeType value = static_cast<SizeType>(ConstBound);
525 };
526
527 template <typename SizeType, SizeType Fact1, SizeType Fact2>
528 struct StaticSizeHelper
529 {
530 static const SizeType value = StaticSizeHelperImpl<SizeType, static_cast<SizeType>(Fact1), static_cast<SizeType>(Fact2), static_cast<SizeType>(dynamic_range)>::value;
531 };
532
533
534 template <size_t Left, size_t Right>
535 struct LessThan
536 {
537 static const bool value = Left < Right;
538 };
539
540 template <typename SizeType, size_t... Ranges>
541 struct BoundsRanges {
542 static const unsigned int Depth = 0;
543 static const unsigned int DynamicNum = 0;
544 static const SizeType CurrentRange = 1;
545 static const SizeType TotalSize = 1;
546
547 BoundsRanges (const BoundsRanges &) = default;
548
549 // TODO : following signature is for work around VS bug
550 template <typename OtherType>
551 BoundsRanges (const OtherType &, bool firstLevel) {}
galikcab9bda2015-09-19 07:52:30 +0100552 BoundsRanges(const SizeType * const) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700553 BoundsRanges() = default;
554
555
556 template <typename T, unsigned int Dim>
557 void serialize(T &) const {
558 }
559 template <typename T, unsigned int Dim>
560 SizeType linearize(const T &) const {
561 return 0;
562 }
563 template <typename T, unsigned int Dim>
564 ptrdiff_t contains(const T &) const {
565 return 0;
566 }
567
568 size_t totalSize() const _NOEXCEPT {
569 return TotalSize;
570 }
571
572 bool operator == (const BoundsRanges &) const _NOEXCEPT
573 {
574 return true;
575 }
576 };
577
578 template <typename SizeType, size_t... RestRanges>
579 struct BoundsRanges <SizeType, dynamic_range, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
580 using Base = BoundsRanges <SizeType, RestRanges... >;
581 static const unsigned int Depth = Base::Depth + 1;
582 static const unsigned int DynamicNum = Base::DynamicNum + 1;
583 static const SizeType CurrentRange = dynamic_range;
584 static const SizeType TotalSize = dynamic_range;
585 const SizeType m_bound;
586
587 BoundsRanges (const BoundsRanges &) = default;
588 BoundsRanges(const SizeType * const arr) : Base(arr + 1), m_bound(static_cast<SizeType>(*arr * this->Base::totalSize()))
589 {
590 fail_fast_assert(0 <= *arr);
591 fail_fast_assert(*arr * this->Base::totalSize() <= details::SizeTypeTraits<SizeType>::max_value);
592 }
593 BoundsRanges() : m_bound(0) {}
594
595 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
596 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool firstLevel = true) :
597 Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false), m_bound (static_cast<SizeType>(other.totalSize()))
598 {
599 }
600
601 template <typename T, unsigned int Dim = 0>
602 void serialize(T & arr) const {
603 arr[Dim] = elementNum();
604 this->Base::template serialize<T, Dim + 1>(arr);
605 }
606 template <typename T, unsigned int Dim = 0>
607 SizeType linearize(const T & arr) const {
608 const size_t index = this->Base::totalSize() * arr[Dim];
609 fail_fast_assert(index < static_cast<size_t>(m_bound));
610 return static_cast<SizeType>(index) + this->Base::template linearize<T, Dim + 1>(arr);
611 }
612
613 template <typename T, unsigned int Dim = 0>
614 ptrdiff_t contains(const T & arr) const {
615 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
616 if (last == -1)
617 return -1;
618 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
619 return static_cast<size_t>(cur) < static_cast<size_t>(m_bound) ? cur + last : -1;
620 }
621
622 size_t totalSize() const _NOEXCEPT {
623 return m_bound;
624 }
625
626 SizeType elementNum() const _NOEXCEPT {
627 return static_cast<SizeType>(totalSize() / this->Base::totalSize());
628 }
629
630 SizeType elementNum(unsigned int dim) const _NOEXCEPT{
631 if (dim > 0)
632 return this->Base::elementNum(dim - 1);
633 else
634 return elementNum();
635 }
636
637 bool operator == (const BoundsRanges & rhs) const _NOEXCEPT
638 {
639 return m_bound == rhs.m_bound && static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
640 }
641 };
642
643 template <typename SizeType, size_t CurRange, size_t... RestRanges>
644 struct BoundsRanges <SizeType, CurRange, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
645 using Base = BoundsRanges <SizeType, RestRanges... >;
646 static const unsigned int Depth = Base::Depth + 1;
647 static const unsigned int DynamicNum = Base::DynamicNum;
648 static const SizeType CurrentRange = static_cast<SizeType>(CurRange);
649 static const SizeType TotalSize = StaticSizeHelper<SizeType, Base::TotalSize, CurrentRange>::value;
650 static_assert (CurRange <= SizeTypeTraits<SizeType>::max_value, "CurRange must be smaller than SizeType limits");
651
652 BoundsRanges (const BoundsRanges &) = default;
653 BoundsRanges(const SizeType * const arr) : Base(arr) { }
654 BoundsRanges() = default;
655
656 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
657 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false)
658 {
659 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
660 }
661
662 template <typename T, unsigned int Dim = 0>
663 void serialize(T & arr) const {
664 arr[Dim] = elementNum();
665 this->Base::template serialize<T, Dim + 1>(arr);
666 }
667
668 template <typename T, unsigned int Dim = 0>
669 SizeType linearize(const T & arr) const {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700670 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700671 return static_cast<SizeType>(this->Base::totalSize()) * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
672 }
673
674 template <typename T, unsigned int Dim = 0>
675 ptrdiff_t contains(const T & arr) const {
676 if (static_cast<size_t>(arr[Dim]) >= CurrentRange)
677 return -1;
678 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
679 if (last == -1)
680 return -1;
681 return static_cast<ptrdiff_t>(this->Base::totalSize() * arr[Dim]) + last;
682 }
683
684 size_t totalSize() const _NOEXCEPT{
685 return CurrentRange * this->Base::totalSize();
686 }
687
688 SizeType elementNum() const _NOEXCEPT{
689 return CurrentRange;
690 }
691
692 SizeType elementNum(unsigned int dim) const _NOEXCEPT{
693 if (dim > 0)
694 return this->Base::elementNum(dim - 1);
695 else
696 return elementNum();
697 }
698
699 bool operator == (const BoundsRanges & rhs) const _NOEXCEPT
700 {
701 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
702 }
703 };
704
705 template <typename SourceType, typename TargetType, size_t Rank>
706 struct BoundsRangeConvertible2;
707
708 // TODO: I have to rewrite BoundsRangeConvertible into following way to workaround VS 2013 bugs
709 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
710 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
711
712 template <size_t Rank, typename SourceType, typename TargetType>
713 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
714
715 template <typename SourceType, typename TargetType, size_t Rank>
716 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
717 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
718 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
719 {};
720
721 template <typename SourceType, typename TargetType>
722 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
723
724 template <typename SourceType, typename TargetType, size_t Rank = TargetType::Depth>
725 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
726 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
727 && (!LessThan<size_t(SourceType::CurrentRange), size_t(TargetType::CurrentRange)>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
728 {};
729 template <typename SourceType, typename TargetType>
730 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
731
732 template <typename TypeChain>
733 struct TypeListIndexer
734 {
735 const TypeChain & obj;
736 TypeListIndexer(const TypeChain & obj) :obj(obj){}
737 template<unsigned int N>
738 const TypeChain & getObj(std::true_type)
739 {
740 return obj;
741 }
742 template<unsigned int N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
743 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
744 {
745 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
746 }
747 template <unsigned int N>
748 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
749 {
750 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
751 }
752 };
753
754 template <typename TypeChain>
755 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
756 {
757 return TypeListIndexer<TypeChain>(obj);
758 }
759}
760
761template <typename IndexType>
762class bounds_iterator;
763
764template <typename SizeType, size_t... Ranges>
765class static_bounds {
766public:
767 static_bounds(const details::BoundsRanges<SizeType, Ranges...> &empty) {
768 }
769};
770
771template <typename SizeType, size_t FirstRange, size_t... RestRanges>
772class static_bounds<SizeType, FirstRange, RestRanges...>
773{
774 using MyRanges = details::BoundsRanges <SizeType, FirstRange, RestRanges... >;
775 static_assert(std::is_integral<SizeType>::value
776 && details::SizeTypeTraits<SizeType>::max_value <= SIZE_MAX, "SizeType must be an integral type and its numeric limits must be smaller than SIZE_MAX");
777
778 MyRanges m_ranges;
779 _CONSTEXPR static_bounds(const MyRanges & range) : m_ranges(range) { }
780
781 template <typename SizeType2, size_t... Ranges2>
782 friend class static_bounds;
783public:
784 static const unsigned int rank = MyRanges::Depth;
785 static const unsigned int dynamic_rank = MyRanges::DynamicNum;
786 static const SizeType static_size = static_cast<SizeType>(MyRanges::TotalSize);
787
788 using size_type = SizeType;
789 using index_type = index<rank, size_type>;
790 using iterator = bounds_iterator<index_type>;
791 using const_iterator = bounds_iterator<index_type>;
792 using difference_type = ptrdiff_t;
793 using sliced_type = static_bounds<SizeType, RestRanges...>;
794 using mapping_type = contiguous_mapping_tag;
795public:
796 _CONSTEXPR static_bounds(const static_bounds &) = default;
797
798 template <typename OtherSizeType, size_t... Ranges, typename Dummy = std::enable_if_t<
799 details::BoundsRangeConvertible<details::BoundsRanges<OtherSizeType, Ranges...>, details::BoundsRanges <SizeType, FirstRange, RestRanges... >>::value>>
800 _CONSTEXPR static_bounds(const static_bounds<OtherSizeType, Ranges...> &other):
801 m_ranges(other.m_ranges)
802 {
803 }
804
805 _CONSTEXPR static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin())
806 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700807 fail_fast_assert(MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
808 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 -0700809 }
810
811 _CONSTEXPR static_bounds() = default;
812
813 _CONSTEXPR static_bounds & operator = (const static_bounds & otherBounds)
814 {
815 new(&m_ranges) MyRanges (otherBounds.m_ranges);
816 return *this;
817 }
818
819 _CONSTEXPR sliced_type slice() const _NOEXCEPT
820 {
821 return sliced_type{static_cast<const details::BoundsRanges<SizeType, RestRanges...> &>(m_ranges)};
822 }
823
824 _CONSTEXPR size_type stride() const _NOEXCEPT
825 {
826 return rank > 1 ? slice().size() : 1;
827 }
828
829 _CONSTEXPR size_type size() const _NOEXCEPT
830 {
831 return static_cast<size_type>(m_ranges.totalSize());
832 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700833
834 _CONSTEXPR size_type total_size() const _NOEXCEPT
835 {
836 return static_cast<size_type>(m_ranges.totalSize());
837 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700838
839 _CONSTEXPR size_type linearize(const index_type & idx) const
840 {
841 return m_ranges.linearize(idx);
842 }
843
844 _CONSTEXPR bool contains(const index_type& idx) const _NOEXCEPT
845 {
846 return m_ranges.contains(idx) != -1;
847 }
848
849 _CONSTEXPR size_type operator[](unsigned int index) const _NOEXCEPT
850 {
851 return m_ranges.elementNum(index);
852 }
853
854 template <unsigned int Dim = 0>
855 _CONSTEXPR size_type extent() const _NOEXCEPT
856 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700857 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700858 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
859 }
860
861 _CONSTEXPR index_type index_bounds() const _NOEXCEPT
862 {
863 index_type extents;
864 m_ranges.serialize(extents);
865 return extents;
866 }
867
868 template <typename OtherSizeTypes, size_t... Ranges>
869 _CONSTEXPR bool operator == (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const _NOEXCEPT
870 {
871 return this->size() == rhs.size();
872 }
873
874 template <typename OtherSizeTypes, size_t... Ranges>
875 _CONSTEXPR bool operator != (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const _NOEXCEPT
876 {
877 return !(*this == rhs);
878 }
879
880 _CONSTEXPR const_iterator begin() const _NOEXCEPT
881 {
882 return const_iterator(*this);
883 }
884
885 _CONSTEXPR const_iterator end() const _NOEXCEPT
886 {
887 index_type boundary;
888 m_ranges.serialize(boundary);
889 return const_iterator(*this, this->index_bounds());
890 }
891};
892
893template <unsigned int Rank, typename SizeType = size_t>
894class strided_bounds : private details::coordinate_facade<strided_bounds<Rank>, SizeType, Rank>
895{
896 using Base = details::coordinate_facade<strided_bounds<Rank>, SizeType, Rank>;
897 friend Base;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700898 template <unsigned int OtherRank, typename OtherSizeType>
899 friend class strided_bounds;
900
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700901public:
902 using Base::rank;
903 using reference = typename Base::reference;
904 using const_reference = typename Base::const_reference;
905 using size_type = typename Base::value_type;
906 using difference_type = typename Base::value_type;
907 using value_type = typename Base::value_type;
908 using index_type = index<rank, size_type>;
909 using iterator = bounds_iterator<index_type>;
910 using const_iterator = bounds_iterator<index_type>;
911 static const int dynamic_rank = rank;
912 static const size_t static_size = dynamic_range;
913 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
914 using mapping_type = generalized_mapping_tag;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700915 _CONSTEXPR strided_bounds(const strided_bounds &) = default;
916
917 template <typename OtherSizeType>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700918 _CONSTEXPR strided_bounds(const strided_bounds<rank, OtherSizeType> &other)
919 : Base(other), m_strides(other.strides)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700920 {
921 }
922
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700923 _CONSTEXPR strided_bounds(const index_type &extents, const index_type &strides)
924 : m_strides(strides)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700925 {
926 for (unsigned int i = 0; i < rank; i++)
927 Base::elems[i] = extents[i];
928 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700929 _CONSTEXPR strided_bounds(const value_type(&values)[rank], index_type strides)
930 : Base(values), m_strides(std::move(strides))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700931 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700932 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700933 _CONSTEXPR index_type strides() const _NOEXCEPT
934 {
935 return m_strides;
936 }
937 _CONSTEXPR size_type total_size() const _NOEXCEPT
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700938 {
939 size_type ret = 0;
940 for (unsigned int i = 0; i < rank; ++i)
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700941 ret += (Base::elems[i] - 1) * m_strides[i];
942 return ret + 1;
943 }
944 _CONSTEXPR size_type size() const _NOEXCEPT
945 {
946 size_type ret = 1;
947 for (unsigned int i = 0; i < rank; ++i)
948 ret *= Base::elems[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700949 return ret;
950 }
951 _CONSTEXPR bool contains(const index_type& idx) const _NOEXCEPT
952 {
953 for (unsigned int i = 0; i < rank; ++i)
954 {
955 if (idx[i] < 0 || idx[i] >= Base::elems[i])
956 return false;
957 }
958 return true;
959 }
960 _CONSTEXPR size_type linearize(const index_type & idx) const
961 {
962 size_type ret = 0;
963 for (unsigned int i = 0; i < rank; i++)
964 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700965 fail_fast_assert(idx[i] < Base::elems[i], "index is out of bounds of the array");
966 ret += idx[i] * m_strides[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700967 }
968 return ret;
969 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700970 _CONSTEXPR size_type stride() const _NOEXCEPT
971 {
972 return m_strides[0];
973 }
974 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700975 _CONSTEXPR sliced_type slice() const
976 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700977 return{ (value_type(&)[rank - 1])Base::elems[1], sliced_type::index_type::shift_left(m_strides) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700978 }
979 template <unsigned int Dim = 0>
980 _CONSTEXPR size_type extent() const _NOEXCEPT
981 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700982 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700983 return Base::elems[Dim];
984 }
985 _CONSTEXPR index_type index_bounds() const _NOEXCEPT
986 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700987 return index_type(Base::elems);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700988 }
989 const_iterator begin() const _NOEXCEPT
990 {
991 return const_iterator{ *this };
992 }
993 const_iterator end() const _NOEXCEPT
994 {
995 return const_iterator{ *this, index_bounds() };
996 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700997private:
998 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700999};
1000
1001template <typename T>
1002struct is_bounds : std::integral_constant<bool, false> {};
1003template <typename SizeType, size_t... Ranges>
1004struct is_bounds<static_bounds<SizeType, Ranges...>> : std::integral_constant<bool, true> {};
1005template <unsigned int Rank, typename SizeType>
1006struct is_bounds<strided_bounds<Rank, SizeType>> : std::integral_constant<bool, true> {};
1007
1008template <typename IndexType>
1009class bounds_iterator
1010 : public std::iterator<std::random_access_iterator_tag,
1011 IndexType,
1012 ptrdiff_t,
1013 const details::arrow_proxy<IndexType>,
1014 const IndexType>
1015{
1016private:
1017 using Base = std::iterator <std::random_access_iterator_tag, IndexType, ptrdiff_t, const details::arrow_proxy<IndexType>, const IndexType>;
1018public:
1019 static const unsigned int rank = IndexType::rank;
1020 using typename Base::reference;
1021 using typename Base::pointer;
1022 using typename Base::difference_type;
1023 using typename Base::value_type;
1024 using index_type = value_type;
1025 using index_size_type = typename IndexType::size_type;
1026 template <typename Bounds>
1027 explicit bounds_iterator(const Bounds & bnd, value_type curr = value_type{}) _NOEXCEPT
1028 : boundary(bnd.index_bounds())
1029 , curr( std::move(curr) )
1030 {
1031 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
1032 }
1033 reference operator*() const _NOEXCEPT
1034 {
1035 return curr;
1036 }
1037 pointer operator->() const _NOEXCEPT
1038 {
1039 return details::arrow_proxy<value_type>{ curr };
1040 }
1041 bounds_iterator& operator++() _NOEXCEPT
1042 {
1043 for (unsigned int i = rank; i-- > 0;)
1044 {
1045 if (++curr[i] < boundary[i])
1046 {
1047 return *this;
1048 }
1049 else
1050 {
1051 curr[i] = 0;
1052 }
1053 }
1054 // If we're here we've wrapped over - set to past-the-end.
1055 for (unsigned int i = 0; i < rank; ++i)
1056 {
1057 curr[i] = boundary[i];
1058 }
1059 return *this;
1060 }
1061 bounds_iterator operator++(int) _NOEXCEPT
1062 {
1063 auto ret = *this;
1064 ++(*this);
1065 return ret;
1066 }
1067 bounds_iterator& operator--() _NOEXCEPT
1068 {
1069 for (int i = rank; i-- > 0;)
1070 {
1071 if (curr[i]-- > 0)
1072 {
1073 return *this;
1074 }
1075 else
1076 {
1077 curr[i] = boundary[i] - 1;
1078 }
1079 }
1080 // If we're here the preconditions were violated
1081 // "pre: there exists s such that r == ++s"
1082 fail_fast_assert(false);
1083 return *this;
1084 }
1085 bounds_iterator operator--(int) _NOEXCEPT
1086 {
1087 auto ret = *this;
1088 --(*this);
1089 return ret;
1090 }
1091 bounds_iterator operator+(difference_type n) const _NOEXCEPT
1092 {
1093 bounds_iterator ret{ *this };
1094 return ret += n;
1095 }
1096 bounds_iterator& operator+=(difference_type n) _NOEXCEPT
1097 {
1098 auto linear_idx = linearize(curr) + n;
1099 value_type stride;
1100 stride[rank - 1] = 1;
1101 for (unsigned int i = rank - 1; i-- > 0;)
1102 {
1103 stride[i] = stride[i + 1] * boundary[i + 1];
1104 }
1105 for (unsigned int i = 0; i < rank; ++i)
1106 {
1107 curr[i] = linear_idx / stride[i];
1108 linear_idx = linear_idx % stride[i];
1109 }
1110 return *this;
1111 }
1112 bounds_iterator operator-(difference_type n) const _NOEXCEPT
1113 {
1114 bounds_iterator ret{ *this };
1115 return ret -= n;
1116 }
1117 bounds_iterator& operator-=(difference_type n) _NOEXCEPT
1118 {
1119 return *this += -n;
1120 }
1121 difference_type operator-(const bounds_iterator& rhs) const _NOEXCEPT
1122 {
1123 return linearize(curr) - linearize(rhs.curr);
1124 }
1125 reference operator[](difference_type n) const _NOEXCEPT
1126 {
1127 return *(*this + n);
1128 }
1129 bool operator==(const bounds_iterator& rhs) const _NOEXCEPT
1130 {
1131 return curr == rhs.curr;
1132 }
1133 bool operator!=(const bounds_iterator& rhs) const _NOEXCEPT
1134 {
1135 return !(*this == rhs);
1136 }
1137 bool operator<(const bounds_iterator& rhs) const _NOEXCEPT
1138 {
1139 for (unsigned int i = 0; i < rank; ++i)
1140 {
1141 if (curr[i] < rhs.curr[i])
1142 return true;
1143 }
1144 return false;
1145 }
1146 bool operator<=(const bounds_iterator& rhs) const _NOEXCEPT
1147 {
1148 return !(rhs < *this);
1149 }
1150 bool operator>(const bounds_iterator& rhs) const _NOEXCEPT
1151 {
1152 return rhs < *this;
1153 }
1154 bool operator>=(const bounds_iterator& rhs) const _NOEXCEPT
1155 {
1156 return !(rhs > *this);
1157 }
1158 void swap(bounds_iterator& rhs) _NOEXCEPT
1159 {
1160 std::swap(boundary, rhs.boundary);
1161 std::swap(curr, rhs.curr);
1162 }
1163private:
1164 index_size_type linearize(const value_type& idx) const _NOEXCEPT
1165 {
1166 // TODO: Smarter impl.
1167 // Check if past-the-end
1168 bool pte = true;
1169 for (unsigned int i = 0; i < rank; ++i)
1170 {
1171 if (idx[i] != boundary[i])
1172 {
1173 pte = false;
1174 break;
1175 }
1176 }
1177 index_size_type multiplier = 1;
1178 index_size_type res = 0;
1179 if (pte)
1180 {
1181 res = 1;
1182 for (unsigned int i = rank; i-- > 0;)
1183 {
1184 res += (idx[i] - 1) * multiplier;
1185 multiplier *= boundary[i];
1186 }
1187 }
1188 else
1189 {
1190 for (unsigned int i = rank; i-- > 0;)
1191 {
1192 res += idx[i] * multiplier;
1193 multiplier *= boundary[i];
1194 }
1195 }
1196 return res;
1197 }
1198 value_type boundary;
1199 value_type curr;
1200};
1201
1202template <typename SizeType>
1203class bounds_iterator<index<1, SizeType>>
1204 : public std::iterator<std::random_access_iterator_tag,
1205 index<1, SizeType>,
1206 ptrdiff_t,
1207 const details::arrow_proxy<index<1, SizeType>>,
1208 const index<1, SizeType>>
1209{
1210 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>>;
1211
1212public:
1213 using typename Base::reference;
1214 using typename Base::pointer;
1215 using typename Base::difference_type;
1216 using typename Base::value_type;
1217 using index_type = value_type;
1218 using index_size_type = typename index_type::size_type;
1219
1220 template <typename Bounds>
1221 explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) _NOEXCEPT
1222 : curr( std::move(curr) )
1223 {}
1224 reference operator*() const _NOEXCEPT
1225 {
1226 return curr;
1227 }
1228 pointer operator->() const _NOEXCEPT
1229 {
1230 return details::arrow_proxy<value_type>{ curr };
1231 }
1232 bounds_iterator& operator++() _NOEXCEPT
1233 {
1234 ++curr;
1235 return *this;
1236 }
1237 bounds_iterator operator++(int) _NOEXCEPT
1238 {
1239 auto ret = *this;
1240 ++(*this);
1241 return ret;
1242 }
1243 bounds_iterator& operator--() _NOEXCEPT
1244 {
1245 curr--;
1246 return *this;
1247 }
1248 bounds_iterator operator--(int) _NOEXCEPT
1249 {
1250 auto ret = *this;
1251 --(*this);
1252 return ret;
1253 }
1254 bounds_iterator operator+(difference_type n) const _NOEXCEPT
1255 {
1256 bounds_iterator ret{ *this };
1257 return ret += n;
1258 }
1259 bounds_iterator& operator+=(difference_type n) _NOEXCEPT
1260 {
1261 curr += n;
1262 return *this;
1263 }
1264 bounds_iterator operator-(difference_type n) const _NOEXCEPT
1265 {
1266 bounds_iterator ret{ *this };
1267 return ret -= n;
1268 }
1269 bounds_iterator& operator-=(difference_type n) _NOEXCEPT
1270 {
1271 return *this += -n;
1272 }
1273 difference_type operator-(const bounds_iterator& rhs) const _NOEXCEPT
1274 {
1275 return curr[0] - rhs.curr[0];
1276 }
1277 reference operator[](difference_type n) const _NOEXCEPT
1278 {
1279 return curr + n;
1280 }
1281 bool operator==(const bounds_iterator& rhs) const _NOEXCEPT
1282 {
1283 return curr == rhs.curr;
1284 }
1285 bool operator!=(const bounds_iterator& rhs) const _NOEXCEPT
1286 {
1287 return !(*this == rhs);
1288 }
1289 bool operator<(const bounds_iterator& rhs) const _NOEXCEPT
1290 {
1291 return curr[0] < rhs.curr[0];
1292 }
1293 bool operator<=(const bounds_iterator& rhs) const _NOEXCEPT
1294 {
1295 return !(rhs < *this);
1296 }
1297 bool operator>(const bounds_iterator& rhs) const _NOEXCEPT
1298 {
1299 return rhs < *this;
1300 }
1301 bool operator>=(const bounds_iterator& rhs) const _NOEXCEPT
1302 {
1303 return !(rhs > *this);
1304 }
1305 void swap(bounds_iterator& rhs) _NOEXCEPT
1306 {
1307 std::swap(curr, rhs.curr);
1308 }
1309private:
1310 value_type curr;
1311};
1312
1313template <typename IndexType>
1314bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) _NOEXCEPT
1315{
1316 return rhs + n;
1317}
1318
1319/*
1320** begin definitions of basic_array_view
1321*/
1322namespace details
1323{
1324 template <typename Bounds>
1325 _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
1326 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001327 return bnd.strides();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001328 }
1329
1330 // Make a stride vector from bounds, assuming continugous memory.
1331 template <typename Bounds>
1332 _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
1333 {
1334 auto extents = bnd.index_bounds();
1335 typename Bounds::index_type stride;
1336 stride[Bounds::rank - 1] = 1;
1337 for (int i = Bounds::rank - 2; i >= 0; --i)
1338 stride[i] = stride[i + 1] * extents[i + 1];
1339 return stride;
1340 }
1341
1342 template <typename BoundsSrc, typename BoundsDest>
1343 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1344 {
1345 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1346 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1347 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");
1348 fail_fast_assert(src.size() == dest.size());
1349 }
1350
1351
1352} // namespace details
1353
1354template <typename ArrayView>
1355class contiguous_array_view_iterator;
1356template <typename ArrayView>
1357class general_array_view_iterator;
1358enum class byte : std::uint8_t {};
1359
1360template <typename ValueType, typename BoundsType>
1361class basic_array_view
1362{
1363public:
1364 static const unsigned int rank = BoundsType::rank;
1365 using bounds_type = BoundsType;
1366 using size_type = typename bounds_type::size_type;
1367 using index_type = typename bounds_type::index_type;
1368 using value_type = ValueType;
1369 using pointer = ValueType*;
1370 using reference = ValueType&;
1371 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>>;
1372 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>>>;
1373 using reverse_iterator = std::reverse_iterator<iterator>;
1374 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1375 using sliced_type = std::conditional_t<rank == 1, value_type, basic_array_view<value_type, typename BoundsType::sliced_type>>;
1376
1377private:
1378 pointer m_pdata;
1379 bounds_type m_bounds;
1380
1381public:
1382 _CONSTEXPR bounds_type bounds() const _NOEXCEPT
1383 {
1384 return m_bounds;
1385 }
1386 template <unsigned int Dim = 0>
1387 _CONSTEXPR size_type extent() const _NOEXCEPT
1388 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001389 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001390 return m_bounds.template extent<Dim>();
1391 }
1392 _CONSTEXPR size_type size() const _NOEXCEPT
1393 {
1394 return m_bounds.size();
1395 }
1396 _CONSTEXPR reference operator[](const index_type& idx) const
1397 {
1398 return m_pdata[m_bounds.linearize(idx)];
1399 }
1400 _CONSTEXPR pointer data() const _NOEXCEPT
1401 {
1402 return m_pdata;
1403 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001404 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001405 _CONSTEXPR Ret operator[](size_type idx) const
1406 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001407 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001408 const size_type ridx = idx * m_bounds.stride();
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001409
1410 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001411 return Ret {m_pdata + ridx, m_bounds.slice()};
1412 }
1413
1414 _CONSTEXPR operator bool () const _NOEXCEPT
1415 {
1416 return m_pdata != nullptr;
1417 }
1418
1419 _CONSTEXPR iterator begin() const
1420 {
1421 return iterator {this, true};
1422 }
1423 _CONSTEXPR iterator end() const
1424 {
1425 return iterator {this};
1426 }
1427 _CONSTEXPR const_iterator cbegin() const
1428 {
1429 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), true};
1430 }
1431 _CONSTEXPR const_iterator cend() const
1432 {
1433 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this)};
1434 }
1435
1436 _CONSTEXPR reverse_iterator rbegin() const
1437 {
1438 return reverse_iterator {end()};
1439 }
1440 _CONSTEXPR reverse_iterator rend() const
1441 {
1442 return reverse_iterator {begin()};
1443 }
1444 _CONSTEXPR const_reverse_iterator crbegin() const
1445 {
1446 return const_reverse_iterator {cend()};
1447 }
1448 _CONSTEXPR const_reverse_iterator crend() const
1449 {
1450 return const_reverse_iterator {cbegin()};
1451 }
1452
1453 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 MacIntosh9f9fad92015-08-27 18:13:49 -07001454 _CONSTEXPR bool operator== (const basic_array_view<OtherValueType, OtherBoundsType> & other) const _NOEXCEPT
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001455 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001456 return m_bounds.size() == other.m_bounds.size() &&
1457 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001458 }
1459
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001460 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>>
1461 _CONSTEXPR bool operator!= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const _NOEXCEPT
1462 {
1463 return !(*this == other);
1464 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001465
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001466 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>>
1467 _CONSTEXPR bool operator< (const basic_array_view<OtherValueType, OtherBoundsType> & other) const _NOEXCEPT
1468 {
1469 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1470 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001471
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001472 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>>
1473 _CONSTEXPR bool operator<= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const _NOEXCEPT
1474 {
1475 return !(other < *this);
1476 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001477
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001478 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>>
1479 _CONSTEXPR bool operator> (const basic_array_view<OtherValueType, OtherBoundsType> & other) const _NOEXCEPT
1480 {
1481 return (other < *this);
1482 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001483
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001484 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>>
1485 _CONSTEXPR bool operator>= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const _NOEXCEPT
1486 {
1487 return !(*this < other);
1488 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001489
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001490public:
1491 template <typename OtherValueType, typename OtherBounds,
1492 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value
1493 && std::is_convertible<OtherBounds, bounds_type>::value>>
1494 _CONSTEXPR basic_array_view(const basic_array_view<OtherValueType, OtherBounds> & other ) _NOEXCEPT
1495 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
1496 {
1497 }
1498protected:
1499
1500 _CONSTEXPR basic_array_view(pointer data, bounds_type bound) _NOEXCEPT
1501 : m_pdata(data)
1502 , m_bounds(std::move(bound))
1503 {
1504 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1505 }
1506 template <typename T>
1507 _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
1508 : m_pdata(reinterpret_cast<pointer>(data))
1509 , m_bounds(std::move(bound))
1510 {
1511 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1512 }
1513 template <typename DestBounds>
1514 _CONSTEXPR basic_array_view<value_type, DestBounds> as_array_view(const DestBounds &bounds)
1515 {
1516 details::verifyBoundsReshape(m_bounds, bounds);
1517 return {m_pdata, bounds};
1518 }
1519private:
1520
1521 friend iterator;
1522 friend const_iterator;
1523 template <typename ValueType2, typename BoundsType2>
1524 friend class basic_array_view;
1525};
1526
1527template <size_t DimSize = dynamic_range>
1528struct dim
1529{
1530 static const size_t value = DimSize;
1531};
1532template <>
1533struct dim<dynamic_range>
1534{
1535 static const size_t value = dynamic_range;
1536 const size_t dvalue;
1537 dim(size_t size) : dvalue(size) {}
1538};
1539
1540template <typename ValueTypeOpt, size_t FirstDimension = dynamic_range, size_t... RestDimensions>
1541class array_view;
1542template <typename ValueTypeOpt, unsigned int Rank>
1543class strided_array_view;
1544
1545namespace details
1546{
1547 template <typename T, typename = std::true_type>
1548 struct ArrayViewTypeTraits
1549 {
1550 using value_type = T;
1551 using size_type = size_t;
1552 };
1553
1554 template <typename Traits>
1555 struct ArrayViewTypeTraits<Traits, typename std::is_reference<typename Traits::array_view_traits &>::type>
1556 {
1557 using value_type = typename Traits::array_view_traits::value_type;
1558 using size_type = typename Traits::array_view_traits::size_type;
1559 };
1560
1561 template <typename T, typename SizeType, size_t... Ranks>
1562 struct ArrayViewArrayTraits {
1563 using type = array_view<T, Ranks...>;
1564 using value_type = T;
1565 using bounds_type = static_bounds<SizeType, Ranks...>;
1566 using pointer = T*;
1567 using reference = T&;
1568 };
1569 template <typename T, typename SizeType, size_t N, size_t... Ranks>
1570 struct ArrayViewArrayTraits<T[N], SizeType, Ranks...> : ArrayViewArrayTraits<T, SizeType, Ranks..., N> {};
1571
1572 template <typename BoundsType>
1573 BoundsType newBoundsHelperImpl(size_t totalSize, std::true_type) // dynamic size
1574 {
1575 fail_fast_assert(totalSize <= details::SizeTypeTraits<typename BoundsType::size_type>::max_value);
1576 return BoundsType{static_cast<typename BoundsType::size_type>(totalSize)};
1577 }
1578 template <typename BoundsType>
1579 BoundsType newBoundsHelperImpl(size_t totalSize, std::false_type) // static size
1580 {
1581 fail_fast_assert(BoundsType::static_size == totalSize);
1582 return {};
1583 }
1584 template <typename BoundsType>
1585 BoundsType newBoundsHelper(size_t totalSize)
1586 {
1587 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1588 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1589 }
1590
1591 struct Sep{};
1592
1593 template <typename T, typename... Args>
1594 T static_as_array_view_helper(Sep, Args... args)
1595 {
1596 return T{static_cast<typename T::size_type>(args)...};
1597 }
1598 template <typename T, typename Arg, typename... Args>
1599 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)
1600 {
1601 return static_as_array_view_helper<T>(args...);
1602 }
1603 template <typename T, typename... Args>
1604 T static_as_array_view_helper(dim<dynamic_range> val, Args ... args)
1605 {
1606 return static_as_array_view_helper<T>(args..., val.dvalue);
1607 }
1608
1609 template <typename SizeType, typename ...Dimensions>
1610 struct static_as_array_view_static_bounds_helper
1611 {
1612 using type = static_bounds<SizeType, (Dimensions::value)...>;
1613 };
1614
1615 template <typename T>
1616 struct is_array_view_oracle : std::false_type
1617 {};
1618 template <typename ValueType, size_t FirstDimension, size_t... RestDimensions>
1619 struct is_array_view_oracle<array_view<ValueType, FirstDimension, RestDimensions...>> : std::true_type
1620 {};
1621 template <typename ValueType, unsigned int Rank>
1622 struct is_array_view_oracle<strided_array_view<ValueType, Rank>> : std::true_type
1623 {};
1624 template <typename T>
1625 struct is_array_view : is_array_view_oracle<std::remove_cv_t<T>>
1626 {};
1627
1628}
1629
1630
1631template <typename ValueType, typename SizeType>
1632struct array_view_options
1633{
1634 struct array_view_traits
1635 {
1636 using value_type = ValueType;
1637 using size_type = SizeType;
1638 };
1639};
1640
1641template <typename ValueTypeOpt, size_t FirstDimension, size_t... RestDimensions>
1642class array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
1643 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>
1644{
1645 template <typename ValueTypeOpt2, size_t FirstDimension2, size_t... RestDimensions2>
1646 friend class array_view;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001647 using Base = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001648 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001649
1650public:
1651 using typename Base::bounds_type;
1652 using typename Base::size_type;
1653 using typename Base::pointer;
1654 using typename Base::value_type;
1655 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001656 using typename Base::iterator;
1657 using typename Base::const_iterator;
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001658 using typename Base::reference;
Neil MacIntosh383dc502015-09-14 15:41:40 -07001659 using Base::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001660
1661public:
1662 // basic
1663 _CONSTEXPR array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds))
1664 {
1665 }
1666
1667 _CONSTEXPR array_view(std::nullptr_t) : Base(nullptr, bounds_type{})
1668 {
1669 }
1670
Neil MacIntosh9b40a0a2015-08-27 19:49:27 -07001671 _CONSTEXPR array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001672 {
1673 fail_fast_assert(size == 0);
1674 }
1675
1676 // default
1677 template <size_t DynamicRank = bounds_type::dynamic_rank, typename Dummy = std::enable_if_t<DynamicRank != 0>>
1678 _CONSTEXPR array_view() : Base(nullptr, bounds_type())
1679 {
1680 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001681
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001682 // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
1683 template <typename T, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001684 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type (*)[], typename Base::value_type (*)[]>::value
1685 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
1686 _CONSTEXPR array_view(T * const & data, size_type size) : Base(data, typename Helper::bounds_type{size})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001687 {
1688 }
1689
1690 // from n-dimensions static array
1691 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, N>,
1692 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 -07001693 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
Anna Gringauzee5b79d22015-09-14 16:38:25 -07001694 _CONSTEXPR array_view (T (&arr)[N]) : Base(arr, typename Helper::bounds_type())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001695 {
1696 }
1697
1698 // from n-dimensions static array with size
1699 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
1700 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 -07001701 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value >>
1702 _CONSTEXPR array_view(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{ size })
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001703 {
1704 fail_fast_assert(size <= N);
1705 }
1706
1707 // from std array
1708 template <size_t N, typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<size_type, N>, typename Base::bounds_type>::value>>
1709 _CONSTEXPR array_view (std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<size_type, N>())
1710 {
1711 }
1712
1713 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>>
1714 _CONSTEXPR array_view (const std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<size_type, N>())
1715 {
1716 }
1717
1718
1719 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1720 template <typename Ptr,
1721 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
1722 && details::LessThan<Base::bounds_type::dynamic_rank, 2>::value>> // remove literal 0 case
1723 _CONSTEXPR array_view (pointer begin, Ptr end) : Base(begin, details::newBoundsHelper<typename Base::bounds_type>(static_cast<pointer>(end) - begin))
1724 {
1725 }
1726
1727 // from containers. It must has .size() and .data() two function signatures
1728 template <typename Cont, typename DataType = typename Cont::value_type, typename SizeType = typename Cont::size_type,
1729 typename Dummy = std::enable_if_t<!details::is_array_view<Cont>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001730 && std::is_convertible<DataType (*)[], typename Base::value_type (*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001731 && std::is_convertible<static_bounds<SizeType, dynamic_range>, typename Base::bounds_type>::value
1732 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001733 >
Anna Gringauze18cd9802015-09-14 16:34:26 -07001734 _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 -07001735 {
1736
1737 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001738
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001739 _CONSTEXPR array_view(const array_view &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001740
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001741 // convertible
1742 template <typename OtherValueTypeOpt, size_t... OtherDimensions,
1743 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>,
1744 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type, OtherDimensions...>>,
1745 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1746 >
1747 _CONSTEXPR array_view(const array_view<OtherValueTypeOpt, OtherDimensions...> &av) : Base(static_cast<const typename array_view<OtherValueTypeOpt, OtherDimensions...>::Base &>(av)) {} // static_cast is required
1748
1749 // reshape
1750 template <typename... Dimensions2>
1751 _CONSTEXPR array_view<ValueTypeOpt, Dimensions2::value...> as_array_view(Dimensions2... dims)
1752 {
1753 static_assert(sizeof...(Dimensions2) > 0, "the target array_view must have at least one dimension.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001754 using BoundsType = typename array_view<ValueTypeOpt, (Dimensions2::value)...>::bounds_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001755 auto tobounds = details::static_as_array_view_helper<BoundsType>(dims..., details::Sep{});
1756 details::verifyBoundsReshape(this->bounds(), tobounds);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001757 return {this->data(), tobounds};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001758 }
1759
1760 // to bytes array
1761 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001762 _CONSTEXPR auto as_bytes() const _NOEXCEPT ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001763 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)>
1764 {
1765 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001766 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001767 }
1768
1769 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001770 _CONSTEXPR auto as_writeable_bytes() const _NOEXCEPT ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001771 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)>
1772 {
1773 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001774 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001775 }
1776
Anna Gringauze18cd9802015-09-14 16:34:26 -07001777
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001778 // from bytes array
1779 template<typename U, bool IsByte = std::is_same<value_type, const byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
1780 _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))>
1781 {
1782 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1783 "Target type must be standard layout and its size must match the byte array size");
1784 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001785 return { reinterpret_cast<const U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001786 }
1787
1788 template<typename U, bool IsByte = std::is_same<value_type, byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
1789 _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))>
1790 {
1791 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1792 "Target type must be standard layout and its size must match the byte array size");
1793 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001794 return { reinterpret_cast<U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001795 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001796
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001797 // section on linear space
1798 template<size_t Count>
1799 _CONSTEXPR array_view<ValueTypeOpt, Count> first() const _NOEXCEPT
1800 {
1801 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1802 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 -07001803 return { this->data(), Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001804 }
1805
1806 _CONSTEXPR array_view<ValueTypeOpt, dynamic_range> first(size_type count) const _NOEXCEPT
1807 {
1808 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001809 return { this->data(), count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001810 }
1811
1812 template<size_t Count>
1813 _CONSTEXPR array_view<ValueTypeOpt, Count> last() const _NOEXCEPT
1814 {
1815 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1816 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001817 return { this->data() + this->size() - Count, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001818 }
1819
1820 _CONSTEXPR array_view<ValueTypeOpt, dynamic_range> last(size_type count) const _NOEXCEPT
1821 {
1822 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001823 return { this->data() + this->size() - count, count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001824 }
1825
1826 template<size_t Offset, size_t Count>
1827 _CONSTEXPR array_view<ValueTypeOpt, Count> sub() const _NOEXCEPT
1828 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001829 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");
1830 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 -07001831 return { this->data() + Offset, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001832 }
1833
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001834 _CONSTEXPR array_view<ValueTypeOpt, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const _NOEXCEPT
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001835 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001836 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1837 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001838 }
1839
1840 // size
1841 _CONSTEXPR size_type length() const _NOEXCEPT
1842 {
1843 return this->size();
1844 }
1845 _CONSTEXPR size_type used_length() const _NOEXCEPT
1846 {
1847 return length();
1848 }
1849 _CONSTEXPR size_type bytes() const _NOEXCEPT
1850 {
1851 return sizeof(value_type) * this->size();
1852 }
1853 _CONSTEXPR size_type used_bytes() const _NOEXCEPT
1854 {
1855 return bytes();
1856 }
1857
1858 // section
1859 _CONSTEXPR strided_array_view<ValueTypeOpt, rank> section(index_type origin, index_type extents) const
1860 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001861 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001862 return{ &this->operator[](origin), size, strided_bounds<rank, size_type> {extents, details::make_stride(Base::bounds())} };
1863 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001864
Anna Gringauze1a864982015-09-14 18:55:06 -07001865 _CONSTEXPR reference operator[](const index_type& idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001866 {
1867 return Base::operator[](idx);
1868 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001869
Anna Gringauze1a864982015-09-14 18:55:06 -07001870 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001871 _CONSTEXPR array_view<ValueTypeOpt, RestDimensions...> operator[](size_type idx) const
1872 {
1873 auto ret = Base::operator[](idx);
1874 return{ ret.data(), ret.bounds() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001875 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001876
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001877 using Base::operator==;
1878 using Base::operator!=;
1879 using Base::operator<;
1880 using Base::operator<=;
1881 using Base::operator>;
1882 using Base::operator>=;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001883};
1884
1885template <typename T, size_t... Dimensions>
1886_CONSTEXPR auto as_array_view(T * const & ptr, dim<Dimensions>... args) -> array_view<std::remove_all_extents_t<T>, Dimensions...>
1887{
1888 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), details::static_as_array_view_helper<static_bounds<size_t, Dimensions...>>(args..., details::Sep{})};
1889}
1890
1891template <typename T>
1892_CONSTEXPR auto as_array_view (T * arr, size_t len) -> typename details::ArrayViewArrayTraits<T, size_t, dynamic_range>::type
1893{
1894 return {arr, len};
1895}
1896
1897template <typename T, size_t N>
1898_CONSTEXPR auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits<T, size_t, N>::type
1899{
1900 return {arr};
1901}
1902
1903template <typename T, size_t N>
1904_CONSTEXPR array_view<const T, N> as_array_view(const std::array<T, N> &arr)
1905{
1906 return {arr};
1907}
1908
1909template <typename T, size_t N>
1910_CONSTEXPR array_view<const T, N> as_array_view(const std::array<T, N> &&) = delete;
1911
1912template <typename T, size_t N>
1913_CONSTEXPR array_view<T, N> as_array_view(std::array<T, N> &arr)
1914{
1915 return {arr};
1916}
1917
1918template <typename T>
1919_CONSTEXPR array_view<T, dynamic_range> as_array_view(T *begin, T *end)
1920{
1921 return {begin, end};
1922}
1923
1924template <typename Cont>
1925_CONSTEXPR auto as_array_view(Cont &arr) -> std::enable_if_t<!details::is_array_view<std::decay_t<Cont>>::value,
1926 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
1927{
1928 return {arr.data(), arr.size()};
1929}
1930
1931template <typename Cont>
1932_CONSTEXPR auto as_array_view(Cont &&arr) -> std::enable_if_t<!details::is_array_view<std::decay_t<Cont>>::value,
1933 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
1934
1935template <typename ValueTypeOpt, unsigned int Rank>
1936class strided_array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>
1937{
1938 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 -07001939
1940 template<typename OtherValueOpt, unsigned int OtherRank>
1941 friend class strided_array_view;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001942public:
1943 using Base::rank;
1944 using typename Base::bounds_type;
1945 using typename Base::size_type;
1946 using typename Base::pointer;
1947 using typename Base::value_type;
1948 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001949 using typename Base::iterator;
1950 using typename Base::const_iterator;
Anna Gringauze9dac1782015-09-14 19:08:03 -07001951 using typename Base::reference;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001952
1953 // from static array of size N
1954 template<size_type N>
1955 strided_array_view(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds))
1956 {
1957 fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries");
1958 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001959
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001960 // from raw data
1961 strided_array_view(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001962 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001963 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001964 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001965
1966 // from array view
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001967 template <size_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001968 strided_array_view(array_view<ValueTypeOpt, Dimensions...> av, bounds_type bounds) : Base(av.data(), std::move(bounds))
1969 {
1970 fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries");
1971 }
1972
1973 // convertible
1974 template <typename OtherValueTypeOpt,
1975 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>,
1976 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type>>,
1977 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1978 >
1979 _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 -07001980 {
1981 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001982
1983 // convert from bytes
Anna Gringauze1a864982015-09-14 18:55:06 -07001984 template <typename OtherValueType>
1985 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 -07001986 {
1987 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
1988 auto d = sizeof(OtherValueType) / sizeof(value_type);
1989
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001990 size_type size = this->bounds().total_size() / d;
1991 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 -07001992 }
1993
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001994 strided_array_view section(index_type origin, index_type extents) const
1995 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001996 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001997 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}};
1998 }
1999
2000 _CONSTEXPR reference operator[](const index_type& idx) const
Anna Gringauze9dac1782015-09-14 19:08:03 -07002001 {
2002 return Base::operator[](idx);
2003 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07002004
2005 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
2006 _CONSTEXPR strided_array_view<value_type, rank-1> operator[](size_type idx) const
2007 {
2008 auto ret = Base::operator[](idx);
2009 return{ ret.data(), ret.bounds().total_size(), ret.bounds() };
2010 }
2011
2012private:
2013 static index_type resize_extent(const index_type& extent, size_t d)
2014 {
2015 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");
2016
2017 index_type ret = extent;
2018 ret[rank - 1] /= d;
2019
2020 return ret;
2021 }
2022
2023 template <bool Enabled = (rank == 1), typename Dummy = std::enable_if_t<Enabled>>
2024 static index_type resize_stride(const index_type& strides, size_t d, void *p = 0)
2025 {
2026 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
2027
2028 return strides;
2029 }
2030
2031 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
2032 static index_type resize_stride(const index_type& strides, size_t d)
2033 {
2034 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
2035 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");
2036
2037 for (int i = rank - 2; i >= 0; --i)
2038 {
2039 fail_fast_assert((strides[i] >= strides[i + 1]) && (strides[i] % strides[i + 1] == 0), "Only strided arrays with regular strides can be resized");
2040 }
2041
2042 index_type ret = strides / d;
2043 ret[rank - 1] = 1;
2044
2045 return ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002046 }
2047};
2048
2049template <typename ArrayView>
2050class contiguous_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
2051{
2052 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
2053public:
2054 using typename Base::reference;
2055 using typename Base::pointer;
2056 using typename Base::difference_type;
2057private:
2058 template <typename ValueType, typename Bounds>
2059 friend class basic_array_view;
2060 pointer m_pdata;
2061 const ArrayView * m_validator;
2062 void validateThis() const
2063 {
Neil MacIntosh383dc502015-09-14 15:41:40 -07002064 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 -07002065 }
2066 contiguous_array_view_iterator (const ArrayView *container, bool isbegin = false) :
2067 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) { }
2068public:
2069 reference operator*() const _NOEXCEPT
2070 {
2071 validateThis();
2072 return *m_pdata;
2073 }
2074 pointer operator->() const _NOEXCEPT
2075 {
2076 validateThis();
2077 return m_pdata;
2078 }
2079 contiguous_array_view_iterator& operator++() _NOEXCEPT
2080 {
2081 ++m_pdata;
2082 return *this;
2083 }
2084 contiguous_array_view_iterator operator++(int)_NOEXCEPT
2085 {
2086 auto ret = *this;
2087 ++(*this);
2088 return ret;
2089 }
2090 contiguous_array_view_iterator& operator--() _NOEXCEPT
2091 {
2092 --m_pdata;
2093 return *this;
2094 }
2095 contiguous_array_view_iterator operator--(int)_NOEXCEPT
2096 {
2097 auto ret = *this;
2098 --(*this);
2099 return ret;
2100 }
2101 contiguous_array_view_iterator operator+(difference_type n) const _NOEXCEPT
2102 {
2103 contiguous_array_view_iterator ret{ *this };
2104 return ret += n;
2105 }
2106 contiguous_array_view_iterator& operator+=(difference_type n) _NOEXCEPT
2107 {
2108 m_pdata += n;
2109 return *this;
2110 }
2111 contiguous_array_view_iterator operator-(difference_type n) const _NOEXCEPT
2112 {
2113 contiguous_array_view_iterator ret{ *this };
2114 return ret -= n;
2115 }
2116 contiguous_array_view_iterator& operator-=(difference_type n) _NOEXCEPT
2117 {
2118 return *this += -n;
2119 }
2120 difference_type operator-(const contiguous_array_view_iterator& rhs) const _NOEXCEPT
2121 {
2122 fail_fast_assert(m_validator == rhs.m_validator);
2123 return m_pdata - rhs.m_pdata;
2124 }
2125 reference operator[](difference_type n) const _NOEXCEPT
2126 {
2127 return *(*this + n);
2128 }
2129 bool operator==(const contiguous_array_view_iterator& rhs) const _NOEXCEPT
2130 {
2131 fail_fast_assert(m_validator == rhs.m_validator);
2132 return m_pdata == rhs.m_pdata;
2133 }
2134 bool operator!=(const contiguous_array_view_iterator& rhs) const _NOEXCEPT
2135 {
2136 return !(*this == rhs);
2137 }
2138 bool operator<(const contiguous_array_view_iterator& rhs) const _NOEXCEPT
2139 {
2140 fail_fast_assert(m_validator == rhs.m_validator);
2141 return m_pdata < rhs.m_pdata;
2142 }
2143 bool operator<=(const contiguous_array_view_iterator& rhs) const _NOEXCEPT
2144 {
2145 return !(rhs < *this);
2146 }
2147 bool operator>(const contiguous_array_view_iterator& rhs) const _NOEXCEPT
2148 {
2149 return rhs < *this;
2150 }
2151 bool operator>=(const contiguous_array_view_iterator& rhs) const _NOEXCEPT
2152 {
2153 return !(rhs > *this);
2154 }
2155 void swap(contiguous_array_view_iterator& rhs) _NOEXCEPT
2156 {
2157 std::swap(m_pdata, rhs.m_pdata);
2158 std::swap(m_validator, rhs.m_validator);
2159 }
2160};
2161
2162template <typename ArrayView>
2163contiguous_array_view_iterator<ArrayView> operator+(typename contiguous_array_view_iterator<ArrayView>::difference_type n, const contiguous_array_view_iterator<ArrayView>& rhs) _NOEXCEPT
2164{
2165 return rhs + n;
2166}
2167
2168template <typename ArrayView>
2169class general_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
2170{
2171 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
2172public:
2173 using typename Base::reference;
2174 using typename Base::pointer;
2175 using typename Base::difference_type;
2176 using typename Base::value_type;
2177private:
2178 template <typename ValueType, typename Bounds>
2179 friend class basic_array_view;
2180 const ArrayView * m_container;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07002181 typename ArrayView::bounds_type::iterator m_itr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002182 general_array_view_iterator(const ArrayView *container, bool isbegin = false) :
2183 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
2184 {
2185 }
2186public:
2187 reference operator*() const _NOEXCEPT
2188 {
2189 return (*m_container)[*m_itr];
2190 }
2191 pointer operator->() const _NOEXCEPT
2192 {
2193 return &(*m_container)[*m_itr];
2194 }
2195 general_array_view_iterator& operator++() _NOEXCEPT
2196 {
2197 ++m_itr;
2198 return *this;
2199 }
2200 general_array_view_iterator operator++(int)_NOEXCEPT
2201 {
2202 auto ret = *this;
2203 ++(*this);
2204 return ret;
2205 }
2206 general_array_view_iterator& operator--() _NOEXCEPT
2207 {
2208 --m_itr;
2209 return *this;
2210 }
2211 general_array_view_iterator operator--(int)_NOEXCEPT
2212 {
2213 auto ret = *this;
2214 --(*this);
2215 return ret;
2216 }
2217 general_array_view_iterator operator+(difference_type n) const _NOEXCEPT
2218 {
2219 general_array_view_iterator ret{ *this };
2220 return ret += n;
2221 }
2222 general_array_view_iterator& operator+=(difference_type n) _NOEXCEPT
2223 {
2224 m_itr += n;
2225 return *this;
2226 }
2227 general_array_view_iterator operator-(difference_type n) const _NOEXCEPT
2228 {
2229 general_array_view_iterator ret{ *this };
2230 return ret -= n;
2231 }
2232 general_array_view_iterator& operator-=(difference_type n) _NOEXCEPT
2233 {
2234 return *this += -n;
2235 }
2236 difference_type operator-(const general_array_view_iterator& rhs) const _NOEXCEPT
2237 {
2238 fail_fast_assert(m_container == rhs.m_container);
2239 return m_itr - rhs.m_itr;
2240 }
2241 value_type operator[](difference_type n) const _NOEXCEPT
2242 {
2243 return (*m_container)[m_itr[n]];;
2244 }
2245 bool operator==(const general_array_view_iterator& rhs) const _NOEXCEPT
2246 {
2247 fail_fast_assert(m_container == rhs.m_container);
2248 return m_itr == rhs.m_itr;
2249 }
2250 bool operator !=(const general_array_view_iterator& rhs) const _NOEXCEPT
2251 {
2252 return !(*this == rhs);
2253 }
2254 bool operator<(const general_array_view_iterator& rhs) const _NOEXCEPT
2255 {
2256 fail_fast_assert(m_container == rhs.m_container);
2257 return m_itr < rhs.m_itr;
2258 }
2259 bool operator<=(const general_array_view_iterator& rhs) const _NOEXCEPT
2260 {
2261 return !(rhs < *this);
2262 }
2263 bool operator>(const general_array_view_iterator& rhs) const _NOEXCEPT
2264 {
2265 return rhs < *this;
2266 }
2267 bool operator>=(const general_array_view_iterator& rhs) const _NOEXCEPT
2268 {
2269 return !(rhs > *this);
2270 }
2271 void swap(general_array_view_iterator& rhs) _NOEXCEPT
2272 {
2273 std::swap(m_itr, rhs.m_itr);
2274 std::swap(m_container, rhs.m_container);
2275 }
2276};
2277
2278template <typename ArrayView>
2279general_array_view_iterator<ArrayView> operator+(typename general_array_view_iterator<ArrayView>::difference_type n, const general_array_view_iterator<ArrayView>& rhs) _NOEXCEPT
2280{
2281 return rhs + n;
2282}
2283
2284} // namespace Guide
2285
galikcab9bda2015-09-19 07:52:30 +01002286#if _MSC_VER
Neil MacIntosh9a297122015-09-14 15:11:07 -07002287#if _MSC_VER <= 1800
2288#pragma warning(pop)
2289#endif // _MSC_VER <= 1800
galikcab9bda2015-09-19 07:52:30 +01002290#endif
Neil MacIntosh9a297122015-09-14 15:11:07 -07002291
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002292#pragma pop_macro("_NOEXCEPT")