blob: 83d923138949d9950c0d5643b09204e0e0895de0 [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
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070074 {
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
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070086template <size_t Rank>
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(Rank > 0, "Rank must be greater than 0!");
90
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070091 template <size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -070092 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -070093
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070094public:
Anna Gringauzedb384972015-10-05 12:34:23 -070095 static const size_t rank = Rank;
Neil MacIntoshace9ab92015-10-23 19:49:17 -070096 using value_type = std::ptrdiff_t;
97 using size_type = value_type;
Anna Gringauzedb384972015-10-05 12:34:23 -070098 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 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700103
Anna Gringauzedb384972015-10-05 12:34:23 -0700104 constexpr index(const value_type(&values)[Rank]) noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -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
Anna Gringauzedb384972015-10-05 12:34:23 -0700115 constexpr index& operator=(const index& rhs) noexcept = default;
116
117 // Preconditions: component_idx < rank
118 constexpr reference operator[](size_t component_idx)
119 {
120 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
121 return elems[component_idx];
122 }
123
124 // Preconditions: component_idx < rank
125 constexpr const_reference operator[](size_t component_idx) const noexcept
126 {
127 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
128 return elems[component_idx];
129 }
130
131 constexpr bool operator==(const index& rhs) const noexcept
132 {
133 return std::equal(elems, elems + rank, rhs.elems);
134 }
135
136 constexpr bool operator!=(const index& rhs) const noexcept
137 {
138 return !(this == rhs);
139 }
140
141 constexpr index operator+() const noexcept
142 {
143 return *this;
144 }
145
146 constexpr index operator-() const noexcept
147 {
148 index ret = *this;
149 std::transform(ret, ret + rank, ret, std::negate<ValueType>{});
150 return ret;
151 }
152
153 constexpr index operator+(const index& rhs) const noexcept
154 {
155 index ret = *this;
156 ret += rhs;
157 return ret;
158 }
159
160 constexpr index operator-(const index& rhs) const noexcept
161 {
162 index ret = *this;
163 ret -= rhs;
164 return ret;
165 }
166
167 constexpr index& operator+=(const index& rhs) noexcept
168 {
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700169 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<value_type>{});
Anna Gringauzedb384972015-10-05 12:34:23 -0700170 return *this;
171 }
172
173 constexpr index& operator-=(const index& rhs) noexcept
174 {
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700175 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<value_type>{});
Anna Gringauzedb384972015-10-05 12:34:23 -0700176 return *this;
177 }
178
179 constexpr index operator*(value_type v) const noexcept
180 {
181 index ret = *this;
182 ret *= v;
183 return ret;
184 }
185
186 constexpr index operator/(value_type v) const noexcept
187 {
188 index ret = *this;
189 ret /= v;
190 return ret;
191 }
192
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700193 friend constexpr index operator*(value_type v, const index& rhs) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700194 {
195 return rhs * v;
196 }
197
198 constexpr index& operator*=(value_type v) noexcept
199 {
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700200 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies<value_type>{}(x, v); });
Anna Gringauzedb384972015-10-05 12:34:23 -0700201 return *this;
202 }
203
204 constexpr index& operator/=(value_type v) noexcept
205 {
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700206 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<value_type>{}(x, v); });
Anna Gringauzedb384972015-10-05 12:34:23 -0700207 return *this;
208 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700209
Anna Gringauzedb384972015-10-05 12:34:23 -0700210private:
211 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700212};
213
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700214#ifndef _MSC_VER
215
216struct static_bounds_dynamic_range_t
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700217{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700218 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
219 constexpr operator T() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700220 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700221 return static_cast<T>(-1);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700222 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700223
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700224 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
225 constexpr bool operator ==(T other) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700226 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700227 return static_cast<T>(-1) == other;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700228 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700229
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700230 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
231 constexpr bool operator !=(T other) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700232 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700233 return static_cast<T>(-1) != other;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700234 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700235
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700236};
237
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700238template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
239constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
240{
241 return right == left;
242}
243
244template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
245constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
246{
247 return right != left;
248}
249
250constexpr static_bounds_dynamic_range_t dynamic_range{};
251#else
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700252const std::ptrdiff_t dynamic_range = -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700253#endif
254
255struct generalized_mapping_tag {};
256struct contiguous_mapping_tag : generalized_mapping_tag {};
257
258namespace details
259{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700260
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700261 template <std::ptrdiff_t Left, std::ptrdiff_t Right>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700262 struct LessThan
263 {
264 static const bool value = Left < Right;
265 };
266
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700267 template <std::ptrdiff_t... Ranges>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700268 struct BoundsRanges {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700269 using size_type = std::ptrdiff_t;
270 static const size_type Depth = 0;
271 static const size_type DynamicNum = 0;
272 static const size_type CurrentRange = 1;
273 static const size_type TotalSize = 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700274
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700275 // TODO : following signature is for work around VS bug
276 template <typename OtherRange>
277 BoundsRanges(const OtherRange&, bool /* firstLevel */)
278 {}
279
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700280 BoundsRanges (const BoundsRanges&) = default;
281 BoundsRanges(const size_type* const) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700282 BoundsRanges() = default;
283
284
Kern Handae1570262015-09-25 00:42:38 -0700285 template <typename T, size_t Dim>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700286 void serialize(T&) const
287 {}
288
Kern Handae1570262015-09-25 00:42:38 -0700289 template <typename T, size_t Dim>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700290 size_type linearize(const T&) const
291 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700292 return 0;
293 }
294
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700295 template <typename T, size_t Dim>
296 bool contains(const T&) const
297 {
298 return 0;
299 }
300
301 size_type totalSize() const noexcept
302 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700303 return TotalSize;
304 }
305
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700306 bool operator==(const BoundsRanges&) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700307 {
308 return true;
309 }
310 };
311
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700312 template <std::ptrdiff_t... RestRanges>
313 struct BoundsRanges <dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>{
314 using Base = BoundsRanges <RestRanges... >;
315 using size_type = Base::size_type;
Kern Handae1570262015-09-25 00:42:38 -0700316 static const size_t Depth = Base::Depth + 1;
317 static const size_t DynamicNum = Base::DynamicNum + 1;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700318 static const size_type CurrentRange = dynamic_range;
319 static const size_type TotalSize = dynamic_range;
320 const size_type m_bound;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700321
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700322 BoundsRanges (const BoundsRanges&) = default;
323
324 BoundsRanges(const size_type* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700325 {
326 fail_fast_assert(0 <= *arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700327 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700328
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700329 BoundsRanges() : m_bound(0) {}
330
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700331 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
332 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other, bool /* firstLevel */ = true) :
333 Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false), m_bound(other.totalSize())
334 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700335
Kern Handae1570262015-09-25 00:42:38 -0700336 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700337 void serialize(T& arr) const
338 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700339 arr[Dim] = elementNum();
340 this->Base::template serialize<T, Dim + 1>(arr);
341 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700342
Kern Handae1570262015-09-25 00:42:38 -0700343 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700344 size_type linearize(const T& arr) const
345 {
346 const size_type index = this->Base::totalSize() * arr[Dim];
347 fail_fast_assert(index < m_bound);
348 return index + this->Base::template linearize<T, Dim + 1>(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700349 }
350
Kern Handae1570262015-09-25 00:42:38 -0700351 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700352 size_type contains(const T & arr) const
353 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700354 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
355 if (last == -1)
356 return -1;
357 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700358 return cur < m_bound ? cur + last : -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700359 }
360
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700361 size_type totalSize() const noexcept
362 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700363 return m_bound;
364 }
365
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700366 size_type elementNum() const noexcept
367 {
368 return totalSize() / this->Base::totalSize();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700369 }
370
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700371 size_type elementNum(size_t dim) const noexcept
372 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700373 if (dim > 0)
374 return this->Base::elementNum(dim - 1);
375 else
376 return elementNum();
377 }
378
Neil MacIntoshd5316802015-09-30 21:54:08 -0700379 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700380 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700381 return m_bound == rhs.m_bound && static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700382 }
383 };
384
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700385 template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
386 struct BoundsRanges <CurRange, RestRanges...> : BoundsRanges<RestRanges...>
387 {
388 using Base = BoundsRanges <RestRanges... >;
389 using size_type = Base::size_type;
Kern Handae1570262015-09-25 00:42:38 -0700390 static const size_t Depth = Base::Depth + 1;
391 static const size_t DynamicNum = Base::DynamicNum;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700392 static const size_type CurrentRange = CurRange;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700393 static const size_type TotalSize = Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700394
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700395 BoundsRanges (const BoundsRanges&) = default;
396 BoundsRanges(const size_type* const arr) : Base(arr) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700397 BoundsRanges() = default;
398
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700399 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
400 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>&other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700401 {
402 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
403 }
404
Kern Handae1570262015-09-25 00:42:38 -0700405 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700406 void serialize(T& arr) const
407 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700408 arr[Dim] = elementNum();
409 this->Base::template serialize<T, Dim + 1>(arr);
410 }
411
Kern Handae1570262015-09-25 00:42:38 -0700412 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700413 size_type linearize(const T& arr) const
414 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700415 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700416 return this->Base::totalSize() * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700417 }
418
Kern Handae1570262015-09-25 00:42:38 -0700419 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700420 size_type contains(const T& arr) const
421 {
422 if (arr[Dim] >= CurrentRange)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700423 return -1;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700424 const size_type last = this->Base::template contains<T, Dim + 1>(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700425 if (last == -1)
426 return -1;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700427 return this->Base::totalSize() * arr[Dim] + last;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700428 }
429
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700430 size_type totalSize() const noexcept
431 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700432 return CurrentRange * this->Base::totalSize();
433 }
434
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700435 size_type elementNum() const noexcept
436 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700437 return CurrentRange;
438 }
439
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700440 size_type elementNum(size_t dim) const noexcept
441 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700442 if (dim > 0)
443 return this->Base::elementNum(dim - 1);
444 else
445 return elementNum();
446 }
447
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700448 bool operator== (const BoundsRanges& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700449 {
450 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
451 }
452 };
453
454 template <typename SourceType, typename TargetType, size_t Rank>
455 struct BoundsRangeConvertible2;
456
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700457 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
458 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
459
460 template <size_t Rank, typename SourceType, typename TargetType>
461 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
462
463 template <typename SourceType, typename TargetType, size_t Rank>
464 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
465 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
466 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
467 {};
468
469 template <typename SourceType, typename TargetType>
470 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
471
472 template <typename SourceType, typename TargetType, size_t Rank = TargetType::Depth>
473 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
474 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
475 && (!LessThan<size_t(SourceType::CurrentRange), size_t(TargetType::CurrentRange)>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
476 {};
477 template <typename SourceType, typename TargetType>
478 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
479
480 template <typename TypeChain>
481 struct TypeListIndexer
482 {
483 const TypeChain & obj;
484 TypeListIndexer(const TypeChain & obj) :obj(obj){}
Kern Handae1570262015-09-25 00:42:38 -0700485 template<size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700486 const TypeChain & getObj(std::true_type)
487 {
488 return obj;
489 }
Kern Handae1570262015-09-25 00:42:38 -0700490 template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700491 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
492 {
493 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
494 }
Kern Handae1570262015-09-25 00:42:38 -0700495 template <size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700496 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
497 {
498 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
499 }
500 };
501
502 template <typename TypeChain>
503 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
504 {
505 return TypeListIndexer<TypeChain>(obj);
506 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700507
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700508 template <size_t Rank, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1>>>
509 constexpr Ret shift_left(const index<Rank>& other) noexcept
Anna Gringauzefdf86432015-10-14 10:46:22 -0700510 {
archshiftb3957172015-11-02 11:47:14 -0800511 Ret ret{};
Anna Gringauzefdf86432015-10-14 10:46:22 -0700512 for (size_t i = 0; i < Rank - 1; ++i)
513 {
514 ret[i] = other[i + 1];
515 }
516 return ret;
517 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700518}
519
520template <typename IndexType>
521class bounds_iterator;
522
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700523template <std::ptrdiff_t... Ranges>
524class static_bounds
525{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700526public:
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700527 static_bounds(const details::BoundsRanges<Ranges...>&) {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700528 }
529};
530
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700531template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
532class static_bounds<FirstRange, RestRanges...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700533{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700534 using MyRanges = details::BoundsRanges<FirstRange, RestRanges... >;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700535
536 MyRanges m_ranges;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700537 constexpr static_bounds(const MyRanges& range) : m_ranges(range)
538 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700539
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700540 template <std::ptrdiff_t... OtherRanges>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700541 friend class static_bounds;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700542
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700543public:
Kern Handae1570262015-09-25 00:42:38 -0700544 static const size_t rank = MyRanges::Depth;
545 static const size_t dynamic_rank = MyRanges::DynamicNum;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700546 static const std::ptrdiff_t static_size = MyRanges::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700547
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700548 using size_type = std::ptrdiff_t;
549 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700550 using const_index_type = std::add_const_t<index_type>;
551 using iterator = bounds_iterator<const_index_type>;
552 using const_iterator = bounds_iterator<const_index_type>;
553 using difference_type = std::ptrdiff_t;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700554 using sliced_type = static_bounds<RestRanges...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700555 using mapping_type = contiguous_mapping_tag;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700556
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700557 constexpr static_bounds(const static_bounds&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700558
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700559 template <std::ptrdiff_t... Ranges, typename Dummy = std::enable_if_t<
560 details::BoundsRangeConvertible<details::BoundsRanges<Ranges...>, details::BoundsRanges <FirstRange, RestRanges... >>::value>>
561 constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
562 {}
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700563
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700564 constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700565 {
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700566 fail_fast_assert((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700567 fail_fast_assert(m_ranges.totalSize() <= PTRDIFF_MAX, "Size of the range is larger than the max element of the size type");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700568 }
569
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700570 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700571
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700572 constexpr static_bounds& operator=(const static_bounds& otherBounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700573 {
574 new(&m_ranges) MyRanges (otherBounds.m_ranges);
575 return *this;
576 }
577
Neil MacIntoshd5316802015-09-30 21:54:08 -0700578 constexpr sliced_type slice() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700579 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700580 return sliced_type{static_cast<const details::BoundsRanges<RestRanges...> &>(m_ranges)};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700581 }
582
Neil MacIntoshd5316802015-09-30 21:54:08 -0700583 constexpr size_type stride() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700584 {
585 return rank > 1 ? slice().size() : 1;
586 }
587
Neil MacIntoshd5316802015-09-30 21:54:08 -0700588 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700589 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700590 return m_ranges.totalSize();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700591 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700592
Neil MacIntoshd5316802015-09-30 21:54:08 -0700593 constexpr size_type total_size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700594 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700595 return m_ranges.totalSize();
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700596 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700597
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700598 constexpr size_type linearize(const index_type & idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700599 {
600 return m_ranges.linearize(idx);
601 }
602
Neil MacIntoshd5316802015-09-30 21:54:08 -0700603 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700604 {
605 return m_ranges.contains(idx) != -1;
606 }
607
Neil MacIntoshd5316802015-09-30 21:54:08 -0700608 constexpr size_type operator[](size_t index) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700609 {
610 return m_ranges.elementNum(index);
611 }
612
Kern Handae1570262015-09-25 00:42:38 -0700613 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700614 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700615 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700616 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700617 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
618 }
619
Neil MacIntoshd5316802015-09-30 21:54:08 -0700620 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700621 {
Anna Gringauzefdf86432015-10-14 10:46:22 -0700622 size_type extents[rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700623 m_ranges.serialize(extents);
Anna Gringauzedb384972015-10-05 12:34:23 -0700624 return{ extents };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700625 }
626
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700627 template <std::ptrdiff_t... Ranges>
628 constexpr bool operator == (const static_bounds<Ranges...>& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700629 {
630 return this->size() == rhs.size();
631 }
632
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700633 template <std::ptrdiff_t... Ranges>
634 constexpr bool operator != (const static_bounds<Ranges...>& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700635 {
636 return !(*this == rhs);
637 }
638
Neil MacIntoshd5316802015-09-30 21:54:08 -0700639 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700640 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700641 return const_iterator(*this, index_type{});
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700642 }
643
Neil MacIntoshd5316802015-09-30 21:54:08 -0700644 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700645 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700646 return const_iterator(*this, this->index_bounds());
647 }
648};
649
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700650template <size_t Rank>
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700651class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700652{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700653 template <size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700654 friend class strided_bounds;
655
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700656public:
Anna Gringauzedb384972015-10-05 12:34:23 -0700657 static const size_t rank = Rank;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700658 using value_type = std::ptrdiff_t;
659 using reference = std::add_lvalue_reference_t<value_type>;
660 using const_reference = std::add_const_t<reference>;
661 using size_type = value_type;
662 using difference_type = value_type;
663 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700664 using const_index_type = std::add_const_t<index_type>;
665 using iterator = bounds_iterator<const_index_type>;
666 using const_iterator = bounds_iterator<const_index_type>;
667 static const value_type dynamic_rank = rank;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700668 static const value_type static_size = dynamic_range;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700669 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
670 using mapping_type = generalized_mapping_tag;
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700671
Anna Gringauzedb384972015-10-05 12:34:23 -0700672 constexpr strided_bounds(const strided_bounds &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700673
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700674 constexpr strided_bounds(const value_type(&values)[rank], index_type strides)
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700675 : m_extents(values), m_strides(std::move(strides))
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700676 {}
677
Anna Gringauzedb384972015-10-05 12:34:23 -0700678 constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept
679 : m_extents(extents), m_strides(strides)
680 {}
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700681
Neil MacIntoshd5316802015-09-30 21:54:08 -0700682 constexpr index_type strides() const noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700683 {
684 return m_strides;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700685 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700686
Neil MacIntoshd5316802015-09-30 21:54:08 -0700687 constexpr size_type total_size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700688 {
689 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700690 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700691 {
692 ret += (m_extents[i] - 1) * m_strides[i];
693 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700694 return ret + 1;
695 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700696
697 constexpr size_type size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700698 {
699 size_type ret = 1;
Kern Handae1570262015-09-25 00:42:38 -0700700 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700701 {
702 ret *= m_extents[i];
703 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700704 return ret;
705 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700706
707 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700708 {
Kern Handae1570262015-09-25 00:42:38 -0700709 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700710 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700711 if (idx[i] < 0 || idx[i] >= m_extents[i])
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700712 return false;
713 }
714 return true;
715 }
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700716
717 constexpr size_type linearize(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700718 {
719 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700720 for (size_t i = 0; i < rank; i++)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700721 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700722 fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700723 ret += idx[i] * m_strides[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700724 }
725 return ret;
726 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700727
728 constexpr size_type stride() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700729 {
730 return m_strides[0];
731 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700732
733 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700734 constexpr sliced_type slice() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700735 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700736 return{ details::shift_left(m_extents), details::shift_left(m_strides) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700737 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700738
739 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700740 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700741 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700742 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
Anna Gringauzedb384972015-10-05 12:34:23 -0700743 return m_extents[Dim];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700744 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700745
746 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700747 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700748 return m_extents;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700749 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700750 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700751 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700752 return const_iterator{ *this, index_type{} };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700753 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700754
Anna Gringauzea4654a42015-10-16 12:15:22 -0700755 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700756 {
757 return const_iterator{ *this, index_bounds() };
758 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700759
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700760private:
Anna Gringauzedb384972015-10-05 12:34:23 -0700761 index_type m_extents;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700762 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700763};
764
765template <typename T>
766struct is_bounds : std::integral_constant<bool, false> {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700767template <std::ptrdiff_t... Ranges>
768struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true> {};
769template <size_t Rank>
770struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700771
772template <typename IndexType>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700773class bounds_iterator: public std::iterator<std::random_access_iterator_tag, IndexType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700774{
775private:
Anna Gringauzea4654a42015-10-16 12:15:22 -0700776 using Base = std::iterator <std::random_access_iterator_tag, IndexType>;
777
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700778public:
Kern Handae1570262015-09-25 00:42:38 -0700779 static const size_t rank = IndexType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700780 using typename Base::reference;
781 using typename Base::pointer;
782 using typename Base::difference_type;
783 using typename Base::value_type;
784 using index_type = value_type;
Anna Gringauzedb384972015-10-05 12:34:23 -0700785 using index_size_type = typename IndexType::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700786 template <typename Bounds>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700787 explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
788 : boundary(bnd.index_bounds()), curr(std::move(curr))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700789 {
790 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
791 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700792
793 constexpr reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700794 {
795 return curr;
796 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700797
798 constexpr pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700799 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700800 return &curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700801 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700802
803 constexpr bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700804 {
Kern Handae1570262015-09-25 00:42:38 -0700805 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700806 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700807 if (curr[i] < boundary[i] - 1)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700808 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700809 curr[i]++;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700810 return *this;
811 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700812 curr[i] = 0;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700813 }
814 // If we're here we've wrapped over - set to past-the-end.
Anna Gringauzea4654a42015-10-16 12:15:22 -0700815 curr = boundary;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700816 return *this;
817 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700818
819 constexpr bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700820 {
821 auto ret = *this;
822 ++(*this);
823 return ret;
824 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700825
826 constexpr bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700827 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700828 if (!less(curr, boundary))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700829 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700830 // if at the past-the-end, set to last element
831 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700832 {
833 curr[i] = boundary[i] - 1;
834 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700835 return *this;
836 }
837 for (size_t i = rank; i-- > 0;)
838 {
839 if (curr[i] >= 1)
840 {
841 curr[i]--;
842 return *this;
843 }
844 curr[i] = boundary[i] - 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700845 }
846 // If we're here the preconditions were violated
847 // "pre: there exists s such that r == ++s"
848 fail_fast_assert(false);
849 return *this;
850 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700851
852 constexpr bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700853 {
854 auto ret = *this;
855 --(*this);
856 return ret;
857 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700858
859 constexpr bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700860 {
861 bounds_iterator ret{ *this };
862 return ret += n;
863 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700864
865 constexpr bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700866 {
867 auto linear_idx = linearize(curr) + n;
archshiftb3957172015-11-02 11:47:14 -0800868 std::remove_const_t<value_type> stride = 0;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700869 stride[rank - 1] = 1;
Kern Handae1570262015-09-25 00:42:38 -0700870 for (size_t i = rank - 1; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700871 {
872 stride[i] = stride[i + 1] * boundary[i + 1];
873 }
Kern Handae1570262015-09-25 00:42:38 -0700874 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700875 {
876 curr[i] = linear_idx / stride[i];
877 linear_idx = linear_idx % stride[i];
878 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700879 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 -0700880 return *this;
881 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700882
883 constexpr bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700884 {
885 bounds_iterator ret{ *this };
886 return ret -= n;
887 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700888
889 constexpr bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700890 {
891 return *this += -n;
892 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700893
894 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700895 {
896 return linearize(curr) - linearize(rhs.curr);
897 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700898
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700899 constexpr value_type operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700900 {
901 return *(*this + n);
902 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700903
904 constexpr bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700905 {
906 return curr == rhs.curr;
907 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700908
909 constexpr bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700910 {
911 return !(*this == rhs);
912 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700913
914 constexpr bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700915 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700916 return less(curr, rhs.curr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700917 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700918
919 constexpr bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700920 {
921 return !(rhs < *this);
922 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700923
924 constexpr bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700925 {
926 return rhs < *this;
927 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700928
929 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700930 {
931 return !(rhs > *this);
932 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700933
Neil MacIntoshd5316802015-09-30 21:54:08 -0700934 void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700935 {
936 std::swap(boundary, rhs.boundary);
937 std::swap(curr, rhs.curr);
938 }
939private:
Anna Gringauzea4654a42015-10-16 12:15:22 -0700940 constexpr bool less(index_type& one, index_type& other) const noexcept
941 {
942 for (size_t i = 0; i < rank; ++i)
943 {
944 if (one[i] < other[i])
945 return true;
946 }
947 return false;
948 }
949
950 constexpr index_size_type linearize(const value_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700951 {
952 // TODO: Smarter impl.
953 // Check if past-the-end
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700954 index_size_type multiplier = 1;
955 index_size_type res = 0;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700956 if (!less(idx, boundary))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700957 {
958 res = 1;
Kern Handae1570262015-09-25 00:42:38 -0700959 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700960 {
961 res += (idx[i] - 1) * multiplier;
962 multiplier *= boundary[i];
963 }
964 }
965 else
966 {
Kern Handae1570262015-09-25 00:42:38 -0700967 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700968 {
969 res += idx[i] * multiplier;
970 multiplier *= boundary[i];
971 }
972 }
973 return res;
974 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700975
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700976 value_type boundary;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700977 std::remove_const_t<value_type> curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700978};
979
980template <typename IndexType>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700981bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700982{
983 return rhs + n;
984}
985
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700986//
987// begin definitions of basic_array_view
988//
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700989namespace details
990{
991 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700992 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 -0700993 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700994 return bnd.strides();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700995 }
996
Neil MacIntosh99746e22015-09-27 16:53:58 -0700997 // Make a stride vector from bounds, assuming contiguous memory.
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700998 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700999 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 -07001000 {
1001 auto extents = bnd.index_bounds();
Anna Gringauzefdf86432015-10-14 10:46:22 -07001002 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001003
1004 stride[Bounds::rank - 1] = 1;
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001005 for (size_t i = 1; i < Bounds::rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -07001006 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001007 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
Anna Gringauzedb384972015-10-05 12:34:23 -07001008 }
1009 return{ stride };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001010 }
1011
1012 template <typename BoundsSrc, typename BoundsDest>
1013 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1014 {
1015 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1016 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1017 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");
1018 fail_fast_assert(src.size() == dest.size());
1019 }
1020
1021
1022} // namespace details
1023
1024template <typename ArrayView>
1025class contiguous_array_view_iterator;
1026template <typename ArrayView>
1027class general_array_view_iterator;
1028enum class byte : std::uint8_t {};
1029
1030template <typename ValueType, typename BoundsType>
1031class basic_array_view
1032{
1033public:
Kern Handae1570262015-09-25 00:42:38 -07001034 static const size_t rank = BoundsType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001035 using bounds_type = BoundsType;
1036 using size_type = typename bounds_type::size_type;
1037 using index_type = typename bounds_type::index_type;
1038 using value_type = ValueType;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001039 using const_value_type = std::add_const_t<value_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001040 using pointer = ValueType*;
1041 using reference = ValueType&;
1042 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 -07001043 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 -07001044 using reverse_iterator = std::reverse_iterator<iterator>;
1045 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1046 using sliced_type = std::conditional_t<rank == 1, value_type, basic_array_view<value_type, typename BoundsType::sliced_type>>;
1047
1048private:
1049 pointer m_pdata;
1050 bounds_type m_bounds;
1051
1052public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001053 constexpr bounds_type bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001054 {
1055 return m_bounds;
1056 }
Kern Handae1570262015-09-25 00:42:38 -07001057 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001058 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001059 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001060 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001061 return m_bounds.template extent<Dim>();
1062 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001063 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001064 {
1065 return m_bounds.size();
1066 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001067 constexpr reference operator[](const index_type& idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001068 {
1069 return m_pdata[m_bounds.linearize(idx)];
1070 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001071 constexpr pointer data() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001072 {
1073 return m_pdata;
1074 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001075 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001076 constexpr Ret operator[](size_type idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001077 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001078 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001079 const size_type ridx = idx * m_bounds.stride();
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001080
1081 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001082 return Ret {m_pdata + ridx, m_bounds.slice()};
1083 }
1084
Neil MacIntoshd5316802015-09-30 21:54:08 -07001085 constexpr operator bool () const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001086 {
1087 return m_pdata != nullptr;
1088 }
1089
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001090 constexpr iterator begin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001091 {
1092 return iterator {this, true};
1093 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001094 constexpr iterator end() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001095 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001096 return iterator {this, false};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001097 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001098 constexpr const_iterator cbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001099 {
1100 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), true};
1101 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001102 constexpr const_iterator cend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001103 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001104 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), false};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001105 }
1106
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001107 constexpr reverse_iterator rbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001108 {
1109 return reverse_iterator {end()};
1110 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001111 constexpr reverse_iterator rend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001112 {
1113 return reverse_iterator {begin()};
1114 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001115 constexpr const_reverse_iterator crbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001116 {
1117 return const_reverse_iterator {cend()};
1118 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001119 constexpr const_reverse_iterator crend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001120 {
1121 return const_reverse_iterator {cbegin()};
1122 }
1123
1124 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 -07001125 constexpr bool operator== (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001126 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001127 return m_bounds.size() == other.m_bounds.size() &&
1128 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001129 }
1130
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001131 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 -07001132 constexpr bool operator!= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001133 {
1134 return !(*this == other);
1135 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001136
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001137 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 -07001138 constexpr bool operator< (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001139 {
1140 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1141 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001142
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001143 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 -07001144 constexpr bool operator<= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001145 {
1146 return !(other < *this);
1147 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001148
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001149 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 -07001150 constexpr bool operator> (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001151 {
1152 return (other < *this);
1153 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001154
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001155 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 -07001156 constexpr bool operator>= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001157 {
1158 return !(*this < other);
1159 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001160
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001161public:
1162 template <typename OtherValueType, typename OtherBounds,
1163 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value
1164 && std::is_convertible<OtherBounds, bounds_type>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001165 constexpr basic_array_view(const basic_array_view<OtherValueType, OtherBounds> & other ) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001166 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
1167 {
1168 }
1169protected:
1170
Neil MacIntoshd5316802015-09-30 21:54:08 -07001171 constexpr basic_array_view(pointer data, bounds_type bound) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001172 : m_pdata(data)
1173 , m_bounds(std::move(bound))
1174 {
1175 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1176 }
1177 template <typename T>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001178 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 -07001179 : m_pdata(reinterpret_cast<pointer>(data))
1180 , m_bounds(std::move(bound))
1181 {
1182 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1183 }
1184 template <typename DestBounds>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001185 constexpr basic_array_view<value_type, DestBounds> as_array_view(const DestBounds &bounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001186 {
1187 details::verifyBoundsReshape(m_bounds, bounds);
1188 return {m_pdata, bounds};
1189 }
1190private:
1191
1192 friend iterator;
1193 friend const_iterator;
1194 template <typename ValueType2, typename BoundsType2>
1195 friend class basic_array_view;
1196};
1197
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001198template <std::ptrdiff_t DimSize = dynamic_range>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001199struct dim
1200{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001201 static const std::ptrdiff_t value = DimSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001202};
1203template <>
1204struct dim<dynamic_range>
1205{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001206 static const std::ptrdiff_t value = dynamic_range;
1207 const std::ptrdiff_t dvalue;
1208 dim(std::ptrdiff_t size) : dvalue(size) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001209};
1210
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001211template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range, std::ptrdiff_t... RestDimensions>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001212class array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001213
1214template <typename ValueType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001215class strided_array_view;
1216
1217namespace details
1218{
1219 template <typename T, typename = std::true_type>
1220 struct ArrayViewTypeTraits
1221 {
1222 using value_type = T;
1223 using size_type = size_t;
1224 };
1225
1226 template <typename Traits>
1227 struct ArrayViewTypeTraits<Traits, typename std::is_reference<typename Traits::array_view_traits &>::type>
1228 {
1229 using value_type = typename Traits::array_view_traits::value_type;
1230 using size_type = typename Traits::array_view_traits::size_type;
1231 };
1232
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001233 template <typename T, size_t... Ranks>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001234 struct ArrayViewArrayTraits {
1235 using type = array_view<T, Ranks...>;
1236 using value_type = T;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001237 using bounds_type = static_bounds<Ranks...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001238 using pointer = T*;
1239 using reference = T&;
1240 };
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001241 template <typename T, size_t N, size_t... Ranks>
1242 struct ArrayViewArrayTraits<T[N], Ranks...> : ArrayViewArrayTraits<T, Ranks..., N> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001243
1244 template <typename BoundsType>
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001245 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001246 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001247 fail_fast_assert(totalSize <= PTRDIFF_MAX);
1248 return BoundsType{totalSize};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001249 }
1250 template <typename BoundsType>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001251 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001252 {
1253 fail_fast_assert(BoundsType::static_size == totalSize);
1254 return {};
1255 }
1256 template <typename BoundsType>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001257 BoundsType newBoundsHelper(std::ptrdiff_t totalSize)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001258 {
1259 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1260 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1261 }
1262
1263 struct Sep{};
1264
1265 template <typename T, typename... Args>
1266 T static_as_array_view_helper(Sep, Args... args)
1267 {
1268 return T{static_cast<typename T::size_type>(args)...};
1269 }
1270 template <typename T, typename Arg, typename... Args>
1271 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)
1272 {
1273 return static_as_array_view_helper<T>(args...);
1274 }
1275 template <typename T, typename... Args>
1276 T static_as_array_view_helper(dim<dynamic_range> val, Args ... args)
1277 {
1278 return static_as_array_view_helper<T>(args..., val.dvalue);
1279 }
1280
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001281 template <typename ...Dimensions>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001282 struct static_as_array_view_static_bounds_helper
1283 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001284 using type = static_bounds<(Dimensions::value)...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001285 };
1286
1287 template <typename T>
1288 struct is_array_view_oracle : std::false_type
1289 {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001290
1291 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001292 struct is_array_view_oracle<array_view<ValueType, FirstDimension, RestDimensions...>> : std::true_type
1293 {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001294
1295 template <typename ValueType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001296 struct is_array_view_oracle<strided_array_view<ValueType, Rank>> : std::true_type
1297 {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001298
1299 template <typename T>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001300 struct is_array_view : is_array_view_oracle<std::remove_cv_t<T>>
1301 {};
1302
1303}
1304
1305
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001306template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
1307class array_view : public basic_array_view <ValueType, static_bounds <FirstDimension, RestDimensions...>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001308{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001309 template <typename ValueType2, std::ptrdiff_t FirstDimension2, std::ptrdiff_t... RestDimensions2>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001310 friend class array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001311
1312 using Base = basic_array_view<ValueType, static_bounds<FirstDimension, RestDimensions...>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001313
1314public:
1315 using typename Base::bounds_type;
1316 using typename Base::size_type;
1317 using typename Base::pointer;
1318 using typename Base::value_type;
1319 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001320 using typename Base::iterator;
1321 using typename Base::const_iterator;
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001322 using typename Base::reference;
Neil MacIntosh383dc502015-09-14 15:41:40 -07001323 using Base::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001324
1325public:
1326 // basic
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001327 constexpr array_view(pointer ptr, size_type size) : Base(ptr, bounds_type{ size })
1328 {}
1329
1330 constexpr array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds))
1331 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001332
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001333 constexpr array_view(std::nullptr_t) : Base(nullptr, bounds_type{})
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001334 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001335
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001336 constexpr array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001337 {
1338 fail_fast_assert(size == 0);
1339 }
1340
1341 // default
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001342 template <size_t DynamicRank = bounds_type::dynamic_rank, typename = std::enable_if_t<DynamicRank != 0>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001343 constexpr array_view() : Base(nullptr, bounds_type())
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001344 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001345
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001346 // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001347 template <typename T, typename Helper = details::ArrayViewArrayTraits<T, dynamic_range>
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001348 /*typename Dummy = std::enable_if_t<std::is_convertible<Helper::value_type (*)[], typename Base::value_type (*)[]>::value>*/>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001349 constexpr array_view(T* const& data, size_type size) : Base(data, typename Helper::bounds_type{size})
1350 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001351
1352 // from n-dimensions static array
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001353 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, N>,
1354 typename = std::enable_if_t<std::is_convertible<Helper::value_type(*)[], typename Base::value_type(*)[]>::value>>
1355 constexpr array_view (T (&arr)[N]) : Base(arr, Helper::bounds_type())
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001356 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001357
1358 // from n-dimensions static array with size
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001359 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, N>,
Neil MacIntosha4fa2b32015-10-28 16:53:53 -07001360 typename = std::enable_if_t<std::is_convertible<Helper::value_type(*)[], typename Base::value_type(*)[]>::value>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001361 >
Neil MacIntosha4fa2b32015-10-28 16:53:53 -07001362 constexpr array_view(T(&arr)[N], size_type size) : Base(arr, Helper::bounds_type{size})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001363 {
1364 fail_fast_assert(size <= N);
1365 }
1366
1367 // from std array
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001368 template <size_t N,
1369 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, typename Base::bounds_type>::value>
1370 >
1371 constexpr array_view (std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<N>())
1372 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001373
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001374 template <size_t N,
1375 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, typename Base::bounds_type>::value
1376 && std::is_const<value_type>::value>
1377 >
1378 constexpr array_view (const std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<N>())
1379 {}
1380
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001381 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1382 template <typename Ptr,
1383 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001384 && details::LessThan<Base::bounds_type::dynamic_rank, 2>::value>
1385 > // remove literal 0 case
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001386 constexpr array_view (pointer begin, Ptr end) : Base(begin, details::newBoundsHelper<typename Base::bounds_type>(static_cast<pointer>(end) - begin))
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001387 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001388
1389 // from containers. It must has .size() and .data() two function signatures
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001390 template <typename Cont, typename DataType = typename Cont::value_type,
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001391 typename Dummy = std::enable_if_t<!details::is_array_view<Cont>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001392 && std::is_convertible<DataType (*)[], typename Base::value_type (*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001393 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001394 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001395 constexpr array_view (Cont& cont) : Base(static_cast<pointer>(cont.data()), details::newBoundsHelper<typename Base::bounds_type>(cont.size()))
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001396 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001397
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001398 constexpr array_view(const array_view &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001399
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001400 // convertible
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001401 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1402 typename BaseType = basic_array_view<ValueType, static_bounds<FirstDimension, RestDimensions...>>,
1403 typename OtherBaseType = basic_array_view<OtherValueType, static_bounds<OtherDimensions...>>,
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001404 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1405 >
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001406 constexpr array_view(const array_view<OtherValueType, OtherDimensions...> &av)
1407 : Base(static_cast<const typename array_view<OtherValueType, OtherDimensions...>::Base&>(av))
1408 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001409
1410 // reshape
Neil MacIntosh14d50a62015-11-03 12:44:09 -08001411 // DimCount here is a workaround for a bug in MSVC 2015
1412 template <typename... Dimensions2, size_t DimCount = sizeof...(Dimensions2), typename = std::enable_if_t<(DimCount > 0)>>
1413 constexpr array_view<ValueType, Dimensions2::value...> as_array_view(Dimensions2... dims)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001414 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001415 using BoundsType = typename array_view<ValueType, (Dimensions2::value)...>::bounds_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001416 auto tobounds = details::static_as_array_view_helper<BoundsType>(dims..., details::Sep{});
1417 details::verifyBoundsReshape(this->bounds(), tobounds);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001418 return {this->data(), tobounds};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001419 }
1420
1421 // to bytes array
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001422 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
1423 constexpr auto as_bytes() const noexcept -> array_view<const byte>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001424 {
1425 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001426 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001427 }
1428
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001429 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
1430 constexpr auto as_writeable_bytes() const noexcept -> array_view<byte>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001431 {
1432 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001433 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001434 }
1435
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001436 // from bytes array
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001437 template<typename U, bool IsByte = std::is_same<value_type, const byte>::value, typename = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Neil MacIntosha4fa2b32015-10-28 16:53:53 -07001438 constexpr auto as_array_view() const noexcept -> array_view<const U, (Base::bounds_type::static_size != dynamic_range ? static_cast<size_t>(Base::bounds_type::static_size) / sizeof(U) : dynamic_range)>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001439 {
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001440 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % static_cast<size_type>(sizeof(U)) == 0),
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001441 "Target type must be standard layout and its size must match the byte array size");
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001442 fail_fast_assert((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX);
1443 return { reinterpret_cast<const U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001444 }
1445
Neil MacIntosha4fa2b32015-10-28 16:53:53 -07001446 template<typename U, bool IsByte = std::is_same<value_type, byte>::value, typename = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
1447 constexpr auto as_array_view() const noexcept -> array_view<U, (Base::bounds_type::static_size != dynamic_range ? static_cast<size_t>(Base::bounds_type::static_size) / sizeof(U) : dynamic_range)>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001448 {
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001449 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % static_cast<size_t>(sizeof(U)) == 0),
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001450 "Target type must be standard layout and its size must match the byte array size");
1451 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001452 return { reinterpret_cast<U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001453 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001454
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001455 // section on linear space
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001456 template<std::ptrdiff_t Count>
1457 constexpr array_view<ValueType, Count> first() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001458 {
1459 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1460 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 -07001461 return { this->data(), Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001462 }
1463
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001464 constexpr array_view<ValueType, dynamic_range> first(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001465 {
1466 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001467 return { this->data(), count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001468 }
1469
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001470 template<std::ptrdiff_t Count>
1471 constexpr array_view<ValueType, Count> last() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001472 {
1473 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1474 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001475 return { this->data() + this->size() - Count, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001476 }
1477
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001478 constexpr array_view<ValueType, dynamic_range> last(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001479 {
1480 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001481 return { this->data() + this->size() - count, count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001482 }
1483
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001484 template<std::ptrdiff_t Offset, std::ptrdiff_t Count>
1485 constexpr array_view<ValueType, Count> sub() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001486 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001487 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");
1488 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 -07001489 return { this->data() + Offset, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001490 }
1491
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001492 constexpr array_view<ValueType, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001493 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001494 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1495 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001496 }
1497
1498 // size
Neil MacIntoshd5316802015-09-30 21:54:08 -07001499 constexpr size_type length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001500 {
1501 return this->size();
1502 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001503
Neil MacIntoshd5316802015-09-30 21:54:08 -07001504 constexpr size_type used_length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001505 {
1506 return length();
1507 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001508
Neil MacIntoshd5316802015-09-30 21:54:08 -07001509 constexpr size_type bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001510 {
1511 return sizeof(value_type) * this->size();
1512 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001513
Neil MacIntoshd5316802015-09-30 21:54:08 -07001514 constexpr size_type used_bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001515 {
1516 return bytes();
1517 }
1518
1519 // section
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001520 constexpr strided_array_view<ValueType, rank> section(index_type origin, index_type extents) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001521 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001522 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001523 return{ &this->operator[](origin), size, strided_bounds<rank> {extents, details::make_stride(Base::bounds())} };
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001524 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001525
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001526 constexpr reference operator[](const index_type& idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001527 {
1528 return Base::operator[](idx);
1529 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001530
Anna Gringauze1a864982015-09-14 18:55:06 -07001531 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001532 constexpr array_view<ValueType, RestDimensions...> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001533 {
1534 auto ret = Base::operator[](idx);
1535 return{ ret.data(), ret.bounds() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001536 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001537
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001538 using Base::operator==;
1539 using Base::operator!=;
1540 using Base::operator<;
1541 using Base::operator<=;
1542 using Base::operator>;
1543 using Base::operator>=;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001544};
1545
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001546template <typename T, std::ptrdiff_t... Dimensions>
1547constexpr 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 -07001548{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001549 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), details::static_as_array_view_helper<static_bounds<Dimensions...>>(args..., details::Sep{})};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001550}
1551
1552template <typename T>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001553constexpr auto as_array_view (T* arr, std::ptrdiff_t len) -> typename details::ArrayViewArrayTraits<T, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001554{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001555 return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001556}
1557
1558template <typename T, size_t N>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001559constexpr auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits<T, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001560{
1561 return {arr};
1562}
1563
1564template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001565constexpr array_view<const T, N> as_array_view(const std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001566{
1567 return {arr};
1568}
1569
1570template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001571constexpr array_view<const T, N> as_array_view(const std::array<T, N> &&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001572
1573template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001574constexpr array_view<T, N> as_array_view(std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001575{
1576 return {arr};
1577}
1578
1579template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001580constexpr array_view<T, dynamic_range> as_array_view(T *begin, T *end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001581{
1582 return {begin, end};
1583}
1584
1585template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001586constexpr 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 -07001587 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
1588{
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001589 fail_fast_assert(arr.size() < PTRDIFF_MAX);
1590 return {arr.data(), static_cast<std::ptrdiff_t>(arr.size())};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001591}
1592
1593template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001594constexpr 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 -07001595 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
1596
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001597template <typename ValueType, size_t Rank>
1598class strided_array_view : public basic_array_view<ValueType, strided_bounds<Rank>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001599{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001600 using Base = basic_array_view<ValueType, strided_bounds<Rank>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001601
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001602 template<typename OtherValue, size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001603 friend class strided_array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001604
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001605public:
1606 using Base::rank;
1607 using typename Base::bounds_type;
1608 using typename Base::size_type;
1609 using typename Base::pointer;
1610 using typename Base::value_type;
1611 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001612 using typename Base::iterator;
1613 using typename Base::const_iterator;
Anna Gringauze9dac1782015-09-14 19:08:03 -07001614 using typename Base::reference;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001615
1616 // from static array of size N
1617 template<size_type N>
1618 strided_array_view(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds))
1619 {
1620 fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries");
1621 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001622
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001623 // from raw data
1624 strided_array_view(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001625 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001626 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001627 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001628
1629 // from array view
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001630 template <std::ptrdiff_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
1631 strided_array_view(array_view<ValueType, Dimensions...> av, bounds_type bounds) : Base(av.data(), std::move(bounds))
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001632 {
1633 fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries");
1634 }
1635
1636 // convertible
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001637 template <typename OtherValueType,
1638 typename BaseType = basic_array_view<ValueType, strided_bounds<Rank>>,
1639 typename OtherBaseType = basic_array_view<OtherValueType, strided_bounds<Rank>>,
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001640 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1641 >
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001642 constexpr strided_array_view(const strided_array_view<OtherValueType, Rank> &av) : Base(static_cast<const typename strided_array_view<OtherValueType, Rank>::Base &>(av)) // static_cast is required
1643 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001644
1645 // convert from bytes
Anna Gringauze1a864982015-09-14 18:55:06 -07001646 template <typename OtherValueType>
1647 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 -07001648 {
1649 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001650 auto d = static_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001651
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001652 size_type size = this->bounds().total_size() / d;
1653 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 -07001654 }
1655
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001656 strided_array_view section(index_type origin, index_type extents) const
1657 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001658 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001659 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}};
1660 }
1661
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001662 constexpr reference operator[](const index_type& idx) const
Anna Gringauze9dac1782015-09-14 19:08:03 -07001663 {
1664 return Base::operator[](idx);
1665 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001666
1667 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001668 constexpr strided_array_view<value_type, rank-1> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001669 {
1670 auto ret = Base::operator[](idx);
1671 return{ ret.data(), ret.bounds().total_size(), ret.bounds() };
1672 }
1673
1674private:
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001675 static index_type resize_extent(const index_type& extent, std::ptrdiff_t d)
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001676 {
1677 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");
1678
1679 index_type ret = extent;
1680 ret[rank - 1] /= d;
1681
1682 return ret;
1683 }
1684
1685 template <bool Enabled = (rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001686 static index_type resize_stride(const index_type& strides, std::ptrdiff_t , void * = 0)
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001687 {
1688 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1689
1690 return strides;
1691 }
1692
1693 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001694 static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001695 {
1696 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1697 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");
1698
Neil MacIntosh99746e22015-09-27 16:53:58 -07001699 for (size_t i = rank - 1; i > 0; --i)
1700 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 -07001701
1702 index_type ret = strides / d;
1703 ret[rank - 1] = 1;
1704
1705 return ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001706 }
1707};
1708
1709template <typename ArrayView>
1710class contiguous_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
1711{
1712 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
1713public:
1714 using typename Base::reference;
1715 using typename Base::pointer;
1716 using typename Base::difference_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001717
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001718private:
1719 template <typename ValueType, typename Bounds>
1720 friend class basic_array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001721
1722 pointer m_pdata;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001723 const ArrayView * m_validator;
1724 void validateThis() const
1725 {
Neil MacIntosh383dc502015-09-14 15:41:40 -07001726 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 -07001727 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001728 contiguous_array_view_iterator (const ArrayView *container, bool isbegin) :
1729 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001730public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001731 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001732 {
1733 validateThis();
1734 return *m_pdata;
1735 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001736 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001737 {
1738 validateThis();
1739 return m_pdata;
1740 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001741 contiguous_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001742 {
1743 ++m_pdata;
1744 return *this;
1745 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001746 contiguous_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001747 {
1748 auto ret = *this;
1749 ++(*this);
1750 return ret;
1751 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001752 contiguous_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001753 {
1754 --m_pdata;
1755 return *this;
1756 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001757 contiguous_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001758 {
1759 auto ret = *this;
1760 --(*this);
1761 return ret;
1762 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001763 contiguous_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001764 {
1765 contiguous_array_view_iterator ret{ *this };
1766 return ret += n;
1767 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001768 contiguous_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001769 {
1770 m_pdata += n;
1771 return *this;
1772 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001773 contiguous_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001774 {
1775 contiguous_array_view_iterator ret{ *this };
1776 return ret -= n;
1777 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001778 contiguous_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001779 {
1780 return *this += -n;
1781 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001782 difference_type operator-(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001783 {
1784 fail_fast_assert(m_validator == rhs.m_validator);
1785 return m_pdata - rhs.m_pdata;
1786 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001787 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001788 {
1789 return *(*this + n);
1790 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001791 bool operator==(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001792 {
1793 fail_fast_assert(m_validator == rhs.m_validator);
1794 return m_pdata == rhs.m_pdata;
1795 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001796 bool operator!=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001797 {
1798 return !(*this == rhs);
1799 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001800 bool operator<(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001801 {
1802 fail_fast_assert(m_validator == rhs.m_validator);
1803 return m_pdata < rhs.m_pdata;
1804 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001805 bool operator<=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001806 {
1807 return !(rhs < *this);
1808 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001809 bool operator>(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001810 {
1811 return rhs < *this;
1812 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001813 bool operator>=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001814 {
1815 return !(rhs > *this);
1816 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001817 void swap(contiguous_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001818 {
1819 std::swap(m_pdata, rhs.m_pdata);
1820 std::swap(m_validator, rhs.m_validator);
1821 }
1822};
1823
1824template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001825contiguous_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 -07001826{
1827 return rhs + n;
1828}
1829
1830template <typename ArrayView>
1831class general_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
1832{
1833 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
1834public:
1835 using typename Base::reference;
1836 using typename Base::pointer;
1837 using typename Base::difference_type;
1838 using typename Base::value_type;
1839private:
1840 template <typename ValueType, typename Bounds>
1841 friend class basic_array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001842
1843 const ArrayView * m_container;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001844 typename ArrayView::bounds_type::iterator m_itr;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001845 general_array_view_iterator(const ArrayView *container, bool isbegin) :
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001846 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
Neil MacIntosha4fa2b32015-10-28 16:53:53 -07001847 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001848public:
Anna Gringauzea4654a42015-10-16 12:15:22 -07001849 reference operator*() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001850 {
1851 return (*m_container)[*m_itr];
1852 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001853 pointer operator->() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001854 {
1855 return &(*m_container)[*m_itr];
1856 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001857 general_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001858 {
1859 ++m_itr;
1860 return *this;
1861 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001862 general_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001863 {
1864 auto ret = *this;
1865 ++(*this);
1866 return ret;
1867 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001868 general_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001869 {
1870 --m_itr;
1871 return *this;
1872 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001873 general_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001874 {
1875 auto ret = *this;
1876 --(*this);
1877 return ret;
1878 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001879 general_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001880 {
1881 general_array_view_iterator ret{ *this };
1882 return ret += n;
1883 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001884 general_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001885 {
1886 m_itr += n;
1887 return *this;
1888 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001889 general_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001890 {
1891 general_array_view_iterator ret{ *this };
1892 return ret -= n;
1893 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001894 general_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001895 {
1896 return *this += -n;
1897 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001898 difference_type operator-(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001899 {
1900 fail_fast_assert(m_container == rhs.m_container);
1901 return m_itr - rhs.m_itr;
1902 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001903 value_type operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001904 {
1905 return (*m_container)[m_itr[n]];;
1906 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001907 bool operator==(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001908 {
1909 fail_fast_assert(m_container == rhs.m_container);
1910 return m_itr == rhs.m_itr;
1911 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001912 bool operator !=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001913 {
1914 return !(*this == rhs);
1915 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001916 bool operator<(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001917 {
1918 fail_fast_assert(m_container == rhs.m_container);
1919 return m_itr < rhs.m_itr;
1920 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001921 bool operator<=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001922 {
1923 return !(rhs < *this);
1924 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001925 bool operator>(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001926 {
1927 return rhs < *this;
1928 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001929 bool operator>=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001930 {
1931 return !(rhs > *this);
1932 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001933 void swap(general_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001934 {
1935 std::swap(m_itr, rhs.m_itr);
1936 std::swap(m_container, rhs.m_container);
1937 }
1938};
1939
1940template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001941general_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 -07001942{
1943 return rhs + n;
1944}
1945
Neil MacIntoshef626fd2015-09-29 16:41:37 -07001946} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001947
Neil MacIntoshd5316802015-09-30 21:54:08 -07001948#ifdef _MSC_VER
1949
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001950#undef constexpr
1951#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001952
Neil MacIntoshd5316802015-09-30 21:54:08 -07001953#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07001954#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07001955
1956#ifndef GSL_THROWS_FOR_TESTING
1957#pragma undef noexcept
1958#endif // GSL_THROWS_FOR_TESTING
1959
Neil MacIntosh9a297122015-09-14 15:11:07 -07001960#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07001961
Neil MacIntoshd5316802015-09-30 21:54:08 -07001962#endif // _MSC_VER
1963
1964#if defined(GSL_THROWS_FOR_TESTING)
1965#undef noexcept
1966#endif // GSL_THROWS_FOR_TESTING
1967
Treb Connell51da1362015-09-24 18:08:34 -07001968
1969#endif // GSL_ARRAY_VIEW_H