blob: 01457994a476b777fd1da3430c1baa3d6b200ef3 [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>
Anna Gringauze2cdedda2015-10-15 13:19:24 -070027#include <numeric>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070028#include <type_traits>
29#include <utility>
30#include <array>
31#include <iterator>
Kern Handac4f9b872015-09-25 17:01:29 -070032#include <algorithm>
Neil MacIntosh01868f22015-10-15 16:48:38 -070033#include <functional>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070034#include "fail_fast.h"
35
Neil MacIntoshd5316802015-09-30 21:54:08 -070036#ifdef _MSC_VER
37
38// No MSVC does constexpr fully yet
Gabriel Dos Reis6554e832015-09-28 05:10:44 -070039#pragma push_macro("constexpr")
40#define constexpr /* nothing */
Neil MacIntoshd5316802015-09-30 21:54:08 -070041
42
43// VS 2013 workarounds
44#if _MSC_VER <= 1800
45
46// noexcept is not understood
47#ifndef GSL_THROWS_FOR_TESTING
48#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070049#endif
50
Neil MacIntoshd5316802015-09-30 21:54:08 -070051// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070052#pragma warning(push)
53#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
Neil MacIntoshd5316802015-09-30 21:54:08 -070054
Neil MacIntosh9a297122015-09-14 15:11:07 -070055#endif // _MSC_VER <= 1800
56
Neil MacIntoshd5316802015-09-30 21:54:08 -070057#endif // _MSC_VER
58
59// In order to test the library, we need it to throw exceptions that we can catch
60#ifdef GSL_THROWS_FOR_TESTING
61#define noexcept /* nothing */
62#endif // GSL_THROWS_FOR_TESTING
63
64
Neil MacIntoshef626fd2015-09-29 16:41:37 -070065namespace gsl {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070066
67/*
68** begin definitions of index and bounds
69*/
70namespace details
71{
72 template <typename SizeType>
73 struct SizeTypeTraits
74 {
Anna Gringauze5f26dda2015-10-16 17:30:48 -070075 static const SizeType max_value = std::numeric_limits<SizeType>::max();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070076 };
Anna Gringauze1c208b32015-10-16 17:40:57 -070077
78
79 template<typename... Ts>
80 class are_integral : public std::integral_constant<bool, true> {};
81
82 template<typename T, typename... Ts>
83 class are_integral<T, Ts...> : public std::integral_constant<bool, std::is_integral<T>::value && are_integral<Ts...>::value> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070084}
85
Kern Handae1570262015-09-25 00:42:38 -070086template <size_t Rank, typename ValueType = size_t>
Anna Gringauzedb384972015-10-05 12:34:23 -070087class index final
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070088{
Anna Gringauzedb384972015-10-05 12:34:23 -070089 static_assert(std::is_integral<ValueType>::value, "ValueType must be an integral type!");
90 static_assert(Rank > 0, "Rank must be greater than 0!");
91
Kern Handae1570262015-09-25 00:42:38 -070092 template <size_t OtherRank, typename OtherValueType>
Anna Gringauze17ed5c32015-08-30 23:30:15 -070093 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -070094
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070095public:
Anna Gringauzedb384972015-10-05 12:34:23 -070096 static const size_t rank = Rank;
97 using value_type = std::remove_reference_t<ValueType>;
98 using reference = std::add_lvalue_reference_t<value_type>;
99 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700100
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700101 constexpr index() noexcept
102 {}
103
Anna Gringauzedb384972015-10-05 12:34:23 -0700104 constexpr index(const value_type(&values)[Rank]) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700105 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700106 std::copy(values, values + Rank, elems);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700107 }
108
Anna Gringauze1c208b32015-10-16 17:40:57 -0700109 template<typename... Ts, bool Enabled1 = (sizeof...(Ts) == Rank), bool Enabled2 = details::are_integral<Ts...>::value, typename Dummy = std::enable_if_t<Enabled1 && Enabled2, bool>>
Anna Gringauze5f26dda2015-10-16 17:30:48 -0700110 constexpr index(Ts... ds) noexcept : elems{ static_cast<value_type>(ds)... }
111 {}
Anna Gringauzedb384972015-10-05 12:34:23 -0700112
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700113 constexpr index(const index& other) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700114
115 // copy from index over smaller domain
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700116 template <typename OtherValueType,
117 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value <= details::SizeTypeTraits<value_type>::max_value),
118 typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
119 constexpr index(const index<Rank, OtherValueType>& other) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700120 {
121 std::copy(other.elems, other.elems + Rank, elems);
122 }
123
124 // copy from index over larger domain
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700125 template <typename OtherValueType,
126 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value > details::SizeTypeTraits<value_type>::max_value),
127 typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
128 constexpr index(const index<Rank, OtherValueType>& other, void* ptr = 0) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700129 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700130 bool ok = std::accumulate(other.elems, other.elems + Rank, true,
131 [&](bool b, OtherValueType val) { return b && (val <= static_cast<OtherValueType>(details::SizeTypeTraits<value_type>::max_value)); }
132 );
Anna Gringauzedb384972015-10-05 12:34:23 -0700133
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700134 fail_fast_assert(ok, "other value must fit in the new domain");
135 std::transform(other.elems, other.elems + rank, elems, [&](OtherValueType val) { return static_cast<value_type>(val); });
Anna Gringauzedb384972015-10-05 12:34:23 -0700136 }
137
138 constexpr index& operator=(const index& rhs) noexcept = default;
139
140 // Preconditions: component_idx < rank
141 constexpr reference operator[](size_t component_idx)
142 {
143 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
144 return elems[component_idx];
145 }
146
147 // Preconditions: component_idx < rank
148 constexpr const_reference operator[](size_t component_idx) const noexcept
149 {
150 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
151 return elems[component_idx];
152 }
153
154 constexpr bool operator==(const index& rhs) const noexcept
155 {
156 return std::equal(elems, elems + rank, rhs.elems);
157 }
158
159 constexpr bool operator!=(const index& rhs) const noexcept
160 {
161 return !(this == rhs);
162 }
163
164 constexpr index operator+() const noexcept
165 {
166 return *this;
167 }
168
169 constexpr index operator-() const noexcept
170 {
171 index ret = *this;
172 std::transform(ret, ret + rank, ret, std::negate<ValueType>{});
173 return ret;
174 }
175
176 constexpr index operator+(const index& rhs) const noexcept
177 {
178 index ret = *this;
179 ret += rhs;
180 return ret;
181 }
182
183 constexpr index operator-(const index& rhs) const noexcept
184 {
185 index ret = *this;
186 ret -= rhs;
187 return ret;
188 }
189
190 constexpr index& operator+=(const index& rhs) noexcept
191 {
192 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<ValueType>{});
193 return *this;
194 }
195
196 constexpr index& operator-=(const index& rhs) noexcept
197 {
198 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<ValueType>{});
199 return *this;
200 }
201
202 constexpr index operator*(value_type v) const noexcept
203 {
204 index ret = *this;
205 ret *= v;
206 return ret;
207 }
208
209 constexpr index operator/(value_type v) const noexcept
210 {
211 index ret = *this;
212 ret /= v;
213 return ret;
214 }
215
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700216 friend constexpr index operator*(value_type v, const index& rhs) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700217 {
218 return rhs * v;
219 }
220
221 constexpr index& operator*=(value_type v) noexcept
222 {
223 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies<ValueType>{}(x, v); });
224 return *this;
225 }
226
227 constexpr index& operator/=(value_type v) noexcept
228 {
229 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<ValueType>{}(x, v); });
230 return *this;
231 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700232
Anna Gringauzedb384972015-10-05 12:34:23 -0700233private:
234 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700235};
236
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700237#ifndef _MSC_VER
238
239struct static_bounds_dynamic_range_t
240{
241 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
242 constexpr operator T() const noexcept
243 {
244 return static_cast<T>(-1);
245 }
246
247 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
248 constexpr bool operator ==(T other) const noexcept
249 {
250 return static_cast<T>(-1) == other;
251 }
252
253 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
254 constexpr bool operator !=(T other) const noexcept
255 {
256 return static_cast<T>(-1) != other;
257 }
258
259};
260
261template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
262constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
263{
264 return right == left;
265}
266
267template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
268constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
269{
270 return right != left;
271}
272
273constexpr static_bounds_dynamic_range_t dynamic_range{};
274#else
275const char dynamic_range = -1;
276#endif
277
278struct generalized_mapping_tag {};
279struct contiguous_mapping_tag : generalized_mapping_tag {};
280
281namespace details
282{
283 template <typename SizeType, SizeType Fact1, SizeType Fact2, SizeType ConstBound>
284 struct StaticSizeHelperImpl
285 {
286 static_assert(static_cast<size_t>(Fact1) * static_cast<size_t>(Fact2) <= SizeTypeTraits<SizeType>::max_value, "Value out of the range of SizeType");
287 static const SizeType value = Fact1 * Fact2;
288 };
289
290 template <typename SizeType, SizeType Fact1, SizeType ConstBound>
291 struct StaticSizeHelperImpl<SizeType, Fact1, ConstBound, ConstBound>
292 {
293 static const SizeType value = ConstBound;
294 };
295
296 template <typename SizeType, SizeType Fact2, SizeType ConstBound>
297 struct StaticSizeHelperImpl<SizeType, ConstBound, Fact2, ConstBound>
298 {
299 static const SizeType value = ConstBound;
300 };
301
302 template <typename SizeType, SizeType ConstBound>
303 struct StaticSizeHelperImpl<SizeType, ConstBound, ConstBound, ConstBound>
304 {
305 static const SizeType value = static_cast<SizeType>(ConstBound);
306 };
307
308 template <typename SizeType, SizeType Fact1, SizeType Fact2>
309 struct StaticSizeHelper
310 {
311 static const SizeType value = StaticSizeHelperImpl<SizeType, static_cast<SizeType>(Fact1), static_cast<SizeType>(Fact2), static_cast<SizeType>(dynamic_range)>::value;
312 };
313
314
315 template <size_t Left, size_t Right>
316 struct LessThan
317 {
318 static const bool value = Left < Right;
319 };
320
321 template <typename SizeType, size_t... Ranges>
322 struct BoundsRanges {
Kern Handae1570262015-09-25 00:42:38 -0700323 static const size_t Depth = 0;
324 static const size_t DynamicNum = 0;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700325 static const SizeType CurrentRange = 1;
326 static const SizeType TotalSize = 1;
327
328 BoundsRanges (const BoundsRanges &) = default;
329
330 // TODO : following signature is for work around VS bug
331 template <typename OtherType>
Kosov Eugene3402b922015-09-28 21:20:02 +0300332 BoundsRanges (const OtherType &, bool /* firstLevel */) {}
galikcab9bda2015-09-19 07:52:30 +0100333 BoundsRanges(const SizeType * const) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700334 BoundsRanges() = default;
335
336
Kern Handae1570262015-09-25 00:42:38 -0700337 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700338 void serialize(T &) const {
339 }
Kern Handae1570262015-09-25 00:42:38 -0700340 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700341 SizeType linearize(const T &) const {
342 return 0;
343 }
Kern Handae1570262015-09-25 00:42:38 -0700344 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700345 ptrdiff_t contains(const T &) const {
346 return 0;
347 }
348
Neil MacIntoshd5316802015-09-30 21:54:08 -0700349 size_t totalSize() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700350 return TotalSize;
351 }
352
Neil MacIntoshd5316802015-09-30 21:54:08 -0700353 bool operator == (const BoundsRanges &) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700354 {
355 return true;
356 }
357 };
358
359 template <typename SizeType, size_t... RestRanges>
360 struct BoundsRanges <SizeType, dynamic_range, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
361 using Base = BoundsRanges <SizeType, RestRanges... >;
Kern Handae1570262015-09-25 00:42:38 -0700362 static const size_t Depth = Base::Depth + 1;
363 static const size_t DynamicNum = Base::DynamicNum + 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700364 static const SizeType CurrentRange = dynamic_range;
365 static const SizeType TotalSize = dynamic_range;
366 const SizeType m_bound;
367
368 BoundsRanges (const BoundsRanges &) = default;
369 BoundsRanges(const SizeType * const arr) : Base(arr + 1), m_bound(static_cast<SizeType>(*arr * this->Base::totalSize()))
370 {
371 fail_fast_assert(0 <= *arr);
372 fail_fast_assert(*arr * this->Base::totalSize() <= details::SizeTypeTraits<SizeType>::max_value);
373 }
374 BoundsRanges() : m_bound(0) {}
375
376 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
Kosov Eugene3402b922015-09-28 21:20:02 +0300377 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool /* firstLevel */ = true) :
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700378 Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false), m_bound (static_cast<SizeType>(other.totalSize()))
379 {
380 }
381
Kern Handae1570262015-09-25 00:42:38 -0700382 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700383 void serialize(T & arr) const {
384 arr[Dim] = elementNum();
385 this->Base::template serialize<T, Dim + 1>(arr);
386 }
Kern Handae1570262015-09-25 00:42:38 -0700387 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700388 SizeType linearize(const T & arr) const {
389 const size_t index = this->Base::totalSize() * arr[Dim];
390 fail_fast_assert(index < static_cast<size_t>(m_bound));
391 return static_cast<SizeType>(index) + this->Base::template linearize<T, Dim + 1>(arr);
392 }
393
Kern Handae1570262015-09-25 00:42:38 -0700394 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700395 ptrdiff_t contains(const T & arr) const {
396 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
397 if (last == -1)
398 return -1;
399 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
400 return static_cast<size_t>(cur) < static_cast<size_t>(m_bound) ? cur + last : -1;
401 }
402
Neil MacIntoshd5316802015-09-30 21:54:08 -0700403 size_t totalSize() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700404 return m_bound;
405 }
406
Neil MacIntoshd5316802015-09-30 21:54:08 -0700407 SizeType elementNum() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700408 return static_cast<SizeType>(totalSize() / this->Base::totalSize());
409 }
410
Neil MacIntoshd5316802015-09-30 21:54:08 -0700411 SizeType elementNum(size_t dim) const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700412 if (dim > 0)
413 return this->Base::elementNum(dim - 1);
414 else
415 return elementNum();
416 }
417
Neil MacIntoshd5316802015-09-30 21:54:08 -0700418 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700419 {
420 return m_bound == rhs.m_bound && static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
421 }
422 };
423
424 template <typename SizeType, size_t CurRange, size_t... RestRanges>
425 struct BoundsRanges <SizeType, CurRange, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
426 using Base = BoundsRanges <SizeType, RestRanges... >;
Kern Handae1570262015-09-25 00:42:38 -0700427 static const size_t Depth = Base::Depth + 1;
428 static const size_t DynamicNum = Base::DynamicNum;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700429 static const SizeType CurrentRange = static_cast<SizeType>(CurRange);
430 static const SizeType TotalSize = StaticSizeHelper<SizeType, Base::TotalSize, CurrentRange>::value;
431 static_assert (CurRange <= SizeTypeTraits<SizeType>::max_value, "CurRange must be smaller than SizeType limits");
432
433 BoundsRanges (const BoundsRanges &) = default;
434 BoundsRanges(const SizeType * const arr) : Base(arr) { }
435 BoundsRanges() = default;
436
437 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
438 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false)
439 {
440 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
441 }
442
Kern Handae1570262015-09-25 00:42:38 -0700443 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700444 void serialize(T & arr) const {
445 arr[Dim] = elementNum();
446 this->Base::template serialize<T, Dim + 1>(arr);
447 }
448
Kern Handae1570262015-09-25 00:42:38 -0700449 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700450 SizeType linearize(const T & arr) const {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700451 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700452 return static_cast<SizeType>(this->Base::totalSize()) * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
453 }
454
Kern Handae1570262015-09-25 00:42:38 -0700455 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700456 ptrdiff_t contains(const T & arr) const {
457 if (static_cast<size_t>(arr[Dim]) >= CurrentRange)
458 return -1;
459 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
460 if (last == -1)
461 return -1;
462 return static_cast<ptrdiff_t>(this->Base::totalSize() * arr[Dim]) + last;
463 }
464
Neil MacIntoshd5316802015-09-30 21:54:08 -0700465 size_t totalSize() const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700466 return CurrentRange * this->Base::totalSize();
467 }
468
Neil MacIntoshd5316802015-09-30 21:54:08 -0700469 SizeType elementNum() const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700470 return CurrentRange;
471 }
472
Neil MacIntoshd5316802015-09-30 21:54:08 -0700473 SizeType elementNum(size_t dim) const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700474 if (dim > 0)
475 return this->Base::elementNum(dim - 1);
476 else
477 return elementNum();
478 }
479
Neil MacIntoshd5316802015-09-30 21:54:08 -0700480 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700481 {
482 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
483 }
484 };
485
486 template <typename SourceType, typename TargetType, size_t Rank>
487 struct BoundsRangeConvertible2;
488
489 // TODO: I have to rewrite BoundsRangeConvertible into following way to workaround VS 2013 bugs
490 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
491 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
492
493 template <size_t Rank, typename SourceType, typename TargetType>
494 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
495
496 template <typename SourceType, typename TargetType, size_t Rank>
497 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
498 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
499 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
500 {};
501
502 template <typename SourceType, typename TargetType>
503 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
504
505 template <typename SourceType, typename TargetType, size_t Rank = TargetType::Depth>
506 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
507 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
508 && (!LessThan<size_t(SourceType::CurrentRange), size_t(TargetType::CurrentRange)>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
509 {};
510 template <typename SourceType, typename TargetType>
511 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
512
513 template <typename TypeChain>
514 struct TypeListIndexer
515 {
516 const TypeChain & obj;
517 TypeListIndexer(const TypeChain & obj) :obj(obj){}
Kern Handae1570262015-09-25 00:42:38 -0700518 template<size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700519 const TypeChain & getObj(std::true_type)
520 {
521 return obj;
522 }
Kern Handae1570262015-09-25 00:42:38 -0700523 template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700524 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
525 {
526 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
527 }
Kern Handae1570262015-09-25 00:42:38 -0700528 template <size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700529 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
530 {
531 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
532 }
533 };
534
535 template <typename TypeChain>
536 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
537 {
538 return TypeListIndexer<TypeChain>(obj);
539 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700540
541 template <size_t Rank, typename ValueType, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1, ValueType>>>
542 constexpr Ret shift_left(const index<Rank, ValueType>& other) noexcept
543 {
544 Ret ret;
545 for (size_t i = 0; i < Rank - 1; ++i)
546 {
547 ret[i] = other[i + 1];
548 }
549 return ret;
550 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700551}
552
553template <typename IndexType>
554class bounds_iterator;
555
556template <typename SizeType, size_t... Ranges>
557class static_bounds {
558public:
Kosov Eugene3402b922015-09-28 21:20:02 +0300559 static_bounds(const details::BoundsRanges<SizeType, Ranges...> &) {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700560 }
561};
562
563template <typename SizeType, size_t FirstRange, size_t... RestRanges>
564class static_bounds<SizeType, FirstRange, RestRanges...>
565{
566 using MyRanges = details::BoundsRanges <SizeType, FirstRange, RestRanges... >;
567 static_assert(std::is_integral<SizeType>::value
568 && details::SizeTypeTraits<SizeType>::max_value <= SIZE_MAX, "SizeType must be an integral type and its numeric limits must be smaller than SIZE_MAX");
569
570 MyRanges m_ranges;
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700571 constexpr static_bounds(const MyRanges & range) : m_ranges(range) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700572
573 template <typename SizeType2, size_t... Ranges2>
574 friend class static_bounds;
575public:
Kern Handae1570262015-09-25 00:42:38 -0700576 static const size_t rank = MyRanges::Depth;
577 static const size_t dynamic_rank = MyRanges::DynamicNum;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700578 static const SizeType static_size = static_cast<SizeType>(MyRanges::TotalSize);
579
580 using size_type = SizeType;
581 using index_type = index<rank, size_type>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700582 using const_index_type = std::add_const_t<index_type>;
583 using iterator = bounds_iterator<const_index_type>;
584 using const_iterator = bounds_iterator<const_index_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700585 using difference_type = ptrdiff_t;
586 using sliced_type = static_bounds<SizeType, RestRanges...>;
587 using mapping_type = contiguous_mapping_tag;
588public:
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700589 constexpr static_bounds(const static_bounds &) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700590
591 template <typename OtherSizeType, size_t... Ranges, typename Dummy = std::enable_if_t<
592 details::BoundsRangeConvertible<details::BoundsRanges<OtherSizeType, Ranges...>, details::BoundsRanges <SizeType, FirstRange, RestRanges... >>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700593 constexpr static_bounds(const static_bounds<OtherSizeType, Ranges...> &other):
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700594 m_ranges(other.m_ranges)
595 {
596 }
597
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700598 constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700599 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700600 fail_fast_assert(MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
601 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 -0700602 }
603
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700604 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700605
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700606 constexpr static_bounds & operator = (const static_bounds & otherBounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700607 {
608 new(&m_ranges) MyRanges (otherBounds.m_ranges);
609 return *this;
610 }
611
Neil MacIntoshd5316802015-09-30 21:54:08 -0700612 constexpr sliced_type slice() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700613 {
614 return sliced_type{static_cast<const details::BoundsRanges<SizeType, RestRanges...> &>(m_ranges)};
615 }
616
Neil MacIntoshd5316802015-09-30 21:54:08 -0700617 constexpr size_type stride() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700618 {
619 return rank > 1 ? slice().size() : 1;
620 }
621
Neil MacIntoshd5316802015-09-30 21:54:08 -0700622 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700623 {
624 return static_cast<size_type>(m_ranges.totalSize());
625 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700626
Neil MacIntoshd5316802015-09-30 21:54:08 -0700627 constexpr size_type total_size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700628 {
629 return static_cast<size_type>(m_ranges.totalSize());
630 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700631
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700632 constexpr size_type linearize(const index_type & idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700633 {
634 return m_ranges.linearize(idx);
635 }
636
Neil MacIntoshd5316802015-09-30 21:54:08 -0700637 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700638 {
639 return m_ranges.contains(idx) != -1;
640 }
641
Neil MacIntoshd5316802015-09-30 21:54:08 -0700642 constexpr size_type operator[](size_t index) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700643 {
644 return m_ranges.elementNum(index);
645 }
646
Kern Handae1570262015-09-25 00:42:38 -0700647 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700648 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700649 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700650 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700651 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
652 }
653
Neil MacIntoshd5316802015-09-30 21:54:08 -0700654 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700655 {
Anna Gringauzefdf86432015-10-14 10:46:22 -0700656 size_type extents[rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700657 m_ranges.serialize(extents);
Anna Gringauzedb384972015-10-05 12:34:23 -0700658 return{ extents };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700659 }
660
661 template <typename OtherSizeTypes, size_t... Ranges>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700662 constexpr bool operator == (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700663 {
664 return this->size() == rhs.size();
665 }
666
667 template <typename OtherSizeTypes, size_t... Ranges>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700668 constexpr bool operator != (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700669 {
670 return !(*this == rhs);
671 }
672
Neil MacIntoshd5316802015-09-30 21:54:08 -0700673 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700674 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700675 return const_iterator(*this, index_type{});
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700676 }
677
Neil MacIntoshd5316802015-09-30 21:54:08 -0700678 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700679 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700680 return const_iterator(*this, this->index_bounds());
681 }
682};
683
Kern Handae1570262015-09-25 00:42:38 -0700684template <size_t Rank, typename SizeType = size_t>
Anna Gringauzedb384972015-10-05 12:34:23 -0700685class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700686{
Kern Handae1570262015-09-25 00:42:38 -0700687 template <size_t OtherRank, typename OtherSizeType>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700688 friend class strided_bounds;
689
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700690public:
Anna Gringauzedb384972015-10-05 12:34:23 -0700691 static const size_t rank = Rank;
Anna Gringauzefdf86432015-10-14 10:46:22 -0700692 using reference = SizeType&;
693 using const_reference = const SizeType&;
694 using size_type = SizeType;
695 using difference_type = SizeType;
696 using value_type = SizeType;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700697 using index_type = index<rank, size_type>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700698 using const_index_type = std::add_const_t<index_type>;
699 using iterator = bounds_iterator<const_index_type>;
700 using const_iterator = bounds_iterator<const_index_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700701 static const int dynamic_rank = rank;
702 static const size_t static_size = dynamic_range;
703 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
704 using mapping_type = generalized_mapping_tag;
Anna Gringauzedb384972015-10-05 12:34:23 -0700705 constexpr strided_bounds(const strided_bounds &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700706
707 template <typename OtherSizeType>
Anna Gringauzedb384972015-10-05 12:34:23 -0700708 constexpr strided_bounds(const strided_bounds<rank, OtherSizeType> &other) noexcept
709 : m_extents(other.extents), m_strides(other.strides)
710 {}
711 constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept
712 : m_extents(extents), m_strides(strides)
713 {}
Neil MacIntoshd5316802015-09-30 21:54:08 -0700714 constexpr index_type strides() const noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700715 {
716 return m_strides;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700717 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700718 constexpr size_type total_size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700719 {
720 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700721 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700722 {
723 ret += (m_extents[i] - 1) * m_strides[i];
724 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700725 return ret + 1;
726 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700727 constexpr size_type size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700728 {
729 size_type ret = 1;
Kern Handae1570262015-09-25 00:42:38 -0700730 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700731 {
732 ret *= m_extents[i];
733 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700734 return ret;
735 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700736 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700737 {
Kern Handae1570262015-09-25 00:42:38 -0700738 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700739 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700740 if (idx[i] < 0 || idx[i] >= m_extents[i])
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700741 return false;
742 }
743 return true;
744 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700745 constexpr size_type linearize(const index_type & idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700746 {
747 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700748 for (size_t i = 0; i < rank; i++)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700749 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700750 fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700751 ret += idx[i] * m_strides[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700752 }
753 return ret;
754 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700755 constexpr size_type stride() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700756 {
757 return m_strides[0];
758 }
759 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700760 constexpr sliced_type slice() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700761 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700762 return{ details::shift_left(m_extents), details::shift_left(m_strides) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700763 }
Kern Handae1570262015-09-25 00:42:38 -0700764 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700765 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700766 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700767 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
Anna Gringauzedb384972015-10-05 12:34:23 -0700768 return m_extents[Dim];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700769 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700770 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700771 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700772 return m_extents;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700773 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700774 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700775 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700776 return const_iterator{ *this, index_type{} };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700777 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700778 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700779 {
780 return const_iterator{ *this, index_bounds() };
781 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700782private:
Anna Gringauzedb384972015-10-05 12:34:23 -0700783 index_type m_extents;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700784 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700785};
786
787template <typename T>
788struct is_bounds : std::integral_constant<bool, false> {};
789template <typename SizeType, size_t... Ranges>
790struct is_bounds<static_bounds<SizeType, Ranges...>> : std::integral_constant<bool, true> {};
Kern Handae1570262015-09-25 00:42:38 -0700791template <size_t Rank, typename SizeType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700792struct is_bounds<strided_bounds<Rank, SizeType>> : std::integral_constant<bool, true> {};
793
794template <typename IndexType>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700795class bounds_iterator: public std::iterator<std::random_access_iterator_tag, IndexType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700796{
797private:
Anna Gringauzea4654a42015-10-16 12:15:22 -0700798 using Base = std::iterator <std::random_access_iterator_tag, IndexType>;
799
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700800public:
Kern Handae1570262015-09-25 00:42:38 -0700801 static const size_t rank = IndexType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700802 using typename Base::reference;
803 using typename Base::pointer;
804 using typename Base::difference_type;
805 using typename Base::value_type;
806 using index_type = value_type;
Anna Gringauzedb384972015-10-05 12:34:23 -0700807 using index_size_type = typename IndexType::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700808 template <typename Bounds>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700809 explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
810 : boundary(bnd.index_bounds()), curr(std::move(curr))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700811 {
812 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
813 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700814
815 constexpr reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700816 {
817 return curr;
818 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700819
820 constexpr pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700821 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700822 return &curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700823 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700824
825 constexpr bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700826 {
Kern Handae1570262015-09-25 00:42:38 -0700827 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700828 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700829 if (curr[i] < boundary[i] - 1)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700830 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700831 curr[i]++;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700832 return *this;
833 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700834 curr[i] = 0;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700835 }
836 // If we're here we've wrapped over - set to past-the-end.
Anna Gringauzea4654a42015-10-16 12:15:22 -0700837 curr = boundary;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700838 return *this;
839 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700840
841 constexpr bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700842 {
843 auto ret = *this;
844 ++(*this);
845 return ret;
846 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700847
848 constexpr bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700849 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700850 if (!less(curr, boundary))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700851 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700852 // if at the past-the-end, set to last element
853 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700854 {
855 curr[i] = boundary[i] - 1;
856 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700857 return *this;
858 }
859 for (size_t i = rank; i-- > 0;)
860 {
861 if (curr[i] >= 1)
862 {
863 curr[i]--;
864 return *this;
865 }
866 curr[i] = boundary[i] - 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700867 }
868 // If we're here the preconditions were violated
869 // "pre: there exists s such that r == ++s"
870 fail_fast_assert(false);
871 return *this;
872 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700873
874 constexpr bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700875 {
876 auto ret = *this;
877 --(*this);
878 return ret;
879 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700880
881 constexpr bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700882 {
883 bounds_iterator ret{ *this };
884 return ret += n;
885 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700886
887 constexpr bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700888 {
889 auto linear_idx = linearize(curr) + n;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700890 std::remove_const_t<value_type> stride;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700891 stride[rank - 1] = 1;
Kern Handae1570262015-09-25 00:42:38 -0700892 for (size_t i = rank - 1; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700893 {
894 stride[i] = stride[i + 1] * boundary[i + 1];
895 }
Kern Handae1570262015-09-25 00:42:38 -0700896 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700897 {
898 curr[i] = linear_idx / stride[i];
899 linear_idx = linear_idx % stride[i];
900 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700901 fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700902 return *this;
903 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700904
905 constexpr bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700906 {
907 bounds_iterator ret{ *this };
908 return ret -= n;
909 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700910
911 constexpr bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700912 {
913 return *this += -n;
914 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700915
916 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700917 {
918 return linearize(curr) - linearize(rhs.curr);
919 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700920
921 constexpr reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700922 {
923 return *(*this + n);
924 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700925
926 constexpr bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700927 {
928 return curr == rhs.curr;
929 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700930
931 constexpr bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700932 {
933 return !(*this == rhs);
934 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700935
936 constexpr bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700937 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700938 return less(curr, rhs.curr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700939 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700940
941 constexpr bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700942 {
943 return !(rhs < *this);
944 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700945
946 constexpr bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700947 {
948 return rhs < *this;
949 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700950
951 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700952 {
953 return !(rhs > *this);
954 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700955
Neil MacIntoshd5316802015-09-30 21:54:08 -0700956 void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700957 {
958 std::swap(boundary, rhs.boundary);
959 std::swap(curr, rhs.curr);
960 }
961private:
Anna Gringauzea4654a42015-10-16 12:15:22 -0700962 constexpr bool less(index_type& one, index_type& other) const noexcept
963 {
964 for (size_t i = 0; i < rank; ++i)
965 {
966 if (one[i] < other[i])
967 return true;
968 }
969 return false;
970 }
971
972 constexpr index_size_type linearize(const value_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700973 {
974 // TODO: Smarter impl.
975 // Check if past-the-end
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700976 index_size_type multiplier = 1;
977 index_size_type res = 0;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700978 if (!less(idx, boundary))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700979 {
980 res = 1;
Kern Handae1570262015-09-25 00:42:38 -0700981 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700982 {
983 res += (idx[i] - 1) * multiplier;
984 multiplier *= boundary[i];
985 }
986 }
987 else
988 {
Kern Handae1570262015-09-25 00:42:38 -0700989 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700990 {
991 res += idx[i] * multiplier;
992 multiplier *= boundary[i];
993 }
994 }
995 return res;
996 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700997
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700998 value_type boundary;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700999 std::remove_const_t<value_type> curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001000};
1001
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001002template <typename IndexType>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001003bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001004{
1005 return rhs + n;
1006}
1007
1008/*
1009** begin definitions of basic_array_view
1010*/
1011namespace details
1012{
1013 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001014 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 -07001015 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001016 return bnd.strides();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001017 }
1018
Neil MacIntosh99746e22015-09-27 16:53:58 -07001019 // Make a stride vector from bounds, assuming contiguous memory.
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001020 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001021 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 -07001022 {
1023 auto extents = bnd.index_bounds();
Anna Gringauzefdf86432015-10-14 10:46:22 -07001024 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001025
1026 stride[Bounds::rank - 1] = 1;
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001027 for (size_t i = 1; i < Bounds::rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -07001028 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001029 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
Anna Gringauzedb384972015-10-05 12:34:23 -07001030 }
1031 return{ stride };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001032 }
1033
1034 template <typename BoundsSrc, typename BoundsDest>
1035 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1036 {
1037 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1038 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1039 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");
1040 fail_fast_assert(src.size() == dest.size());
1041 }
1042
1043
1044} // namespace details
1045
1046template <typename ArrayView>
1047class contiguous_array_view_iterator;
1048template <typename ArrayView>
1049class general_array_view_iterator;
1050enum class byte : std::uint8_t {};
1051
1052template <typename ValueType, typename BoundsType>
1053class basic_array_view
1054{
1055public:
Kern Handae1570262015-09-25 00:42:38 -07001056 static const size_t rank = BoundsType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001057 using bounds_type = BoundsType;
1058 using size_type = typename bounds_type::size_type;
1059 using index_type = typename bounds_type::index_type;
1060 using value_type = ValueType;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001061 using const_value_type = std::add_const_t<value_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001062 using pointer = ValueType*;
1063 using reference = ValueType&;
1064 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>>;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001065 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_value_type, BoundsType>>, general_array_view_iterator<basic_array_view<const_value_type, BoundsType>>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001066 using reverse_iterator = std::reverse_iterator<iterator>;
1067 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1068 using sliced_type = std::conditional_t<rank == 1, value_type, basic_array_view<value_type, typename BoundsType::sliced_type>>;
1069
1070private:
1071 pointer m_pdata;
1072 bounds_type m_bounds;
1073
1074public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001075 constexpr bounds_type bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001076 {
1077 return m_bounds;
1078 }
Kern Handae1570262015-09-25 00:42:38 -07001079 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001080 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001081 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001082 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001083 return m_bounds.template extent<Dim>();
1084 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001085 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001086 {
1087 return m_bounds.size();
1088 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001089 constexpr reference operator[](const index_type& idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001090 {
1091 return m_pdata[m_bounds.linearize(idx)];
1092 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001093 constexpr pointer data() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001094 {
1095 return m_pdata;
1096 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001097 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001098 constexpr Ret operator[](size_type idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001099 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001100 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001101 const size_type ridx = idx * m_bounds.stride();
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001102
1103 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001104 return Ret {m_pdata + ridx, m_bounds.slice()};
1105 }
1106
Neil MacIntoshd5316802015-09-30 21:54:08 -07001107 constexpr operator bool () const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001108 {
1109 return m_pdata != nullptr;
1110 }
1111
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001112 constexpr iterator begin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001113 {
1114 return iterator {this, true};
1115 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001116 constexpr iterator end() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001117 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001118 return iterator {this, false};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001119 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001120 constexpr const_iterator cbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001121 {
1122 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), true};
1123 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001124 constexpr const_iterator cend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001125 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001126 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), false};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001127 }
1128
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001129 constexpr reverse_iterator rbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001130 {
1131 return reverse_iterator {end()};
1132 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001133 constexpr reverse_iterator rend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001134 {
1135 return reverse_iterator {begin()};
1136 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001137 constexpr const_reverse_iterator crbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001138 {
1139 return const_reverse_iterator {cend()};
1140 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001141 constexpr const_reverse_iterator crend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001142 {
1143 return const_reverse_iterator {cbegin()};
1144 }
1145
1146 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 -07001147 constexpr bool operator== (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001148 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001149 return m_bounds.size() == other.m_bounds.size() &&
1150 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001151 }
1152
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001153 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 -07001154 constexpr bool operator!= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001155 {
1156 return !(*this == other);
1157 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001158
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001159 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 -07001160 constexpr bool operator< (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001161 {
1162 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1163 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001164
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001165 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 -07001166 constexpr bool operator<= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001167 {
1168 return !(other < *this);
1169 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001170
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001171 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 -07001172 constexpr bool operator> (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001173 {
1174 return (other < *this);
1175 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001176
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001177 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 -07001178 constexpr bool operator>= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001179 {
1180 return !(*this < other);
1181 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001182
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001183public:
1184 template <typename OtherValueType, typename OtherBounds,
1185 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value
1186 && std::is_convertible<OtherBounds, bounds_type>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001187 constexpr basic_array_view(const basic_array_view<OtherValueType, OtherBounds> & other ) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001188 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
1189 {
1190 }
1191protected:
1192
Neil MacIntoshd5316802015-09-30 21:54:08 -07001193 constexpr basic_array_view(pointer data, bounds_type bound) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001194 : m_pdata(data)
1195 , m_bounds(std::move(bound))
1196 {
1197 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1198 }
1199 template <typename T>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001200 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 -07001201 : m_pdata(reinterpret_cast<pointer>(data))
1202 , m_bounds(std::move(bound))
1203 {
1204 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1205 }
1206 template <typename DestBounds>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001207 constexpr basic_array_view<value_type, DestBounds> as_array_view(const DestBounds &bounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001208 {
1209 details::verifyBoundsReshape(m_bounds, bounds);
1210 return {m_pdata, bounds};
1211 }
1212private:
1213
1214 friend iterator;
1215 friend const_iterator;
1216 template <typename ValueType2, typename BoundsType2>
1217 friend class basic_array_view;
1218};
1219
1220template <size_t DimSize = dynamic_range>
1221struct dim
1222{
1223 static const size_t value = DimSize;
1224};
1225template <>
1226struct dim<dynamic_range>
1227{
1228 static const size_t value = dynamic_range;
1229 const size_t dvalue;
1230 dim(size_t size) : dvalue(size) {}
1231};
1232
1233template <typename ValueTypeOpt, size_t FirstDimension = dynamic_range, size_t... RestDimensions>
1234class array_view;
Kern Handae1570262015-09-25 00:42:38 -07001235template <typename ValueTypeOpt, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001236class strided_array_view;
1237
1238namespace details
1239{
1240 template <typename T, typename = std::true_type>
1241 struct ArrayViewTypeTraits
1242 {
1243 using value_type = T;
1244 using size_type = size_t;
1245 };
1246
1247 template <typename Traits>
1248 struct ArrayViewTypeTraits<Traits, typename std::is_reference<typename Traits::array_view_traits &>::type>
1249 {
1250 using value_type = typename Traits::array_view_traits::value_type;
1251 using size_type = typename Traits::array_view_traits::size_type;
1252 };
1253
1254 template <typename T, typename SizeType, size_t... Ranks>
1255 struct ArrayViewArrayTraits {
1256 using type = array_view<T, Ranks...>;
1257 using value_type = T;
1258 using bounds_type = static_bounds<SizeType, Ranks...>;
1259 using pointer = T*;
1260 using reference = T&;
1261 };
1262 template <typename T, typename SizeType, size_t N, size_t... Ranks>
1263 struct ArrayViewArrayTraits<T[N], SizeType, Ranks...> : ArrayViewArrayTraits<T, SizeType, Ranks..., N> {};
1264
1265 template <typename BoundsType>
1266 BoundsType newBoundsHelperImpl(size_t totalSize, std::true_type) // dynamic size
1267 {
1268 fail_fast_assert(totalSize <= details::SizeTypeTraits<typename BoundsType::size_type>::max_value);
1269 return BoundsType{static_cast<typename BoundsType::size_type>(totalSize)};
1270 }
1271 template <typename BoundsType>
1272 BoundsType newBoundsHelperImpl(size_t totalSize, std::false_type) // static size
1273 {
1274 fail_fast_assert(BoundsType::static_size == totalSize);
1275 return {};
1276 }
1277 template <typename BoundsType>
1278 BoundsType newBoundsHelper(size_t totalSize)
1279 {
1280 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1281 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1282 }
1283
1284 struct Sep{};
1285
1286 template <typename T, typename... Args>
1287 T static_as_array_view_helper(Sep, Args... args)
1288 {
1289 return T{static_cast<typename T::size_type>(args)...};
1290 }
1291 template <typename T, typename Arg, typename... Args>
1292 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)
1293 {
1294 return static_as_array_view_helper<T>(args...);
1295 }
1296 template <typename T, typename... Args>
1297 T static_as_array_view_helper(dim<dynamic_range> val, Args ... args)
1298 {
1299 return static_as_array_view_helper<T>(args..., val.dvalue);
1300 }
1301
1302 template <typename SizeType, typename ...Dimensions>
1303 struct static_as_array_view_static_bounds_helper
1304 {
1305 using type = static_bounds<SizeType, (Dimensions::value)...>;
1306 };
1307
1308 template <typename T>
1309 struct is_array_view_oracle : std::false_type
1310 {};
1311 template <typename ValueType, size_t FirstDimension, size_t... RestDimensions>
1312 struct is_array_view_oracle<array_view<ValueType, FirstDimension, RestDimensions...>> : std::true_type
1313 {};
Kern Handae1570262015-09-25 00:42:38 -07001314 template <typename ValueType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001315 struct is_array_view_oracle<strided_array_view<ValueType, Rank>> : std::true_type
1316 {};
1317 template <typename T>
1318 struct is_array_view : is_array_view_oracle<std::remove_cv_t<T>>
1319 {};
1320
1321}
1322
1323
1324template <typename ValueType, typename SizeType>
1325struct array_view_options
1326{
1327 struct array_view_traits
1328 {
1329 using value_type = ValueType;
1330 using size_type = SizeType;
1331 };
1332};
1333
1334template <typename ValueTypeOpt, size_t FirstDimension, size_t... RestDimensions>
1335class array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
1336 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>
1337{
1338 template <typename ValueTypeOpt2, size_t FirstDimension2, size_t... RestDimensions2>
1339 friend class array_view;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001340 using Base = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001341 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001342
1343public:
1344 using typename Base::bounds_type;
1345 using typename Base::size_type;
1346 using typename Base::pointer;
1347 using typename Base::value_type;
1348 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001349 using typename Base::iterator;
1350 using typename Base::const_iterator;
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001351 using typename Base::reference;
Neil MacIntosh383dc502015-09-14 15:41:40 -07001352 using Base::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001353
1354public:
1355 // basic
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001356 constexpr array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001357 {
1358 }
1359
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001360 constexpr array_view(std::nullptr_t) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001361 {
1362 }
1363
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001364 constexpr array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001365 {
1366 fail_fast_assert(size == 0);
1367 }
1368
1369 // default
1370 template <size_t DynamicRank = bounds_type::dynamic_rank, typename Dummy = std::enable_if_t<DynamicRank != 0>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001371 constexpr array_view() : Base(nullptr, bounds_type())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001372 {
1373 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001374
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001375 // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
1376 template <typename T, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001377 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type (*)[], typename Base::value_type (*)[]>::value
1378 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001379 constexpr array_view(T * const & data, size_type size) : Base(data, typename Helper::bounds_type{size})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001380 {
1381 }
1382
1383 // from n-dimensions static array
1384 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, N>,
1385 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 -07001386 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001387 constexpr array_view (T (&arr)[N]) : Base(arr, typename Helper::bounds_type())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001388 {
1389 }
1390
1391 // from n-dimensions static array with size
1392 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
1393 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 -07001394 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value >>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001395 constexpr array_view(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{ size })
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001396 {
1397 fail_fast_assert(size <= N);
1398 }
1399
1400 // from std array
1401 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 -07001402 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 -07001403 {
1404 }
1405
1406 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 -07001407 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 -07001408 {
1409 }
1410
1411
1412 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1413 template <typename Ptr,
1414 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
1415 && details::LessThan<Base::bounds_type::dynamic_rank, 2>::value>> // remove literal 0 case
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001416 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 -07001417 {
1418 }
1419
1420 // from containers. It must has .size() and .data() two function signatures
1421 template <typename Cont, typename DataType = typename Cont::value_type, typename SizeType = typename Cont::size_type,
1422 typename Dummy = std::enable_if_t<!details::is_array_view<Cont>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001423 && std::is_convertible<DataType (*)[], typename Base::value_type (*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001424 && std::is_convertible<static_bounds<SizeType, dynamic_range>, typename Base::bounds_type>::value
1425 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001426 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001427 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 -07001428 {
1429
1430 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001431
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001432 constexpr array_view(const array_view &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001433
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001434 // convertible
1435 template <typename OtherValueTypeOpt, size_t... OtherDimensions,
1436 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>,
1437 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type, OtherDimensions...>>,
1438 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1439 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001440 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 -07001441
1442 // reshape
1443 template <typename... Dimensions2>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001444 constexpr array_view<ValueTypeOpt, Dimensions2::value...> as_array_view(Dimensions2... dims)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001445 {
1446 static_assert(sizeof...(Dimensions2) > 0, "the target array_view must have at least one dimension.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001447 using BoundsType = typename array_view<ValueTypeOpt, (Dimensions2::value)...>::bounds_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001448 auto tobounds = details::static_as_array_view_helper<BoundsType>(dims..., details::Sep{});
1449 details::verifyBoundsReshape(this->bounds(), tobounds);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001450 return {this->data(), tobounds};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001451 }
1452
1453 // to bytes array
1454 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001455 constexpr auto as_bytes() const noexcept ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001456 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)>
1457 {
1458 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001459 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001460 }
1461
1462 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001463 constexpr auto as_writeable_bytes() const noexcept ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001464 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)>
1465 {
1466 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001467 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001468 }
1469
Anna Gringauze18cd9802015-09-14 16:34:26 -07001470
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001471 // from bytes array
1472 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 -07001473 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 -07001474 {
1475 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1476 "Target type must be standard layout and its size must match the byte array size");
1477 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001478 return { reinterpret_cast<const U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001479 }
1480
1481 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 -07001482 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 -07001483 {
1484 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1485 "Target type must be standard layout and its size must match the byte array size");
1486 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001487 return { reinterpret_cast<U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001488 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001489
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001490 // section on linear space
1491 template<size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001492 constexpr array_view<ValueTypeOpt, Count> first() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001493 {
1494 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1495 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 -07001496 return { this->data(), Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001497 }
1498
Neil MacIntoshd5316802015-09-30 21:54:08 -07001499 constexpr array_view<ValueTypeOpt, dynamic_range> first(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001500 {
1501 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001502 return { this->data(), count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001503 }
1504
1505 template<size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001506 constexpr array_view<ValueTypeOpt, Count> last() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001507 {
1508 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1509 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001510 return { this->data() + this->size() - Count, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001511 }
1512
Neil MacIntoshd5316802015-09-30 21:54:08 -07001513 constexpr array_view<ValueTypeOpt, dynamic_range> last(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001514 {
1515 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001516 return { this->data() + this->size() - count, count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001517 }
1518
1519 template<size_t Offset, size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001520 constexpr array_view<ValueTypeOpt, Count> sub() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001521 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001522 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");
1523 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 -07001524 return { this->data() + Offset, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001525 }
1526
Neil MacIntoshd5316802015-09-30 21:54:08 -07001527 constexpr array_view<ValueTypeOpt, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001528 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001529 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1530 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001531 }
1532
1533 // size
Neil MacIntoshd5316802015-09-30 21:54:08 -07001534 constexpr size_type length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001535 {
1536 return this->size();
1537 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001538 constexpr size_type used_length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001539 {
1540 return length();
1541 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001542 constexpr size_type bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001543 {
1544 return sizeof(value_type) * this->size();
1545 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001546 constexpr size_type used_bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001547 {
1548 return bytes();
1549 }
1550
1551 // section
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001552 constexpr strided_array_view<ValueTypeOpt, rank> section(index_type origin, index_type extents) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001553 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001554 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001555 return{ &this->operator[](origin), size, strided_bounds<rank, size_type> {extents, details::make_stride(Base::bounds())} };
1556 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001557
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001558 constexpr reference operator[](const index_type& idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001559 {
1560 return Base::operator[](idx);
1561 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001562
Anna Gringauze1a864982015-09-14 18:55:06 -07001563 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001564 constexpr array_view<ValueTypeOpt, RestDimensions...> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001565 {
1566 auto ret = Base::operator[](idx);
1567 return{ ret.data(), ret.bounds() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001568 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001569
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001570 using Base::operator==;
1571 using Base::operator!=;
1572 using Base::operator<;
1573 using Base::operator<=;
1574 using Base::operator>;
1575 using Base::operator>=;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001576};
1577
1578template <typename T, size_t... Dimensions>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001579constexpr 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 -07001580{
1581 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), details::static_as_array_view_helper<static_bounds<size_t, Dimensions...>>(args..., details::Sep{})};
1582}
1583
1584template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001585constexpr 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 -07001586{
1587 return {arr, len};
1588}
1589
1590template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001591constexpr auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits<T, size_t, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001592{
1593 return {arr};
1594}
1595
1596template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001597constexpr array_view<const T, N> as_array_view(const std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001598{
1599 return {arr};
1600}
1601
1602template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001603constexpr array_view<const T, N> as_array_view(const std::array<T, N> &&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001604
1605template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001606constexpr array_view<T, N> as_array_view(std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001607{
1608 return {arr};
1609}
1610
1611template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001612constexpr array_view<T, dynamic_range> as_array_view(T *begin, T *end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001613{
1614 return {begin, end};
1615}
1616
1617template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001618constexpr 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 -07001619 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
1620{
1621 return {arr.data(), arr.size()};
1622}
1623
1624template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001625constexpr 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 -07001626 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
1627
Kern Handae1570262015-09-25 00:42:38 -07001628template <typename ValueTypeOpt, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001629class strided_array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>
1630{
1631 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 -07001632
Kern Handae1570262015-09-25 00:42:38 -07001633 template<typename OtherValueOpt, size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001634 friend class strided_array_view;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001635public:
1636 using Base::rank;
1637 using typename Base::bounds_type;
1638 using typename Base::size_type;
1639 using typename Base::pointer;
1640 using typename Base::value_type;
1641 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001642 using typename Base::iterator;
1643 using typename Base::const_iterator;
Anna Gringauze9dac1782015-09-14 19:08:03 -07001644 using typename Base::reference;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001645
1646 // from static array of size N
1647 template<size_type N>
1648 strided_array_view(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds))
1649 {
1650 fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries");
1651 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001652
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001653 // from raw data
1654 strided_array_view(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001655 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001656 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001657 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001658
1659 // from array view
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001660 template <size_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001661 strided_array_view(array_view<ValueTypeOpt, Dimensions...> av, bounds_type bounds) : Base(av.data(), std::move(bounds))
1662 {
1663 fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries");
1664 }
1665
1666 // convertible
1667 template <typename OtherValueTypeOpt,
1668 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>,
1669 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type>>,
1670 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1671 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001672 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 -07001673 {
1674 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001675
1676 // convert from bytes
Anna Gringauze1a864982015-09-14 18:55:06 -07001677 template <typename OtherValueType>
1678 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 -07001679 {
1680 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
1681 auto d = sizeof(OtherValueType) / sizeof(value_type);
1682
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001683 size_type size = this->bounds().total_size() / d;
1684 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 -07001685 }
1686
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001687 strided_array_view section(index_type origin, index_type extents) const
1688 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001689 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001690 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}};
1691 }
1692
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001693 constexpr reference operator[](const index_type& idx) const
Anna Gringauze9dac1782015-09-14 19:08:03 -07001694 {
1695 return Base::operator[](idx);
1696 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001697
1698 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001699 constexpr strided_array_view<value_type, rank-1> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001700 {
1701 auto ret = Base::operator[](idx);
1702 return{ ret.data(), ret.bounds().total_size(), ret.bounds() };
1703 }
1704
1705private:
1706 static index_type resize_extent(const index_type& extent, size_t d)
1707 {
1708 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");
1709
1710 index_type ret = extent;
1711 ret[rank - 1] /= d;
1712
1713 return ret;
1714 }
1715
1716 template <bool Enabled = (rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Kosov Eugene3402b922015-09-28 21:20:02 +03001717 static index_type resize_stride(const index_type& strides, size_t , void * = 0)
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001718 {
1719 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1720
1721 return strides;
1722 }
1723
1724 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
1725 static index_type resize_stride(const index_type& strides, size_t d)
1726 {
1727 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1728 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");
1729
Neil MacIntosh99746e22015-09-27 16:53:58 -07001730 for (size_t i = rank - 1; i > 0; --i)
1731 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 -07001732
1733 index_type ret = strides / d;
1734 ret[rank - 1] = 1;
1735
1736 return ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001737 }
1738};
1739
1740template <typename ArrayView>
1741class contiguous_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
1742{
1743 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
1744public:
1745 using typename Base::reference;
1746 using typename Base::pointer;
1747 using typename Base::difference_type;
1748private:
1749 template <typename ValueType, typename Bounds>
1750 friend class basic_array_view;
1751 pointer m_pdata;
1752 const ArrayView * m_validator;
1753 void validateThis() const
1754 {
Neil MacIntosh383dc502015-09-14 15:41:40 -07001755 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 -07001756 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001757 contiguous_array_view_iterator (const ArrayView *container, bool isbegin) :
1758 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001759public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001760 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001761 {
1762 validateThis();
1763 return *m_pdata;
1764 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001765 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001766 {
1767 validateThis();
1768 return m_pdata;
1769 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001770 contiguous_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001771 {
1772 ++m_pdata;
1773 return *this;
1774 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001775 contiguous_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001776 {
1777 auto ret = *this;
1778 ++(*this);
1779 return ret;
1780 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001781 contiguous_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001782 {
1783 --m_pdata;
1784 return *this;
1785 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001786 contiguous_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001787 {
1788 auto ret = *this;
1789 --(*this);
1790 return ret;
1791 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001792 contiguous_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001793 {
1794 contiguous_array_view_iterator ret{ *this };
1795 return ret += n;
1796 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001797 contiguous_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001798 {
1799 m_pdata += n;
1800 return *this;
1801 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001802 contiguous_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001803 {
1804 contiguous_array_view_iterator ret{ *this };
1805 return ret -= n;
1806 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001807 contiguous_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001808 {
1809 return *this += -n;
1810 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001811 difference_type operator-(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001812 {
1813 fail_fast_assert(m_validator == rhs.m_validator);
1814 return m_pdata - rhs.m_pdata;
1815 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001816 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001817 {
1818 return *(*this + n);
1819 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001820 bool operator==(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001821 {
1822 fail_fast_assert(m_validator == rhs.m_validator);
1823 return m_pdata == rhs.m_pdata;
1824 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001825 bool operator!=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001826 {
1827 return !(*this == rhs);
1828 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001829 bool operator<(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001830 {
1831 fail_fast_assert(m_validator == rhs.m_validator);
1832 return m_pdata < rhs.m_pdata;
1833 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001834 bool operator<=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001835 {
1836 return !(rhs < *this);
1837 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001838 bool operator>(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001839 {
1840 return rhs < *this;
1841 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001842 bool operator>=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001843 {
1844 return !(rhs > *this);
1845 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001846 void swap(contiguous_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001847 {
1848 std::swap(m_pdata, rhs.m_pdata);
1849 std::swap(m_validator, rhs.m_validator);
1850 }
1851};
1852
1853template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001854contiguous_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 -07001855{
1856 return rhs + n;
1857}
1858
1859template <typename ArrayView>
1860class general_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
1861{
1862 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
1863public:
1864 using typename Base::reference;
1865 using typename Base::pointer;
1866 using typename Base::difference_type;
1867 using typename Base::value_type;
1868private:
1869 template <typename ValueType, typename Bounds>
1870 friend class basic_array_view;
1871 const ArrayView * m_container;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001872 typename ArrayView::bounds_type::iterator m_itr;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001873 general_array_view_iterator(const ArrayView *container, bool isbegin) :
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001874 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
1875 {
1876 }
1877public:
Anna Gringauzea4654a42015-10-16 12:15:22 -07001878 reference operator*() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001879 {
1880 return (*m_container)[*m_itr];
1881 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001882 pointer operator->() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001883 {
1884 return &(*m_container)[*m_itr];
1885 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001886 general_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001887 {
1888 ++m_itr;
1889 return *this;
1890 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001891 general_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001892 {
1893 auto ret = *this;
1894 ++(*this);
1895 return ret;
1896 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001897 general_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001898 {
1899 --m_itr;
1900 return *this;
1901 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001902 general_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001903 {
1904 auto ret = *this;
1905 --(*this);
1906 return ret;
1907 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001908 general_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001909 {
1910 general_array_view_iterator ret{ *this };
1911 return ret += n;
1912 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001913 general_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001914 {
1915 m_itr += n;
1916 return *this;
1917 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001918 general_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001919 {
1920 general_array_view_iterator ret{ *this };
1921 return ret -= n;
1922 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001923 general_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001924 {
1925 return *this += -n;
1926 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001927 difference_type operator-(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001928 {
1929 fail_fast_assert(m_container == rhs.m_container);
1930 return m_itr - rhs.m_itr;
1931 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001932 value_type operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001933 {
1934 return (*m_container)[m_itr[n]];;
1935 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001936 bool operator==(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001937 {
1938 fail_fast_assert(m_container == rhs.m_container);
1939 return m_itr == rhs.m_itr;
1940 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001941 bool operator !=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001942 {
1943 return !(*this == rhs);
1944 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001945 bool operator<(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001946 {
1947 fail_fast_assert(m_container == rhs.m_container);
1948 return m_itr < rhs.m_itr;
1949 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001950 bool operator<=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001951 {
1952 return !(rhs < *this);
1953 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001954 bool operator>(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001955 {
1956 return rhs < *this;
1957 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001958 bool operator>=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001959 {
1960 return !(rhs > *this);
1961 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001962 void swap(general_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001963 {
1964 std::swap(m_itr, rhs.m_itr);
1965 std::swap(m_container, rhs.m_container);
1966 }
1967};
1968
1969template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001970general_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 -07001971{
1972 return rhs + n;
1973}
1974
Neil MacIntoshef626fd2015-09-29 16:41:37 -07001975} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001976
Neil MacIntoshd5316802015-09-30 21:54:08 -07001977#ifdef _MSC_VER
1978
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001979#undef constexpr
1980#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001981
Neil MacIntoshd5316802015-09-30 21:54:08 -07001982#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07001983#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07001984
1985#ifndef GSL_THROWS_FOR_TESTING
1986#pragma undef noexcept
1987#endif // GSL_THROWS_FOR_TESTING
1988
Neil MacIntosh9a297122015-09-14 15:11:07 -07001989#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07001990
Neil MacIntoshd5316802015-09-30 21:54:08 -07001991#endif // _MSC_VER
1992
1993#if defined(GSL_THROWS_FOR_TESTING)
1994#undef noexcept
1995#endif // GSL_THROWS_FOR_TESTING
1996
Treb Connell51da1362015-09-24 18:08:34 -07001997
1998#endif // GSL_ARRAY_VIEW_H