blob: 1178e43495fe2de6906909606d3c06aa9ea0d89e [file] [log] [blame]
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001///////////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4//
5// This code is licensed under the MIT License (MIT).
6//
7// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13// THE SOFTWARE.
14//
15///////////////////////////////////////////////////////////////////////////////
16
17#pragma once
18
Treb Connell51da1362015-09-24 18:08:34 -070019#ifndef GSL_ARRAY_VIEW_H
20#define GSL_ARRAY_VIEW_H
21
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070022#include <new>
23#include <stdexcept>
24#include <cstddef>
25#include <cstdint>
26#include <limits>
27#include <type_traits>
28#include <utility>
29#include <array>
30#include <iterator>
Kern Handac4f9b872015-09-25 17:01:29 -070031#include <algorithm>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070032#include "fail_fast.h"
33
Neil MacIntoshd5316802015-09-30 21:54:08 -070034#ifdef _MSC_VER
35
36// No MSVC does constexpr fully yet
Gabriel Dos Reis6554e832015-09-28 05:10:44 -070037#pragma push_macro("constexpr")
38#define constexpr /* nothing */
Neil MacIntoshd5316802015-09-30 21:54:08 -070039
40
41// VS 2013 workarounds
42#if _MSC_VER <= 1800
43
44// noexcept is not understood
45#ifndef GSL_THROWS_FOR_TESTING
46#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070047#endif
48
Neil MacIntoshd5316802015-09-30 21:54:08 -070049// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070050#pragma warning(push)
51#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
Neil MacIntoshd5316802015-09-30 21:54:08 -070052
Neil MacIntosh9a297122015-09-14 15:11:07 -070053#endif // _MSC_VER <= 1800
54
Neil MacIntoshd5316802015-09-30 21:54:08 -070055#endif // _MSC_VER
56
57// In order to test the library, we need it to throw exceptions that we can catch
58#ifdef GSL_THROWS_FOR_TESTING
59#define noexcept /* nothing */
60#endif // GSL_THROWS_FOR_TESTING
61
62
Neil MacIntoshef626fd2015-09-29 16:41:37 -070063namespace gsl {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070064
65/*
66** begin definitions of index and bounds
67*/
68namespace details
69{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070070 template <typename ConcreteType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070071 class coordinate_facade
72 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070073 static_assert(Rank > 0, "Rank must be greater than 0!");
74
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070075 template <typename OtherConcreteType, size_t OtherRank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070076 friend class coordinate_facade;
77 public:
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070078 using reference = std::add_lvalue_reference_t<std::ptrdiff_t>;
79 using const_reference = std::add_const_t<reference>;
80 using value_type = std::ptrdiff_t;
Kern Handae1570262015-09-25 00:42:38 -070081 static const size_t rank = Rank;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070082
Neil MacIntoshd5316802015-09-30 21:54:08 -070083 constexpr coordinate_facade() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070084 {
85 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -070086 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070087
Neil MacIntoshd5316802015-09-30 21:54:08 -070088 constexpr coordinate_facade(const value_type(&values)[rank]) noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -070089 {
90 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
Kern Handae1570262015-09-25 00:42:38 -070091 for (size_t i = 0; i < rank; ++i)
Anna Gringauze17ed5c32015-08-30 23:30:15 -070092 elems[i] = values[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070093 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070094
Neil MacIntoshd5316802015-09-30 21:54:08 -070095 constexpr coordinate_facade(value_type e0) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070096 {
97 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
98 static_assert(rank == 1, "This constructor can only be used with rank == 1.");
99 elems[0] = e0;
100 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700101
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700102 // Preconditions: il.size() == rank
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700103 constexpr coordinate_facade(std::initializer_list<value_type> il)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700104 {
105 static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700106 fail_fast_assert(il.size() == rank, "The size of the initializer list must match the rank of the array");
Kern Handae1570262015-09-25 00:42:38 -0700107 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700108 {
109 elems[i] = begin(il)[i];
110 }
111 }
112
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700113 constexpr coordinate_facade(const coordinate_facade & other) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700114
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700115 template <typename OtherConcreteType>
116 constexpr coordinate_facade(const coordinate_facade<OtherConcreteType, Rank>& other)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700117 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700118 for (size_t i = 0; i < rank; ++i)
119 elems[i] = other.elems[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700120 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700121
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700122 protected:
123 coordinate_facade& operator=(const coordinate_facade& rhs) = default;
124 // Preconditions: component_idx < rank
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700125 constexpr reference operator[](size_t component_idx)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700126 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700127 fail_fast_assert(component_idx < rank, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700128 return elems[component_idx];
129 }
130 // Preconditions: component_idx < rank
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700131 constexpr const_reference operator[](size_t component_idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700132 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700133 fail_fast_assert(component_idx < rank, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700134 return elems[component_idx];
135 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700136 constexpr bool operator==(const ConcreteType& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700137 {
Kern Handac4f9b872015-09-25 17:01:29 -0700138 return std::equal(elems, elems + rank, rhs.elems);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700139 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700140 constexpr bool operator!=(const ConcreteType& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700141 {
142 return !(to_concrete() == rhs);
143 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700144 constexpr ConcreteType operator+() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700145 {
146 return to_concrete();
147 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700148 constexpr ConcreteType operator-() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700149 {
150 ConcreteType ret = to_concrete();
Kern Handaf1be21a2015-09-27 23:25:20 +0000151 std::transform(ret, ret + rank, ret, std::negate<ValueType>{});
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700152 return ret;
153 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700154 constexpr ConcreteType operator+(const ConcreteType& rhs) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700155 {
156 ConcreteType ret = to_concrete();
157 ret += rhs;
158 return ret;
159 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700160 constexpr ConcreteType operator-(const ConcreteType& rhs) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700161 {
162 ConcreteType ret = to_concrete();
163 ret -= rhs;
164 return ret;
165 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700166 constexpr ConcreteType& operator+=(const ConcreteType& rhs)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700167 {
Kern Handae1570262015-09-25 00:42:38 -0700168 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700169 elems[i] += rhs.elems[i];
170 return to_concrete();
171 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700172 constexpr ConcreteType& operator-=(const ConcreteType& rhs)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700173 {
Kern Handae1570262015-09-25 00:42:38 -0700174 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700175 elems[i] -= rhs.elems[i];
176 return to_concrete();
177 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700178 constexpr ConcreteType& operator++()
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700179 {
180 static_assert(rank == 1, "This operator can only be used with rank == 1.");
181 ++elems[0];
182 return to_concrete();
183 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700184 constexpr ConcreteType operator++(int)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700185 {
186 static_assert(rank == 1, "This operator can only be used with rank == 1.");
187 ConcreteType ret = to_concrete();
188 ++(*this);
189 return ret;
190 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700191 constexpr ConcreteType& operator--()
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700192 {
193 static_assert(rank == 1, "This operator can only be used with rank == 1.");
194 --elems[0];
195 return to_concrete();
196 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700197 constexpr ConcreteType operator--(int)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700198 {
199 static_assert(rank == 1, "This operator can only be used with rank == 1.");
200 ConcreteType ret = to_concrete();
201 --(*this);
202 return ret;
203 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700204 constexpr ConcreteType operator*(value_type v) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700205 {
206 ConcreteType ret = to_concrete();
207 ret *= v;
208 return ret;
209 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700210 constexpr ConcreteType operator/(value_type v) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700211 {
212 ConcreteType ret = to_concrete();
213 ret /= v;
214 return ret;
215 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700216 friend constexpr ConcreteType operator*(value_type v, const ConcreteType& rhs)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700217 {
218 return rhs * v;
219 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700220 constexpr ConcreteType& operator*=(value_type v)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700221 {
Kern Handae1570262015-09-25 00:42:38 -0700222 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700223 elems[i] *= v;
224 return to_concrete();
225 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700226 constexpr ConcreteType& operator/=(value_type v)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700227 {
Kern Handae1570262015-09-25 00:42:38 -0700228 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700229 elems[i] /= v;
230 return to_concrete();
231 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700232 value_type elems[rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700233 private:
Neil MacIntoshd5316802015-09-30 21:54:08 -0700234 constexpr const ConcreteType& to_concrete() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700235 {
236 return static_cast<const ConcreteType&>(*this);
237 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700238 constexpr ConcreteType& to_concrete() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700239 {
240 return static_cast<ConcreteType&>(*this);
241 }
242 };
243 template <typename T>
244 class arrow_proxy
245 {
246 public:
247 explicit arrow_proxy(T t)
248 : val(t)
249 {}
Neil MacIntoshd5316802015-09-30 21:54:08 -0700250 const T operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700251 {
252 return val;
253 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700254 const T* operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700255 {
256 return &val;
257 }
258 private:
259 T val;
260 };
261}
262
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700263template <size_t Rank>
264class index : private details::coordinate_facade<index<Rank>, Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700265{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700266 using Base = details::coordinate_facade<index<Rank>, Rank>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700267 friend Base;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700268 template <size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700269 friend class index;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700270public:
271 using Base::rank;
272 using reference = typename Base::reference;
273 using const_reference = typename Base::const_reference;
274 using size_type = typename Base::value_type;
275 using value_type = typename Base::value_type;
Neil MacIntoshd5316802015-09-30 21:54:08 -0700276 constexpr index() noexcept : Base(){}
277 constexpr index(const value_type (&values)[rank]) noexcept : Base(values) {}
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700278 constexpr index(std::initializer_list<value_type> il) : Base(il) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700279
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700280 constexpr index(const index &) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700281
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700282 constexpr static index shift_left(const index<rank+1>& other) noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700283 {
Anna Gringauze1a864982015-09-14 18:55:06 -0700284 value_type (&arr)[rank] = (value_type(&)[rank])(*(other.elems + 1));
285 return index(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700286 }
287
288 using Base::operator[];
289 using Base::operator==;
290 using Base::operator!=;
291 using Base::operator+;
292 using Base::operator-;
293 using Base::operator+=;
294 using Base::operator-=;
295 using Base::operator++;
296 using Base::operator--;
297 using Base::operator*;
298 using Base::operator/;
299 using Base::operator*=;
300 using Base::operator/=;
301};
302
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700303template<>
304class index<1>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700305{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700306public:
Kern Handae1570262015-09-25 00:42:38 -0700307 static const size_t rank = 1;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700308 using size_type = std::ptrdiff_t;
309 using value_type = std::ptrdiff_t;
310 using reference = std::add_lvalue_reference_t<std::ptrdiff_t>;
311 using const_reference = const std::ptrdiff_t&;//std::add_const_t<std::add_lvalue_reference_t<std::ptrdiff_t>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700312
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700313 constexpr index() noexcept : value(0)
314 {}
315
Neil MacIntoshd5316802015-09-30 21:54:08 -0700316 constexpr index(value_type e0) noexcept : value(e0)
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700317 {}
318
319 constexpr index(const value_type(&values)[1]) noexcept : index(values[0])
320 {}
321
322 // Preconditions: il.size() == rank
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700323 constexpr index(std::initializer_list<value_type> il)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700324 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700325 fail_fast_assert(il.size() == rank, "Size of the initializer list must match the rank of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700326 value = begin(il)[0];
327 }
328
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700329 constexpr index(const index &) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700330
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700331 constexpr static index shift_left(const index<rank + 1>& other) noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700332 {
333 return other.elems[1];
334 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700335
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700336 // Preconditions: component_idx < rank
Neil MacIntoshd5316802015-09-30 21:54:08 -0700337 constexpr reference operator[](size_type component_idx) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700338 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700339 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700340 return value;
341 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700342
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700343 // Preconditions: component_idx < rank
Neil MacIntoshd5316802015-09-30 21:54:08 -0700344 constexpr const_reference operator[](size_type component_idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700345 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700346 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700347 return value;
348 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700349
Neil MacIntoshd5316802015-09-30 21:54:08 -0700350 constexpr bool operator==(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700351 {
352 return value == rhs.value;
353 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700354
Neil MacIntoshd5316802015-09-30 21:54:08 -0700355 constexpr bool operator!=(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700356 {
357 return !(*this == rhs);
358 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700359
360 constexpr index operator+() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700361 {
362 return *this;
363 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700364
365 constexpr index operator-() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700366 {
367 return index(-value);
368 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700369
370 constexpr index operator+(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700371 {
372 return index(value + rhs.value);
373 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700374
375 constexpr index operator-(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700376 {
377 return index(value - rhs.value);
378 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700379
380 constexpr index& operator+=(const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700381 {
382 value += rhs.value;
383 return *this;
384 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700385
386 constexpr index& operator-=(const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700387 {
388 value -= rhs.value;
389 return *this;
390 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700391
392 constexpr index& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700393 {
394 ++value;
395 return *this;
396 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700397
398 constexpr index operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700399 {
400 index ret = *this;
401 ++(*this);
402 return ret;
403 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700404
405 constexpr index& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700406 {
407 --value;
408 return *this;
409 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700410
411 constexpr index operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700412 {
413 index ret = *this;
414 --(*this);
415 return ret;
416 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700417
418 constexpr index operator*(value_type v) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700419 {
420 return index(value * v);
421 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700422
423 constexpr index operator/(value_type v) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700424 {
425 return index(value / v);
426 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700427
428 constexpr index& operator*=(value_type v) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700429 {
430 value *= v;
431 return *this;
432 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700433
434 constexpr index& operator/=(value_type v) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700435 {
436 value /= v;
437 return *this;
438 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700439
440 friend constexpr index operator*(value_type v, const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700441 {
442 return index(rhs * v);
443 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700444
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700445private:
446 value_type value;
447};
448
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700449const std::ptrdiff_t dynamic_range = -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700450
451struct generalized_mapping_tag {};
452struct contiguous_mapping_tag : generalized_mapping_tag {};
453
454namespace details
455{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700456
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700457 template <std::ptrdiff_t Left, std::ptrdiff_t Right>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700458 struct LessThan
459 {
460 static const bool value = Left < Right;
461 };
462
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700463 template <std::ptrdiff_t... Ranges>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700464 struct BoundsRanges {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700465 using size_type = std::ptrdiff_t;
466 static const size_type Depth = 0;
467 static const size_type DynamicNum = 0;
468 static const size_type CurrentRange = 1;
469 static const size_type TotalSize = 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700470
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700471 BoundsRanges (const BoundsRanges&) = default;
472 BoundsRanges(const size_type* const) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700473 BoundsRanges() = default;
474
475
Kern Handae1570262015-09-25 00:42:38 -0700476 template <typename T, size_t Dim>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700477 void serialize(T&) const
478 {}
479
Kern Handae1570262015-09-25 00:42:38 -0700480 template <typename T, size_t Dim>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700481 size_type linearize(const T&) const
482 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700483 return 0;
484 }
485
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700486 template <typename T, size_t Dim>
487 bool contains(const T&) const
488 {
489 return 0;
490 }
491
492 size_type totalSize() const noexcept
493 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700494 return TotalSize;
495 }
496
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700497 bool operator==(const BoundsRanges&) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700498 {
499 return true;
500 }
501 };
502
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700503 template <std::ptrdiff_t... RestRanges>
504 struct BoundsRanges <dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>{
505 using Base = BoundsRanges <RestRanges... >;
506 using size_type = Base::size_type;
Kern Handae1570262015-09-25 00:42:38 -0700507 static const size_t Depth = Base::Depth + 1;
508 static const size_t DynamicNum = Base::DynamicNum + 1;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700509 static const size_type CurrentRange = dynamic_range;
510 static const size_type TotalSize = dynamic_range;
511 const size_type m_bound;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700512
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700513 BoundsRanges (const BoundsRanges&) = default;
514
515 BoundsRanges(const size_type* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700516 {
517 fail_fast_assert(0 <= *arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700518 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700519
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700520 BoundsRanges() : m_bound(0) {}
521
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700522 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
523 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other, bool /* firstLevel */ = true) :
524 Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false), m_bound(other.totalSize())
525 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700526
Kern Handae1570262015-09-25 00:42:38 -0700527 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700528 void serialize(T& arr) const
529 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700530 arr[Dim] = elementNum();
531 this->Base::template serialize<T, Dim + 1>(arr);
532 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700533
Kern Handae1570262015-09-25 00:42:38 -0700534 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700535 size_type linearize(const T& arr) const
536 {
537 const size_type index = this->Base::totalSize() * arr[Dim];
538 fail_fast_assert(index < m_bound);
539 return index + this->Base::template linearize<T, Dim + 1>(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700540 }
541
Kern Handae1570262015-09-25 00:42:38 -0700542 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700543 size_type contains(const T & arr) const
544 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700545 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
546 if (last == -1)
547 return -1;
548 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700549 return cur < m_bound ? cur + last : -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700550 }
551
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700552 size_type totalSize() const noexcept
553 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700554 return m_bound;
555 }
556
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700557 size_type elementNum() const noexcept
558 {
559 return totalSize() / this->Base::totalSize();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700560 }
561
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700562 size_type elementNum(size_t dim) const noexcept
563 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700564 if (dim > 0)
565 return this->Base::elementNum(dim - 1);
566 else
567 return elementNum();
568 }
569
Neil MacIntoshd5316802015-09-30 21:54:08 -0700570 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700571 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700572 return m_bound == rhs.m_bound && static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700573 }
574 };
575
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700576 template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
577 struct BoundsRanges <CurRange, RestRanges...> : BoundsRanges<RestRanges...>
578 {
579 using Base = BoundsRanges <RestRanges... >;
580 using size_type = Base::size_type;
Kern Handae1570262015-09-25 00:42:38 -0700581 static const size_t Depth = Base::Depth + 1;
582 static const size_t DynamicNum = Base::DynamicNum;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700583 static const size_type CurrentRange = CurRange;
584 static const size_type TotalSize = CurrentRange;
585 static_assert (CurRange <= PTRDIFF_MAX, "CurRange must be smaller than std::ptrdiff_t limits");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700586
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700587 BoundsRanges (const BoundsRanges&) = default;
588 BoundsRanges(const size_type* const arr) : Base(arr) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700589 BoundsRanges() = default;
590
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700591 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
592 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>&other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700593 {
594 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
595 }
596
Kern Handae1570262015-09-25 00:42:38 -0700597 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700598 void serialize(T& arr) const
599 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700600 arr[Dim] = elementNum();
601 this->Base::template serialize<T, Dim + 1>(arr);
602 }
603
Kern Handae1570262015-09-25 00:42:38 -0700604 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700605 size_type linearize(const T& arr) const
606 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700607 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700608 return this->Base::totalSize() * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700609 }
610
Kern Handae1570262015-09-25 00:42:38 -0700611 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700612 size_type contains(const T& arr) const
613 {
614 if (arr[Dim] >= CurrentRange)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700615 return -1;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700616 const size_type last = this->Base::template contains<T, Dim + 1>(arr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700617 if (last == -1)
618 return -1;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700619 return this->Base::totalSize() * arr[Dim] + last;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700620 }
621
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700622 size_type totalSize() const noexcept
623 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700624 return CurrentRange * this->Base::totalSize();
625 }
626
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700627 size_type elementNum() const noexcept
628 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700629 return CurrentRange;
630 }
631
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700632 size_type elementNum(size_t dim) const noexcept
633 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700634 if (dim > 0)
635 return this->Base::elementNum(dim - 1);
636 else
637 return elementNum();
638 }
639
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700640 bool operator== (const BoundsRanges& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700641 {
642 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
643 }
644 };
645
646 template <typename SourceType, typename TargetType, size_t Rank>
647 struct BoundsRangeConvertible2;
648
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700649 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
650 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
651
652 template <size_t Rank, typename SourceType, typename TargetType>
653 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
654
655 template <typename SourceType, typename TargetType, size_t Rank>
656 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
657 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
658 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
659 {};
660
661 template <typename SourceType, typename TargetType>
662 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
663
664 template <typename SourceType, typename TargetType, size_t Rank = TargetType::Depth>
665 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
666 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
667 && (!LessThan<size_t(SourceType::CurrentRange), size_t(TargetType::CurrentRange)>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
668 {};
669 template <typename SourceType, typename TargetType>
670 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
671
672 template <typename TypeChain>
673 struct TypeListIndexer
674 {
675 const TypeChain & obj;
676 TypeListIndexer(const TypeChain & obj) :obj(obj){}
Kern Handae1570262015-09-25 00:42:38 -0700677 template<size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700678 const TypeChain & getObj(std::true_type)
679 {
680 return obj;
681 }
Kern Handae1570262015-09-25 00:42:38 -0700682 template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700683 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
684 {
685 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
686 }
Kern Handae1570262015-09-25 00:42:38 -0700687 template <size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700688 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
689 {
690 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
691 }
692 };
693
694 template <typename TypeChain>
695 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
696 {
697 return TypeListIndexer<TypeChain>(obj);
698 }
699}
700
701template <typename IndexType>
702class bounds_iterator;
703
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700704template <std::ptrdiff_t... Ranges>
705class static_bounds
706{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700707public:
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700708 static_bounds(const details::BoundsRanges<Ranges...>&) {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700709 }
710};
711
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700712template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
713class static_bounds<FirstRange, RestRanges...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700714{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700715 using MyRanges = details::BoundsRanges<FirstRange, RestRanges... >;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700716
717 MyRanges m_ranges;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700718 constexpr static_bounds(const MyRanges& range) : m_ranges(range)
719 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700720
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700721 template <std::ptrdiff_t... OtherRanges>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700722 friend class static_bounds;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700723
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700724public:
Kern Handae1570262015-09-25 00:42:38 -0700725 static const size_t rank = MyRanges::Depth;
726 static const size_t dynamic_rank = MyRanges::DynamicNum;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700727 static const std::ptrdiff_t static_size = MyRanges::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700728
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700729 using size_type = std::ptrdiff_t;
730 using index_type = index<rank>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700731 using iterator = bounds_iterator<index_type>;
732 using const_iterator = bounds_iterator<index_type>;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700733 using difference_type = std::ptrdiff_t;
734 using sliced_type = static_bounds<RestRanges...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700735 using mapping_type = contiguous_mapping_tag;
736public:
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700737 constexpr static_bounds(const static_bounds&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700738
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700739 template <std::ptrdiff_t... Ranges, typename Dummy = std::enable_if_t<
740 details::BoundsRangeConvertible<details::BoundsRanges<Ranges...>, details::BoundsRanges <FirstRange, RestRanges... >>::value>>
741 constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
742 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700743
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700744 constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700745 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700746 fail_fast_assert(MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700747 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 -0700748 }
749
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700750 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700751
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700752 constexpr static_bounds& operator=(const static_bounds& otherBounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700753 {
754 new(&m_ranges) MyRanges (otherBounds.m_ranges);
755 return *this;
756 }
757
Neil MacIntoshd5316802015-09-30 21:54:08 -0700758 constexpr sliced_type slice() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700759 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700760 return sliced_type{static_cast<const details::BoundsRanges<RestRanges...> &>(m_ranges)};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700761 }
762
Neil MacIntoshd5316802015-09-30 21:54:08 -0700763 constexpr size_type stride() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700764 {
765 return rank > 1 ? slice().size() : 1;
766 }
767
Neil MacIntoshd5316802015-09-30 21:54:08 -0700768 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700769 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700770 return m_ranges.totalSize();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700771 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700772
Neil MacIntoshd5316802015-09-30 21:54:08 -0700773 constexpr size_type total_size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700774 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700775 return m_ranges.totalSize();
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700776 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700777
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700778 constexpr size_type linearize(const index_type & idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700779 {
780 return m_ranges.linearize(idx);
781 }
782
Neil MacIntoshd5316802015-09-30 21:54:08 -0700783 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700784 {
785 return m_ranges.contains(idx) != -1;
786 }
787
Neil MacIntoshd5316802015-09-30 21:54:08 -0700788 constexpr size_type operator[](size_t index) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700789 {
790 return m_ranges.elementNum(index);
791 }
792
Kern Handae1570262015-09-25 00:42:38 -0700793 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700794 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700795 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700796 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700797 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
798 }
799
Neil MacIntoshd5316802015-09-30 21:54:08 -0700800 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700801 {
802 index_type extents;
803 m_ranges.serialize(extents);
804 return extents;
805 }
806
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700807 template <std::ptrdiff_t... Ranges>
808 constexpr bool operator == (const static_bounds<Ranges...>& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700809 {
810 return this->size() == rhs.size();
811 }
812
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700813 template <std::ptrdiff_t... Ranges>
814 constexpr bool operator != (const static_bounds<Ranges...>& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700815 {
816 return !(*this == rhs);
817 }
818
Neil MacIntoshd5316802015-09-30 21:54:08 -0700819 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700820 {
821 return const_iterator(*this);
822 }
823
Neil MacIntoshd5316802015-09-30 21:54:08 -0700824 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700825 {
826 index_type boundary;
827 m_ranges.serialize(boundary);
828 return const_iterator(*this, this->index_bounds());
829 }
830};
831
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700832template <size_t Rank>
833class strided_bounds : private details::coordinate_facade<strided_bounds<Rank>, Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700834{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700835 using Base = details::coordinate_facade<strided_bounds<Rank>, Rank>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700836 friend Base;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700837
838 template <size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700839 friend class strided_bounds;
840
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700841public:
842 using Base::rank;
843 using reference = typename Base::reference;
844 using const_reference = typename Base::const_reference;
845 using size_type = typename Base::value_type;
846 using difference_type = typename Base::value_type;
847 using value_type = typename Base::value_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700848 using index_type = index<rank>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700849 using iterator = bounds_iterator<index_type>;
850 using const_iterator = bounds_iterator<index_type>;
851 static const int dynamic_rank = rank;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700852 static const std::ptrdiff_t static_size = dynamic_range;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700853 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
854 using mapping_type = generalized_mapping_tag;
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700855 constexpr strided_bounds(const strided_bounds &) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700856
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700857 constexpr strided_bounds(const index_type& extents, const index_type& strides)
858 : m_strides(strides)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700859 {
Kern Handae1570262015-09-25 00:42:38 -0700860 for (size_t i = 0; i < rank; i++)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700861 Base::elems[i] = extents[i];
862 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700863
864 constexpr strided_bounds(const value_type(&values)[rank], index_type strides)
865 : Base(values), m_strides(std::move(strides))
866 {}
867
Neil MacIntoshd5316802015-09-30 21:54:08 -0700868 constexpr index_type strides() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700869 {
870 return m_strides;
871 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700872
Neil MacIntoshd5316802015-09-30 21:54:08 -0700873 constexpr size_type total_size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700874 {
875 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700876 for (size_t i = 0; i < rank; ++i)
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700877 ret += (Base::elems[i] - 1) * m_strides[i];
878 return ret + 1;
879 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700880
881 constexpr size_type size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700882 {
883 size_type ret = 1;
Kern Handae1570262015-09-25 00:42:38 -0700884 for (size_t i = 0; i < rank; ++i)
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700885 ret *= Base::elems[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700886 return ret;
887 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700888
889 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700890 {
Kern Handae1570262015-09-25 00:42:38 -0700891 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700892 {
893 if (idx[i] < 0 || idx[i] >= Base::elems[i])
894 return false;
895 }
896 return true;
897 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700898
899 constexpr size_type linearize(const index_type & idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700900 {
901 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700902 for (size_t i = 0; i < rank; i++)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700903 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700904 fail_fast_assert(idx[i] < Base::elems[i], "index is out of bounds of the array");
905 ret += idx[i] * m_strides[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700906 }
907 return ret;
908 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700909
910 constexpr size_type stride() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700911 {
912 return m_strides[0];
913 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700914
915 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700916 constexpr sliced_type slice() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700917 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700918 return{ (value_type(&)[rank - 1])Base::elems[1], sliced_type::index_type::shift_left(m_strides) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700919 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700920
921 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700922 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700923 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700924 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700925 return Base::elems[Dim];
926 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700927
928 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700929 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700930 return index_type(Base::elems);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700931 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700932
933 const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700934 {
935 return const_iterator{ *this };
936 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700937
938 const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700939 {
940 return const_iterator{ *this, index_bounds() };
941 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700942
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700943private:
944 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700945};
946
947template <typename T>
948struct is_bounds : std::integral_constant<bool, false> {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700949template <std::ptrdiff_t... Ranges>
950struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true> {};
951template <size_t Rank>
952struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700953
954template <typename IndexType>
955class bounds_iterator
956 : public std::iterator<std::random_access_iterator_tag,
957 IndexType,
958 ptrdiff_t,
959 const details::arrow_proxy<IndexType>,
960 const IndexType>
961{
962private:
963 using Base = std::iterator <std::random_access_iterator_tag, IndexType, ptrdiff_t, const details::arrow_proxy<IndexType>, const IndexType>;
964public:
Kern Handae1570262015-09-25 00:42:38 -0700965 static const size_t rank = IndexType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700966 using typename Base::reference;
967 using typename Base::pointer;
968 using typename Base::difference_type;
969 using typename Base::value_type;
970 using index_type = value_type;
971 using index_size_type = typename IndexType::size_type;
972 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700973 explicit bounds_iterator(const Bounds & bnd, value_type curr = value_type{}) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700974 : boundary(bnd.index_bounds())
975 , curr( std::move(curr) )
976 {
977 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
978 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700979 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700980 {
981 return curr;
982 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700983 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700984 {
985 return details::arrow_proxy<value_type>{ curr };
986 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700987 bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700988 {
Kern Handae1570262015-09-25 00:42:38 -0700989 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700990 {
991 if (++curr[i] < boundary[i])
992 {
993 return *this;
994 }
995 else
996 {
997 curr[i] = 0;
998 }
999 }
1000 // If we're here we've wrapped over - set to past-the-end.
Kern Handae1570262015-09-25 00:42:38 -07001001 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001002 {
1003 curr[i] = boundary[i];
1004 }
1005 return *this;
1006 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001007 bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001008 {
1009 auto ret = *this;
1010 ++(*this);
1011 return ret;
1012 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001013 bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001014 {
Neil MacIntoshfb913932015-09-27 16:25:43 -07001015 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001016 {
1017 if (curr[i]-- > 0)
1018 {
1019 return *this;
1020 }
1021 else
1022 {
1023 curr[i] = boundary[i] - 1;
1024 }
1025 }
1026 // If we're here the preconditions were violated
1027 // "pre: there exists s such that r == ++s"
1028 fail_fast_assert(false);
1029 return *this;
1030 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001031 bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001032 {
1033 auto ret = *this;
1034 --(*this);
1035 return ret;
1036 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001037 bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001038 {
1039 bounds_iterator ret{ *this };
1040 return ret += n;
1041 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001042 bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001043 {
1044 auto linear_idx = linearize(curr) + n;
1045 value_type stride;
1046 stride[rank - 1] = 1;
Kern Handae1570262015-09-25 00:42:38 -07001047 for (size_t i = rank - 1; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001048 {
1049 stride[i] = stride[i + 1] * boundary[i + 1];
1050 }
Kern Handae1570262015-09-25 00:42:38 -07001051 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001052 {
1053 curr[i] = linear_idx / stride[i];
1054 linear_idx = linear_idx % stride[i];
1055 }
1056 return *this;
1057 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001058 bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001059 {
1060 bounds_iterator ret{ *this };
1061 return ret -= n;
1062 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001063 bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001064 {
1065 return *this += -n;
1066 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001067 difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001068 {
1069 return linearize(curr) - linearize(rhs.curr);
1070 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001071 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001072 {
1073 return *(*this + n);
1074 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001075 bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001076 {
1077 return curr == rhs.curr;
1078 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001079 bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001080 {
1081 return !(*this == rhs);
1082 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001083 bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001084 {
Kern Handae1570262015-09-25 00:42:38 -07001085 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001086 {
1087 if (curr[i] < rhs.curr[i])
1088 return true;
1089 }
1090 return false;
1091 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001092 bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001093 {
1094 return !(rhs < *this);
1095 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001096 bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001097 {
1098 return rhs < *this;
1099 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001100 bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001101 {
1102 return !(rhs > *this);
1103 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001104 void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001105 {
1106 std::swap(boundary, rhs.boundary);
1107 std::swap(curr, rhs.curr);
1108 }
1109private:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001110 index_size_type linearize(const value_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001111 {
1112 // TODO: Smarter impl.
1113 // Check if past-the-end
1114 bool pte = true;
Kern Handae1570262015-09-25 00:42:38 -07001115 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001116 {
1117 if (idx[i] != boundary[i])
1118 {
1119 pte = false;
1120 break;
1121 }
1122 }
1123 index_size_type multiplier = 1;
1124 index_size_type res = 0;
1125 if (pte)
1126 {
1127 res = 1;
Kern Handae1570262015-09-25 00:42:38 -07001128 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001129 {
1130 res += (idx[i] - 1) * multiplier;
1131 multiplier *= boundary[i];
1132 }
1133 }
1134 else
1135 {
Kern Handae1570262015-09-25 00:42:38 -07001136 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001137 {
1138 res += idx[i] * multiplier;
1139 multiplier *= boundary[i];
1140 }
1141 }
1142 return res;
1143 }
1144 value_type boundary;
1145 value_type curr;
1146};
1147
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001148template <>
1149class bounds_iterator<index<1>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001150 : public std::iterator<std::random_access_iterator_tag,
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001151 index<1>,
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001152 ptrdiff_t,
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001153 const details::arrow_proxy<index<1>>,
1154 const index<1>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001155{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001156 using Base = std::iterator<std::random_access_iterator_tag, index<1>, std::ptrdiff_t, const details::arrow_proxy<index<1>>, const index<1>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001157
1158public:
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001159 using Base::reference;
1160 using Base::pointer;
1161 using Base::difference_type;
1162 using Base::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001163 using index_type = value_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001164 using index_size_type = index_type::size_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001165
1166 template <typename Bounds>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001167 explicit bounds_iterator(const Bounds&, value_type curr = value_type{}) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001168 : curr( std::move(curr) )
1169 {}
Neil MacIntoshd5316802015-09-30 21:54:08 -07001170 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001171 {
1172 return curr;
1173 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001174 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001175 {
1176 return details::arrow_proxy<value_type>{ curr };
1177 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001178 bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001179 {
1180 ++curr;
1181 return *this;
1182 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001183 bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001184 {
1185 auto ret = *this;
1186 ++(*this);
1187 return ret;
1188 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001189 bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001190 {
1191 curr--;
1192 return *this;
1193 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001194 bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001195 {
1196 auto ret = *this;
1197 --(*this);
1198 return ret;
1199 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001200 bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001201 {
1202 bounds_iterator ret{ *this };
1203 return ret += n;
1204 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001205 bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001206 {
1207 curr += n;
1208 return *this;
1209 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001210 bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001211 {
1212 bounds_iterator ret{ *this };
1213 return ret -= n;
1214 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001215 bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001216 {
1217 return *this += -n;
1218 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001219 difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001220 {
1221 return curr[0] - rhs.curr[0];
1222 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001223 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001224 {
1225 return curr + n;
1226 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001227 bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001228 {
1229 return curr == rhs.curr;
1230 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001231 bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001232 {
1233 return !(*this == rhs);
1234 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001235 bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001236 {
1237 return curr[0] < rhs.curr[0];
1238 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001239 bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001240 {
1241 return !(rhs < *this);
1242 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001243 bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001244 {
1245 return rhs < *this;
1246 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001247 bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001248 {
1249 return !(rhs > *this);
1250 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001251 void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001252 {
1253 std::swap(curr, rhs.curr);
1254 }
1255private:
1256 value_type curr;
1257};
1258
1259template <typename IndexType>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001260bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001261{
1262 return rhs + n;
1263}
1264
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001265//
1266// begin definitions of basic_array_view
1267//
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001268namespace details
1269{
1270 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001271 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 -07001272 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001273 return bnd.strides();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001274 }
1275
Neil MacIntosh99746e22015-09-27 16:53:58 -07001276 // Make a stride vector from bounds, assuming contiguous memory.
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001277 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001278 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 -07001279 {
1280 auto extents = bnd.index_bounds();
1281 typename Bounds::index_type stride;
1282 stride[Bounds::rank - 1] = 1;
Neil MacIntosh99746e22015-09-27 16:53:58 -07001283 for (size_t i = Bounds::rank - 1; Bounds::rank > 1 && i > 0; --i)
1284 stride[i-1] = stride[i] * extents[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001285 return stride;
1286 }
1287
1288 template <typename BoundsSrc, typename BoundsDest>
1289 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1290 {
1291 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1292 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1293 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");
1294 fail_fast_assert(src.size() == dest.size());
1295 }
1296
1297
1298} // namespace details
1299
1300template <typename ArrayView>
1301class contiguous_array_view_iterator;
1302template <typename ArrayView>
1303class general_array_view_iterator;
1304enum class byte : std::uint8_t {};
1305
1306template <typename ValueType, typename BoundsType>
1307class basic_array_view
1308{
1309public:
Kern Handae1570262015-09-25 00:42:38 -07001310 static const size_t rank = BoundsType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001311 using bounds_type = BoundsType;
1312 using size_type = typename bounds_type::size_type;
1313 using index_type = typename bounds_type::index_type;
1314 using value_type = ValueType;
1315 using pointer = ValueType*;
1316 using reference = ValueType&;
1317 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>>;
1318 using const_iterator = std::conditional_t<std::is_same<typename BoundsType::mapping_type, contiguous_mapping_tag>::value, contiguous_array_view_iterator<basic_array_view<const ValueType, BoundsType>>, general_array_view_iterator<basic_array_view<const ValueType, BoundsType>>>;
1319 using reverse_iterator = std::reverse_iterator<iterator>;
1320 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1321 using sliced_type = std::conditional_t<rank == 1, value_type, basic_array_view<value_type, typename BoundsType::sliced_type>>;
1322
1323private:
1324 pointer m_pdata;
1325 bounds_type m_bounds;
1326
1327public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001328 constexpr bounds_type bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001329 {
1330 return m_bounds;
1331 }
Kern Handae1570262015-09-25 00:42:38 -07001332 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001333 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001334 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001335 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001336 return m_bounds.template extent<Dim>();
1337 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001338 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001339 {
1340 return m_bounds.size();
1341 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001342 constexpr reference operator[](const index_type& idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001343 {
1344 return m_pdata[m_bounds.linearize(idx)];
1345 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001346 constexpr pointer data() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001347 {
1348 return m_pdata;
1349 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001350 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001351 constexpr Ret operator[](size_type idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001352 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001353 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001354 const size_type ridx = idx * m_bounds.stride();
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001355
1356 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001357 return Ret {m_pdata + ridx, m_bounds.slice()};
1358 }
1359
Neil MacIntoshd5316802015-09-30 21:54:08 -07001360 constexpr operator bool () const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001361 {
1362 return m_pdata != nullptr;
1363 }
1364
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001365 constexpr iterator begin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001366 {
1367 return iterator {this, true};
1368 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001369 constexpr iterator end() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001370 {
1371 return iterator {this};
1372 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001373 constexpr const_iterator cbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001374 {
1375 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), true};
1376 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001377 constexpr const_iterator cend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001378 {
1379 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this)};
1380 }
1381
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001382 constexpr reverse_iterator rbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001383 {
1384 return reverse_iterator {end()};
1385 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001386 constexpr reverse_iterator rend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001387 {
1388 return reverse_iterator {begin()};
1389 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001390 constexpr const_reverse_iterator crbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001391 {
1392 return const_reverse_iterator {cend()};
1393 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001394 constexpr const_reverse_iterator crend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001395 {
1396 return const_reverse_iterator {cbegin()};
1397 }
1398
1399 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 -07001400 constexpr bool operator== (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001401 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001402 return m_bounds.size() == other.m_bounds.size() &&
1403 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001404 }
1405
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001406 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 -07001407 constexpr bool operator!= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001408 {
1409 return !(*this == other);
1410 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001411
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001412 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 -07001413 constexpr bool operator< (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001414 {
1415 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1416 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001417
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001418 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 -07001419 constexpr bool operator<= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001420 {
1421 return !(other < *this);
1422 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001423
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001424 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 -07001425 constexpr bool operator> (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001426 {
1427 return (other < *this);
1428 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001429
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001430 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 -07001431 constexpr bool operator>= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001432 {
1433 return !(*this < other);
1434 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001435
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001436public:
1437 template <typename OtherValueType, typename OtherBounds,
1438 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value
1439 && std::is_convertible<OtherBounds, bounds_type>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001440 constexpr basic_array_view(const basic_array_view<OtherValueType, OtherBounds> & other ) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001441 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
1442 {
1443 }
1444protected:
1445
Neil MacIntoshd5316802015-09-30 21:54:08 -07001446 constexpr basic_array_view(pointer data, bounds_type bound) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001447 : m_pdata(data)
1448 , m_bounds(std::move(bound))
1449 {
1450 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1451 }
1452 template <typename T>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001453 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 -07001454 : m_pdata(reinterpret_cast<pointer>(data))
1455 , m_bounds(std::move(bound))
1456 {
1457 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1458 }
1459 template <typename DestBounds>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001460 constexpr basic_array_view<value_type, DestBounds> as_array_view(const DestBounds &bounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001461 {
1462 details::verifyBoundsReshape(m_bounds, bounds);
1463 return {m_pdata, bounds};
1464 }
1465private:
1466
1467 friend iterator;
1468 friend const_iterator;
1469 template <typename ValueType2, typename BoundsType2>
1470 friend class basic_array_view;
1471};
1472
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001473template <std::ptrdiff_t DimSize = dynamic_range>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001474struct dim
1475{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001476 static const std::ptrdiff_t value = DimSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001477};
1478template <>
1479struct dim<dynamic_range>
1480{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001481 static const std::ptrdiff_t value = dynamic_range;
1482 const std::ptrdiff_t dvalue;
1483 dim(std::ptrdiff_t size) : dvalue(size) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001484};
1485
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001486template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range, std::ptrdiff_t... RestDimensions>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001487class array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001488
1489template <typename ValueType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001490class strided_array_view;
1491
1492namespace details
1493{
1494 template <typename T, typename = std::true_type>
1495 struct ArrayViewTypeTraits
1496 {
1497 using value_type = T;
1498 using size_type = size_t;
1499 };
1500
1501 template <typename Traits>
1502 struct ArrayViewTypeTraits<Traits, typename std::is_reference<typename Traits::array_view_traits &>::type>
1503 {
1504 using value_type = typename Traits::array_view_traits::value_type;
1505 using size_type = typename Traits::array_view_traits::size_type;
1506 };
1507
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001508 template <typename T, size_t... Ranks>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001509 struct ArrayViewArrayTraits {
1510 using type = array_view<T, Ranks...>;
1511 using value_type = T;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001512 using bounds_type = static_bounds<Ranks...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001513 using pointer = T*;
1514 using reference = T&;
1515 };
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001516 template <typename T, size_t N, size_t... Ranks>
1517 struct ArrayViewArrayTraits<T[N], Ranks...> : ArrayViewArrayTraits<T, Ranks..., N> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001518
1519 template <typename BoundsType>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001520 BoundsType newBoundsHelperImpl(std::ptrdiff_t , std::true_type) // dynamic size
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001521 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001522 fail_fast_assert(totalSize <= PTRDIFF_MAX);
1523 return BoundsType{totalSize};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001524 }
1525 template <typename BoundsType>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001526 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001527 {
1528 fail_fast_assert(BoundsType::static_size == totalSize);
1529 return {};
1530 }
1531 template <typename BoundsType>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001532 BoundsType newBoundsHelper(std::ptrdiff_t totalSize)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001533 {
1534 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1535 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1536 }
1537
1538 struct Sep{};
1539
1540 template <typename T, typename... Args>
1541 T static_as_array_view_helper(Sep, Args... args)
1542 {
1543 return T{static_cast<typename T::size_type>(args)...};
1544 }
1545 template <typename T, typename Arg, typename... Args>
1546 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)
1547 {
1548 return static_as_array_view_helper<T>(args...);
1549 }
1550 template <typename T, typename... Args>
1551 T static_as_array_view_helper(dim<dynamic_range> val, Args ... args)
1552 {
1553 return static_as_array_view_helper<T>(args..., val.dvalue);
1554 }
1555
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001556 template <typename ...Dimensions>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001557 struct static_as_array_view_static_bounds_helper
1558 {
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001559 using type = static_bounds<(Dimensions::value)...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001560 };
1561
1562 template <typename T>
1563 struct is_array_view_oracle : std::false_type
1564 {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001565
1566 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001567 struct is_array_view_oracle<array_view<ValueType, FirstDimension, RestDimensions...>> : std::true_type
1568 {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001569
1570 template <typename ValueType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001571 struct is_array_view_oracle<strided_array_view<ValueType, Rank>> : std::true_type
1572 {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001573
1574 template <typename T>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001575 struct is_array_view : is_array_view_oracle<std::remove_cv_t<T>>
1576 {};
1577
1578}
1579
1580
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001581template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
1582class array_view : public basic_array_view <ValueType, static_bounds <FirstDimension, RestDimensions...>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001583{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001584 template <typename ValueType2, std::ptrdiff_t FirstDimension2, std::ptrdiff_t... RestDimensions2>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001585 friend class array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001586
1587 using Base = basic_array_view<ValueType, static_bounds<FirstDimension, RestDimensions...>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001588
1589public:
1590 using typename Base::bounds_type;
1591 using typename Base::size_type;
1592 using typename Base::pointer;
1593 using typename Base::value_type;
1594 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001595 using typename Base::iterator;
1596 using typename Base::const_iterator;
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001597 using typename Base::reference;
Neil MacIntosh383dc502015-09-14 15:41:40 -07001598 using Base::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001599
1600public:
1601 // basic
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001602 constexpr array_view(pointer ptr, size_type size) : Base(ptr, bounds_type{ size })
1603 {}
1604
1605 constexpr array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds))
1606 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001607
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001608 constexpr array_view(std::nullptr_t) : Base(nullptr, bounds_type{})
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001609 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001610
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001611 constexpr array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001612 {
1613 fail_fast_assert(size == 0);
1614 }
1615
1616 // default
1617 template <size_t DynamicRank = bounds_type::dynamic_rank, typename Dummy = std::enable_if_t<DynamicRank != 0>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001618 constexpr array_view() : Base(nullptr, bounds_type())
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001619 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001620
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001621 // 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 -07001622 template <typename T, typename Helper = details::ArrayViewArrayTraits<T, dynamic_range>
1623 typename Dummy = std::enable_if_t<std::is_convertible<Helper::value_type (*)[], typename Base::value_type (*)[]>::value>>
1624 constexpr array_view(T* const& data, size_type size) : Base(data, typename Helper::bounds_type{size})
1625 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001626
1627 // from n-dimensions static array
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001628 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, dynamic_range>
1629 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], typename Base::value_type(*)[]>::value>
1630 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001631 constexpr array_view (T (&arr)[N]) : Base(arr, typename Helper::bounds_type())
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001632 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001633
1634 // from n-dimensions static array with size
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001635 template <typename T, size_t N,
1636 typename Dummy = std::enable_if_t<std::is_convertible<T(*)[], typename Base::value_type(*)[]>::value>
1637 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001638 constexpr array_view(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{ size })
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001639 {
1640 fail_fast_assert(size <= N);
1641 }
1642
1643 // from std array
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001644 template <size_t N,
1645 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, typename Base::bounds_type>::value>
1646 >
1647 constexpr array_view (std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<N>())
1648 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001649
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001650 template <size_t N,
1651 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, typename Base::bounds_type>::value
1652 && std::is_const<value_type>::value>
1653 >
1654 constexpr array_view (const std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<N>())
1655 {}
1656
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001657 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1658 template <typename Ptr,
1659 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001660 && details::LessThan<Base::bounds_type::dynamic_rank, 2>::value>
1661 > // remove literal 0 case
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001662 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 -07001663 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001664
1665 // from containers. It must has .size() and .data() two function signatures
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001666 template <typename Cont, typename DataType = typename Cont::value_type,
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001667 typename Dummy = std::enable_if_t<!details::is_array_view<Cont>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001668 && std::is_convertible<DataType (*)[], typename Base::value_type (*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001669 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001670 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001671 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 -07001672 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001673
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001674 constexpr array_view(const array_view &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001675
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001676 // convertible
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001677 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1678 typename BaseType = basic_array_view<ValueType, static_bounds<FirstDimension, RestDimensions...>>,
1679 typename OtherBaseType = basic_array_view<OtherValueType, static_bounds<OtherDimensions...>>,
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001680 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1681 >
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001682 constexpr array_view(const array_view<OtherValueType, OtherDimensions...> &av)
1683 : Base(static_cast<const typename array_view<OtherValueType, OtherDimensions...>::Base&>(av))
1684 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001685
1686 // reshape
1687 template <typename... Dimensions2>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001688 constexpr array_view<ValueType, Dimensions2::value...> as_array_view(Dimensions2... dims)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001689 {
1690 static_assert(sizeof...(Dimensions2) > 0, "the target array_view must have at least one dimension.");
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001691 using BoundsType = typename array_view<ValueType, (Dimensions2::value)...>::bounds_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001692 auto tobounds = details::static_as_array_view_helper<BoundsType>(dims..., details::Sep{});
1693 details::verifyBoundsReshape(this->bounds(), tobounds);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001694 return {this->data(), tobounds};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001695 }
1696
1697 // to bytes array
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001698 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
1699 constexpr auto as_bytes() const noexcept -> array_view<const byte>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001700 {
1701 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001702 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001703 }
1704
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001705 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
1706 constexpr auto as_writeable_bytes() const noexcept -> array_view<byte>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001707 {
1708 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001709 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001710 }
1711
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001712 // from bytes array
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001713 template<typename U, bool IsByte = std::is_same<value_type, const byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001714 constexpr auto as_array_view() const noexcept -> array_view<const U, (Base::bounds_type::dynamic_rank == 0 ? Base::bounds_type::static_size / sizeof(U) : dynamic_range)>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001715 {
1716 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1717 "Target type must be standard layout and its size must match the byte array size");
1718 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001719 return { reinterpret_cast<const U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001720 }
1721
1722 template<typename U, bool IsByte = std::is_same<value_type, byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001723 constexpr auto as_array_view() const noexcept -> array_view<U, (Base::bounds_type::dynamic_rank == 0 ? Base::bounds_type::static_size / sizeof(U) : dynamic_range)>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001724 {
1725 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1726 "Target type must be standard layout and its size must match the byte array size");
1727 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001728 return { reinterpret_cast<U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001729 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001730
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001731 // section on linear space
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001732 template<std::ptrdiff_t Count>
1733 constexpr array_view<ValueType, Count> first() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001734 {
1735 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1736 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 -07001737 return { this->data(), Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001738 }
1739
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001740 constexpr array_view<ValueType, dynamic_range> first(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001741 {
1742 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001743 return { this->data(), count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001744 }
1745
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001746 template<std::ptrdiff_t Count>
1747 constexpr array_view<ValueType, Count> last() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001748 {
1749 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1750 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001751 return { this->data() + this->size() - Count, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001752 }
1753
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001754 constexpr array_view<ValueType, dynamic_range> last(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001755 {
1756 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001757 return { this->data() + this->size() - count, count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001758 }
1759
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001760 template<std::ptrdiff_t Offset, std::ptrdiff_t Count>
1761 constexpr array_view<ValueType, Count> sub() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001762 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001763 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");
1764 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 -07001765 return { this->data() + Offset, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001766 }
1767
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001768 constexpr array_view<ValueType, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001769 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001770 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1771 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001772 }
1773
1774 // size
Neil MacIntoshd5316802015-09-30 21:54:08 -07001775 constexpr size_type length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001776 {
1777 return this->size();
1778 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001779
Neil MacIntoshd5316802015-09-30 21:54:08 -07001780 constexpr size_type used_length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001781 {
1782 return length();
1783 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001784
Neil MacIntoshd5316802015-09-30 21:54:08 -07001785 constexpr size_type bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001786 {
1787 return sizeof(value_type) * this->size();
1788 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001789
Neil MacIntoshd5316802015-09-30 21:54:08 -07001790 constexpr size_type used_bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001791 {
1792 return bytes();
1793 }
1794
1795 // section
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001796 constexpr strided_array_view<ValueType, rank> section(index_type origin, index_type extents) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001797 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001798 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001799 return{ &this->operator[](origin), size, strided_bounds<rank> {extents, details::make_stride(Base::bounds())} };
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001800 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001801
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001802 constexpr reference operator[](const index_type& idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001803 {
1804 return Base::operator[](idx);
1805 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001806
Anna Gringauze1a864982015-09-14 18:55:06 -07001807 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001808 constexpr array_view<ValueType, RestDimensions...> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001809 {
1810 auto ret = Base::operator[](idx);
1811 return{ ret.data(), ret.bounds() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001812 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001813
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001814 using Base::operator==;
1815 using Base::operator!=;
1816 using Base::operator<;
1817 using Base::operator<=;
1818 using Base::operator>;
1819 using Base::operator>=;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001820};
1821
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001822template <typename T, std::ptrdiff_t... Dimensions>
1823constexpr 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 -07001824{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001825 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 -07001826}
1827
1828template <typename T>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001829constexpr auto as_array_view (T* arr, std::ptrdiff_t len) -> typename details::ArrayViewArrayTraits<T, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001830{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001831 return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001832}
1833
1834template <typename T, size_t N>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001835constexpr auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits<T, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001836{
1837 return {arr};
1838}
1839
1840template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001841constexpr array_view<const T, N> as_array_view(const std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001842{
1843 return {arr};
1844}
1845
1846template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001847constexpr array_view<const T, N> as_array_view(const std::array<T, N> &&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001848
1849template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001850constexpr array_view<T, N> as_array_view(std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001851{
1852 return {arr};
1853}
1854
1855template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001856constexpr array_view<T, dynamic_range> as_array_view(T *begin, T *end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001857{
1858 return {begin, end};
1859}
1860
1861template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001862constexpr 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 -07001863 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
1864{
1865 return {arr.data(), arr.size()};
1866}
1867
1868template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001869constexpr 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 -07001870 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
1871
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001872template <typename ValueType, size_t Rank>
1873class strided_array_view : public basic_array_view<ValueType, strided_bounds<Rank>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001874{
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001875 using Base = basic_array_view<ValueType, strided_bounds<Rank>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001876
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001877 template<typename OtherValue, size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001878 friend class strided_array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001879
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001880public:
1881 using Base::rank;
1882 using typename Base::bounds_type;
1883 using typename Base::size_type;
1884 using typename Base::pointer;
1885 using typename Base::value_type;
1886 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001887 using typename Base::iterator;
1888 using typename Base::const_iterator;
Anna Gringauze9dac1782015-09-14 19:08:03 -07001889 using typename Base::reference;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001890
1891 // from static array of size N
1892 template<size_type N>
1893 strided_array_view(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds))
1894 {
1895 fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries");
1896 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001897
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001898 // from raw data
1899 strided_array_view(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001900 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001901 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001902 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001903
1904 // from array view
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001905 template <std::ptrdiff_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
1906 strided_array_view(array_view<ValueType, Dimensions...> av, bounds_type bounds) : Base(av.data(), std::move(bounds))
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001907 {
1908 fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries");
1909 }
1910
1911 // convertible
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001912 template <typename OtherValueType,
1913 typename BaseType = basic_array_view<ValueType, strided_bounds<Rank>>,
1914 typename OtherBaseType = basic_array_view<OtherValueType, strided_bounds<Rank>>,
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001915 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1916 >
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001917 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
1918 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001919
1920 // convert from bytes
Anna Gringauze1a864982015-09-14 18:55:06 -07001921 template <typename OtherValueType>
1922 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 -07001923 {
1924 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
1925 auto d = sizeof(OtherValueType) / sizeof(value_type);
1926
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001927 size_type size = this->bounds().total_size() / d;
1928 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 -07001929 }
1930
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001931 strided_array_view section(index_type origin, index_type extents) const
1932 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001933 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001934 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}};
1935 }
1936
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001937 constexpr reference operator[](const index_type& idx) const
Anna Gringauze9dac1782015-09-14 19:08:03 -07001938 {
1939 return Base::operator[](idx);
1940 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001941
1942 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001943 constexpr strided_array_view<value_type, rank-1> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001944 {
1945 auto ret = Base::operator[](idx);
1946 return{ ret.data(), ret.bounds().total_size(), ret.bounds() };
1947 }
1948
1949private:
1950 static index_type resize_extent(const index_type& extent, size_t d)
1951 {
1952 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");
1953
1954 index_type ret = extent;
1955 ret[rank - 1] /= d;
1956
1957 return ret;
1958 }
1959
1960 template <bool Enabled = (rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Kosov Eugene3402b922015-09-28 21:20:02 +03001961 static index_type resize_stride(const index_type& strides, size_t , void * = 0)
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001962 {
1963 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1964
1965 return strides;
1966 }
1967
1968 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
1969 static index_type resize_stride(const index_type& strides, size_t d)
1970 {
1971 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1972 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");
1973
Neil MacIntosh99746e22015-09-27 16:53:58 -07001974 for (size_t i = rank - 1; i > 0; --i)
1975 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 -07001976
1977 index_type ret = strides / d;
1978 ret[rank - 1] = 1;
1979
1980 return ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001981 }
1982};
1983
1984template <typename ArrayView>
1985class contiguous_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
1986{
1987 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
1988public:
1989 using typename Base::reference;
1990 using typename Base::pointer;
1991 using typename Base::difference_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001992
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001993private:
1994 template <typename ValueType, typename Bounds>
1995 friend class basic_array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001996
1997 pointer m_pdata;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001998 const ArrayView * m_validator;
1999 void validateThis() const
2000 {
Neil MacIntosh383dc502015-09-14 15:41:40 -07002001 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 -07002002 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07002003
2004 contiguous_array_view_iterator (const ArrayView *container, bool isbegin = false) :
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002005 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) { }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07002006
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002007public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07002008 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002009 {
2010 validateThis();
2011 return *m_pdata;
2012 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002013 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002014 {
2015 validateThis();
2016 return m_pdata;
2017 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002018 contiguous_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002019 {
2020 ++m_pdata;
2021 return *this;
2022 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002023 contiguous_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002024 {
2025 auto ret = *this;
2026 ++(*this);
2027 return ret;
2028 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002029 contiguous_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002030 {
2031 --m_pdata;
2032 return *this;
2033 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002034 contiguous_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002035 {
2036 auto ret = *this;
2037 --(*this);
2038 return ret;
2039 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002040 contiguous_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002041 {
2042 contiguous_array_view_iterator ret{ *this };
2043 return ret += n;
2044 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002045 contiguous_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002046 {
2047 m_pdata += n;
2048 return *this;
2049 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002050 contiguous_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002051 {
2052 contiguous_array_view_iterator ret{ *this };
2053 return ret -= n;
2054 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002055 contiguous_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002056 {
2057 return *this += -n;
2058 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002059 difference_type operator-(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002060 {
2061 fail_fast_assert(m_validator == rhs.m_validator);
2062 return m_pdata - rhs.m_pdata;
2063 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002064 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002065 {
2066 return *(*this + n);
2067 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002068 bool operator==(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002069 {
2070 fail_fast_assert(m_validator == rhs.m_validator);
2071 return m_pdata == rhs.m_pdata;
2072 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002073 bool operator!=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002074 {
2075 return !(*this == rhs);
2076 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002077 bool operator<(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002078 {
2079 fail_fast_assert(m_validator == rhs.m_validator);
2080 return m_pdata < rhs.m_pdata;
2081 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002082 bool operator<=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002083 {
2084 return !(rhs < *this);
2085 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002086 bool operator>(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002087 {
2088 return rhs < *this;
2089 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002090 bool operator>=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002091 {
2092 return !(rhs > *this);
2093 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002094 void swap(contiguous_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002095 {
2096 std::swap(m_pdata, rhs.m_pdata);
2097 std::swap(m_validator, rhs.m_validator);
2098 }
2099};
2100
2101template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07002102contiguous_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 -07002103{
2104 return rhs + n;
2105}
2106
2107template <typename ArrayView>
2108class general_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
2109{
2110 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
2111public:
2112 using typename Base::reference;
2113 using typename Base::pointer;
2114 using typename Base::difference_type;
2115 using typename Base::value_type;
2116private:
2117 template <typename ValueType, typename Bounds>
2118 friend class basic_array_view;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07002119
2120 const ArrayView * m_container;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07002121 typename ArrayView::bounds_type::iterator m_itr;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07002122
2123 general_array_view_iterator(const ArrayView *container, bool isbegin = false) :
2124 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
2125 {}
2126
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002127public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07002128 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002129 {
2130 return (*m_container)[*m_itr];
2131 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002132 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002133 {
2134 return &(*m_container)[*m_itr];
2135 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002136 general_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002137 {
2138 ++m_itr;
2139 return *this;
2140 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002141 general_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002142 {
2143 auto ret = *this;
2144 ++(*this);
2145 return ret;
2146 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002147 general_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002148 {
2149 --m_itr;
2150 return *this;
2151 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002152 general_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002153 {
2154 auto ret = *this;
2155 --(*this);
2156 return ret;
2157 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002158 general_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002159 {
2160 general_array_view_iterator ret{ *this };
2161 return ret += n;
2162 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002163 general_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002164 {
2165 m_itr += n;
2166 return *this;
2167 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002168 general_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002169 {
2170 general_array_view_iterator ret{ *this };
2171 return ret -= n;
2172 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002173 general_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002174 {
2175 return *this += -n;
2176 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002177 difference_type operator-(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002178 {
2179 fail_fast_assert(m_container == rhs.m_container);
2180 return m_itr - rhs.m_itr;
2181 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002182 value_type operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002183 {
2184 return (*m_container)[m_itr[n]];;
2185 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002186 bool operator==(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002187 {
2188 fail_fast_assert(m_container == rhs.m_container);
2189 return m_itr == rhs.m_itr;
2190 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002191 bool operator !=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002192 {
2193 return !(*this == rhs);
2194 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002195 bool operator<(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002196 {
2197 fail_fast_assert(m_container == rhs.m_container);
2198 return m_itr < rhs.m_itr;
2199 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002200 bool operator<=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002201 {
2202 return !(rhs < *this);
2203 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002204 bool operator>(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002205 {
2206 return rhs < *this;
2207 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002208 bool operator>=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002209 {
2210 return !(rhs > *this);
2211 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002212 void swap(general_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002213 {
2214 std::swap(m_itr, rhs.m_itr);
2215 std::swap(m_container, rhs.m_container);
2216 }
2217};
2218
2219template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07002220general_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 -07002221{
2222 return rhs + n;
2223}
2224
Neil MacIntoshef626fd2015-09-29 16:41:37 -07002225} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002226
Neil MacIntoshd5316802015-09-30 21:54:08 -07002227#ifdef _MSC_VER
2228
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002229#undef constexpr
2230#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002231
Neil MacIntoshd5316802015-09-30 21:54:08 -07002232#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002233#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07002234
2235#ifndef GSL_THROWS_FOR_TESTING
2236#pragma undef noexcept
2237#endif // GSL_THROWS_FOR_TESTING
2238
Neil MacIntosh9a297122015-09-14 15:11:07 -07002239#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002240
Neil MacIntoshd5316802015-09-30 21:54:08 -07002241#endif // _MSC_VER
2242
2243#if defined(GSL_THROWS_FOR_TESTING)
2244#undef noexcept
2245#endif // GSL_THROWS_FOR_TESTING
2246
Treb Connell51da1362015-09-24 18:08:34 -07002247
2248#endif // GSL_ARRAY_VIEW_H