blob: a2ea49fa4a33ebbfe277b1d080c7586b39221708 [file] [log] [blame]
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001///////////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4//
5// This code is licensed under the MIT License (MIT).
6//
7// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13// THE SOFTWARE.
14//
15///////////////////////////////////////////////////////////////////////////////
16
17#pragma once
18
Treb Connell51da1362015-09-24 18:08:34 -070019#ifndef GSL_ARRAY_VIEW_H
20#define GSL_ARRAY_VIEW_H
21
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070022#include <new>
23#include <stdexcept>
24#include <cstddef>
25#include <cstdint>
26#include <limits>
Anna Gringauze2cdedda2015-10-15 13:19:24 -070027#include <numeric>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070028#include <type_traits>
29#include <utility>
30#include <array>
31#include <iterator>
Kern Handac4f9b872015-09-25 17:01:29 -070032#include <algorithm>
Neil MacIntosh01868f22015-10-15 16:48:38 -070033#include <functional>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070034#include "fail_fast.h"
35
Neil MacIntoshd5316802015-09-30 21:54:08 -070036#ifdef _MSC_VER
37
38// No MSVC does constexpr fully yet
Gabriel Dos Reis6554e832015-09-28 05:10:44 -070039#pragma push_macro("constexpr")
40#define constexpr /* nothing */
Neil MacIntoshd5316802015-09-30 21:54:08 -070041
42
43// VS 2013 workarounds
44#if _MSC_VER <= 1800
45
46// noexcept is not understood
47#ifndef GSL_THROWS_FOR_TESTING
48#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070049#endif
50
Neil MacIntoshd5316802015-09-30 21:54:08 -070051// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070052#pragma warning(push)
53#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
Neil MacIntoshd5316802015-09-30 21:54:08 -070054
Neil MacIntosh9a297122015-09-14 15:11:07 -070055#endif // _MSC_VER <= 1800
56
Neil MacIntoshd5316802015-09-30 21:54:08 -070057#endif // _MSC_VER
58
59// In order to test the library, we need it to throw exceptions that we can catch
60#ifdef GSL_THROWS_FOR_TESTING
61#define noexcept /* nothing */
62#endif // GSL_THROWS_FOR_TESTING
63
64
Neil MacIntoshef626fd2015-09-29 16:41:37 -070065namespace gsl {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070066
67/*
68** begin definitions of index and bounds
69*/
70namespace details
71{
72 template <typename SizeType>
73 struct SizeTypeTraits
74 {
Anna Gringauze5f26dda2015-10-16 17:30:48 -070075 static const SizeType max_value = std::numeric_limits<SizeType>::max();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070076 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070077}
78
Kern Handae1570262015-09-25 00:42:38 -070079template <size_t Rank, typename ValueType = size_t>
Anna Gringauzedb384972015-10-05 12:34:23 -070080class index final
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070081{
Anna Gringauzedb384972015-10-05 12:34:23 -070082 static_assert(std::is_integral<ValueType>::value, "ValueType must be an integral type!");
83 static_assert(Rank > 0, "Rank must be greater than 0!");
84
Kern Handae1570262015-09-25 00:42:38 -070085 template <size_t OtherRank, typename OtherValueType>
Anna Gringauze17ed5c32015-08-30 23:30:15 -070086 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -070087
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070088public:
Anna Gringauzedb384972015-10-05 12:34:23 -070089 static const size_t rank = Rank;
90 using value_type = std::remove_reference_t<ValueType>;
91 using reference = std::add_lvalue_reference_t<value_type>;
92 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070093
Anna Gringauze546f8cc2015-10-05 21:04:56 -070094 constexpr index() noexcept
95 {}
96
Anna Gringauzedb384972015-10-05 12:34:23 -070097 constexpr index(const value_type(&values)[Rank]) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070098 {
Anna Gringauzedb384972015-10-05 12:34:23 -070099 std::copy(values, values + Rank, elems);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700100 }
101
Anna Gringauze5f26dda2015-10-16 17:30:48 -0700102 template<typename... Ts, bool Enabled = (sizeof...(Ts) == Rank), typename Dummy = std::enable_if_t<Enabled, bool>>
103 constexpr index(Ts... ds) noexcept : elems{ static_cast<value_type>(ds)... }
104 {}
Anna Gringauzedb384972015-10-05 12:34:23 -0700105
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700106 constexpr index(const index& other) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700107
108 // copy from index over smaller domain
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700109 template <typename OtherValueType,
110 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value <= details::SizeTypeTraits<value_type>::max_value),
111 typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
112 constexpr index(const index<Rank, OtherValueType>& other) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700113 {
114 std::copy(other.elems, other.elems + Rank, elems);
115 }
116
117 // copy from index over larger domain
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700118 template <typename OtherValueType,
119 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value > details::SizeTypeTraits<value_type>::max_value),
120 typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
121 constexpr index(const index<Rank, OtherValueType>& other, void* ptr = 0) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700122 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700123 bool ok = std::accumulate(other.elems, other.elems + Rank, true,
124 [&](bool b, OtherValueType val) { return b && (val <= static_cast<OtherValueType>(details::SizeTypeTraits<value_type>::max_value)); }
125 );
Anna Gringauzedb384972015-10-05 12:34:23 -0700126
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700127 fail_fast_assert(ok, "other value must fit in the new domain");
128 std::transform(other.elems, other.elems + rank, elems, [&](OtherValueType val) { return static_cast<value_type>(val); });
Anna Gringauzedb384972015-10-05 12:34:23 -0700129 }
130
131 constexpr index& operator=(const index& rhs) noexcept = default;
132
133 // Preconditions: component_idx < rank
134 constexpr reference operator[](size_t component_idx)
135 {
136 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
137 return elems[component_idx];
138 }
139
140 // Preconditions: component_idx < rank
141 constexpr const_reference operator[](size_t component_idx) const noexcept
142 {
143 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
144 return elems[component_idx];
145 }
146
147 constexpr bool operator==(const index& rhs) const noexcept
148 {
149 return std::equal(elems, elems + rank, rhs.elems);
150 }
151
152 constexpr bool operator!=(const index& rhs) const noexcept
153 {
154 return !(this == rhs);
155 }
156
157 constexpr index operator+() const noexcept
158 {
159 return *this;
160 }
161
162 constexpr index operator-() const noexcept
163 {
164 index ret = *this;
165 std::transform(ret, ret + rank, ret, std::negate<ValueType>{});
166 return ret;
167 }
168
169 constexpr index operator+(const index& rhs) const noexcept
170 {
171 index ret = *this;
172 ret += rhs;
173 return ret;
174 }
175
176 constexpr index operator-(const index& rhs) const noexcept
177 {
178 index ret = *this;
179 ret -= rhs;
180 return ret;
181 }
182
183 constexpr index& operator+=(const index& rhs) noexcept
184 {
185 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<ValueType>{});
186 return *this;
187 }
188
189 constexpr index& operator-=(const index& rhs) noexcept
190 {
191 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<ValueType>{});
192 return *this;
193 }
194
195 constexpr index operator*(value_type v) const noexcept
196 {
197 index ret = *this;
198 ret *= v;
199 return ret;
200 }
201
202 constexpr index operator/(value_type v) const noexcept
203 {
204 index ret = *this;
205 ret /= v;
206 return ret;
207 }
208
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700209 friend constexpr index operator*(value_type v, const index& rhs) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700210 {
211 return rhs * v;
212 }
213
214 constexpr index& operator*=(value_type v) noexcept
215 {
216 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies<ValueType>{}(x, v); });
217 return *this;
218 }
219
220 constexpr index& operator/=(value_type v) noexcept
221 {
222 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<ValueType>{}(x, v); });
223 return *this;
224 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700225
Anna Gringauzedb384972015-10-05 12:34:23 -0700226private:
227 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700228};
229
230template <typename ValueType>
231class index<1, ValueType>
232{
Kern Handae1570262015-09-25 00:42:38 -0700233 template <size_t, typename OtherValueType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700234 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -0700235
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700236public:
Kern Handae1570262015-09-25 00:42:38 -0700237 static const size_t rank = 1;
Anna Gringauzedb384972015-10-05 12:34:23 -0700238 using value_type = std::remove_reference_t<ValueType>;
239 using reference = std::add_lvalue_reference_t<value_type>;
240 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700241
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700242 constexpr index() noexcept : value(0)
Anna Gringauzedb384972015-10-05 12:34:23 -0700243 {}
244
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700245 constexpr index(value_type e) noexcept : value(e)
Anna Gringauzedb384972015-10-05 12:34:23 -0700246 {}
247
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700248 constexpr index(const value_type(&values)[1]) noexcept : index(values[0])
249 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700250
Anna Gringauzedb384972015-10-05 12:34:23 -0700251 constexpr index(const index &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700252
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700253 template <typename OtherValueType,
254 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value <= details::SizeTypeTraits<value_type>::max_value),
255 typename Other = std::enable_if_t<Enabled, index<1, OtherValueType>>>
256 constexpr index(const index<1, OtherValueType>& other) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700257 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700258 value = static_cast<ValueType>(other.value);
259 }
260
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700261 template <typename OtherValueType,
262 bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value > details::SizeTypeTraits<value_type>::max_value),
263 typename Other = std::enable_if_t<Enabled, index<1, OtherValueType>>>
264 constexpr index(const index<1, OtherValueType>& other, void* ptr=0) noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700265 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700266 fail_fast_assert(other.value <= static_cast<OtherValueType>(details::SizeTypeTraits<value_type>::max_value));
Anna Gringauzedb384972015-10-05 12:34:23 -0700267 value = static_cast<value_type>(other.value);
268 }
269
Anna Gringauzedb384972015-10-05 12:34:23 -0700270 // Preconditions: component_idx < 1
271 constexpr reference operator[](value_type component_idx) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700272 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700273 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700274 (void)(component_idx);
275 return value;
276 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700277 // Preconditions: component_idx < 1
278 constexpr const_reference operator[](value_type component_idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700279 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700280 fail_fast_assert(component_idx == 0, "Component index must be less than rank");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700281 (void)(component_idx);
282 return value;
283 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700284 constexpr bool operator==(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700285 {
286 return value == rhs.value;
287 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700288 constexpr bool operator!=(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700289 {
290 return !(*this == rhs);
291 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700292 constexpr index operator+() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700293 {
294 return *this;
295 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700296 constexpr index operator-() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700297 {
298 return index(-value);
299 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700300 constexpr index operator+(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700301 {
302 return index(value + rhs.value);
303 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700304 constexpr index operator-(const index& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700305 {
306 return index(value - rhs.value);
307 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700308 constexpr index& operator+=(const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700309 {
310 value += rhs.value;
311 return *this;
312 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700313 constexpr index& operator-=(const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700314 {
315 value -= rhs.value;
316 return *this;
317 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700318 constexpr index& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700319 {
320 ++value;
321 return *this;
322 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700323 constexpr index operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700324 {
325 index ret = *this;
326 ++(*this);
327 return ret;
328 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700329 constexpr index& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700330 {
331 --value;
332 return *this;
333 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700334 constexpr index operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700335 {
336 index ret = *this;
337 --(*this);
338 return ret;
339 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700340 constexpr index operator*(value_type v) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700341 {
342 return index(value * v);
343 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700344 constexpr index operator/(value_type v) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700345 {
346 return index(value / v);
347 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700348 constexpr index& operator*=(value_type v) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700349 {
350 value *= v;
351 return *this;
352 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700353 constexpr index& operator/=(value_type v) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700354 {
355 value /= v;
356 return *this;
357 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700358 friend constexpr index operator*(value_type v, const index& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700359 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700360 return{ rhs * v };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700361 }
362private:
363 value_type value;
364};
365
366#ifndef _MSC_VER
367
368struct static_bounds_dynamic_range_t
369{
370 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
371 constexpr operator T() const noexcept
372 {
373 return static_cast<T>(-1);
374 }
375
376 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
377 constexpr bool operator ==(T other) const noexcept
378 {
379 return static_cast<T>(-1) == other;
380 }
381
382 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
383 constexpr bool operator !=(T other) const noexcept
384 {
385 return static_cast<T>(-1) != other;
386 }
387
388};
389
390template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
391constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
392{
393 return right == left;
394}
395
396template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
397constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
398{
399 return right != left;
400}
401
402constexpr static_bounds_dynamic_range_t dynamic_range{};
403#else
404const char dynamic_range = -1;
405#endif
406
407struct generalized_mapping_tag {};
408struct contiguous_mapping_tag : generalized_mapping_tag {};
409
410namespace details
411{
412 template <typename SizeType, SizeType Fact1, SizeType Fact2, SizeType ConstBound>
413 struct StaticSizeHelperImpl
414 {
415 static_assert(static_cast<size_t>(Fact1) * static_cast<size_t>(Fact2) <= SizeTypeTraits<SizeType>::max_value, "Value out of the range of SizeType");
416 static const SizeType value = Fact1 * Fact2;
417 };
418
419 template <typename SizeType, SizeType Fact1, SizeType ConstBound>
420 struct StaticSizeHelperImpl<SizeType, Fact1, ConstBound, ConstBound>
421 {
422 static const SizeType value = ConstBound;
423 };
424
425 template <typename SizeType, SizeType Fact2, SizeType ConstBound>
426 struct StaticSizeHelperImpl<SizeType, ConstBound, Fact2, ConstBound>
427 {
428 static const SizeType value = ConstBound;
429 };
430
431 template <typename SizeType, SizeType ConstBound>
432 struct StaticSizeHelperImpl<SizeType, ConstBound, ConstBound, ConstBound>
433 {
434 static const SizeType value = static_cast<SizeType>(ConstBound);
435 };
436
437 template <typename SizeType, SizeType Fact1, SizeType Fact2>
438 struct StaticSizeHelper
439 {
440 static const SizeType value = StaticSizeHelperImpl<SizeType, static_cast<SizeType>(Fact1), static_cast<SizeType>(Fact2), static_cast<SizeType>(dynamic_range)>::value;
441 };
442
443
444 template <size_t Left, size_t Right>
445 struct LessThan
446 {
447 static const bool value = Left < Right;
448 };
449
450 template <typename SizeType, size_t... Ranges>
451 struct BoundsRanges {
Kern Handae1570262015-09-25 00:42:38 -0700452 static const size_t Depth = 0;
453 static const size_t DynamicNum = 0;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700454 static const SizeType CurrentRange = 1;
455 static const SizeType TotalSize = 1;
456
457 BoundsRanges (const BoundsRanges &) = default;
458
459 // TODO : following signature is for work around VS bug
460 template <typename OtherType>
Kosov Eugene3402b922015-09-28 21:20:02 +0300461 BoundsRanges (const OtherType &, bool /* firstLevel */) {}
galikcab9bda2015-09-19 07:52:30 +0100462 BoundsRanges(const SizeType * const) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700463 BoundsRanges() = default;
464
465
Kern Handae1570262015-09-25 00:42:38 -0700466 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700467 void serialize(T &) const {
468 }
Kern Handae1570262015-09-25 00:42:38 -0700469 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700470 SizeType linearize(const T &) const {
471 return 0;
472 }
Kern Handae1570262015-09-25 00:42:38 -0700473 template <typename T, size_t Dim>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700474 ptrdiff_t contains(const T &) const {
475 return 0;
476 }
477
Neil MacIntoshd5316802015-09-30 21:54:08 -0700478 size_t totalSize() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700479 return TotalSize;
480 }
481
Neil MacIntoshd5316802015-09-30 21:54:08 -0700482 bool operator == (const BoundsRanges &) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700483 {
484 return true;
485 }
486 };
487
488 template <typename SizeType, size_t... RestRanges>
489 struct BoundsRanges <SizeType, dynamic_range, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
490 using Base = BoundsRanges <SizeType, RestRanges... >;
Kern Handae1570262015-09-25 00:42:38 -0700491 static const size_t Depth = Base::Depth + 1;
492 static const size_t DynamicNum = Base::DynamicNum + 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700493 static const SizeType CurrentRange = dynamic_range;
494 static const SizeType TotalSize = dynamic_range;
495 const SizeType m_bound;
496
497 BoundsRanges (const BoundsRanges &) = default;
498 BoundsRanges(const SizeType * const arr) : Base(arr + 1), m_bound(static_cast<SizeType>(*arr * this->Base::totalSize()))
499 {
500 fail_fast_assert(0 <= *arr);
501 fail_fast_assert(*arr * this->Base::totalSize() <= details::SizeTypeTraits<SizeType>::max_value);
502 }
503 BoundsRanges() : m_bound(0) {}
504
505 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
Kosov Eugene3402b922015-09-28 21:20:02 +0300506 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool /* firstLevel */ = true) :
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700507 Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false), m_bound (static_cast<SizeType>(other.totalSize()))
508 {
509 }
510
Kern Handae1570262015-09-25 00:42:38 -0700511 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700512 void serialize(T & arr) const {
513 arr[Dim] = elementNum();
514 this->Base::template serialize<T, Dim + 1>(arr);
515 }
Kern Handae1570262015-09-25 00:42:38 -0700516 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700517 SizeType linearize(const T & arr) const {
518 const size_t index = this->Base::totalSize() * arr[Dim];
519 fail_fast_assert(index < static_cast<size_t>(m_bound));
520 return static_cast<SizeType>(index) + this->Base::template linearize<T, Dim + 1>(arr);
521 }
522
Kern Handae1570262015-09-25 00:42:38 -0700523 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700524 ptrdiff_t contains(const T & arr) const {
525 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
526 if (last == -1)
527 return -1;
528 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
529 return static_cast<size_t>(cur) < static_cast<size_t>(m_bound) ? cur + last : -1;
530 }
531
Neil MacIntoshd5316802015-09-30 21:54:08 -0700532 size_t totalSize() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700533 return m_bound;
534 }
535
Neil MacIntoshd5316802015-09-30 21:54:08 -0700536 SizeType elementNum() const noexcept {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700537 return static_cast<SizeType>(totalSize() / this->Base::totalSize());
538 }
539
Neil MacIntoshd5316802015-09-30 21:54:08 -0700540 SizeType elementNum(size_t dim) const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700541 if (dim > 0)
542 return this->Base::elementNum(dim - 1);
543 else
544 return elementNum();
545 }
546
Neil MacIntoshd5316802015-09-30 21:54:08 -0700547 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700548 {
549 return m_bound == rhs.m_bound && static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
550 }
551 };
552
553 template <typename SizeType, size_t CurRange, size_t... RestRanges>
554 struct BoundsRanges <SizeType, CurRange, RestRanges...> : BoundsRanges<SizeType, RestRanges...>{
555 using Base = BoundsRanges <SizeType, RestRanges... >;
Kern Handae1570262015-09-25 00:42:38 -0700556 static const size_t Depth = Base::Depth + 1;
557 static const size_t DynamicNum = Base::DynamicNum;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700558 static const SizeType CurrentRange = static_cast<SizeType>(CurRange);
559 static const SizeType TotalSize = StaticSizeHelper<SizeType, Base::TotalSize, CurrentRange>::value;
560 static_assert (CurRange <= SizeTypeTraits<SizeType>::max_value, "CurRange must be smaller than SizeType limits");
561
562 BoundsRanges (const BoundsRanges &) = default;
563 BoundsRanges(const SizeType * const arr) : Base(arr) { }
564 BoundsRanges() = default;
565
566 template <typename OtherSizeType, size_t OtherRange, size_t... RestOtherRanges>
567 BoundsRanges(const BoundsRanges<OtherSizeType, OtherRange, RestOtherRanges...> &other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<OtherSizeType, RestOtherRanges...>&>(other), false)
568 {
569 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
570 }
571
Kern Handae1570262015-09-25 00:42:38 -0700572 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700573 void serialize(T & arr) const {
574 arr[Dim] = elementNum();
575 this->Base::template serialize<T, Dim + 1>(arr);
576 }
577
Kern Handae1570262015-09-25 00:42:38 -0700578 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700579 SizeType linearize(const T & arr) const {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700580 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700581 return static_cast<SizeType>(this->Base::totalSize()) * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
582 }
583
Kern Handae1570262015-09-25 00:42:38 -0700584 template <typename T, size_t Dim = 0>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700585 ptrdiff_t contains(const T & arr) const {
586 if (static_cast<size_t>(arr[Dim]) >= CurrentRange)
587 return -1;
588 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
589 if (last == -1)
590 return -1;
591 return static_cast<ptrdiff_t>(this->Base::totalSize() * arr[Dim]) + last;
592 }
593
Neil MacIntoshd5316802015-09-30 21:54:08 -0700594 size_t totalSize() const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700595 return CurrentRange * this->Base::totalSize();
596 }
597
Neil MacIntoshd5316802015-09-30 21:54:08 -0700598 SizeType elementNum() const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700599 return CurrentRange;
600 }
601
Neil MacIntoshd5316802015-09-30 21:54:08 -0700602 SizeType elementNum(size_t dim) const noexcept{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700603 if (dim > 0)
604 return this->Base::elementNum(dim - 1);
605 else
606 return elementNum();
607 }
608
Neil MacIntoshd5316802015-09-30 21:54:08 -0700609 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700610 {
611 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
612 }
613 };
614
615 template <typename SourceType, typename TargetType, size_t Rank>
616 struct BoundsRangeConvertible2;
617
618 // TODO: I have to rewrite BoundsRangeConvertible into following way to workaround VS 2013 bugs
619 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
620 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
621
622 template <size_t Rank, typename SourceType, typename TargetType>
623 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
624
625 template <typename SourceType, typename TargetType, size_t Rank>
626 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
627 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
628 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
629 {};
630
631 template <typename SourceType, typename TargetType>
632 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
633
634 template <typename SourceType, typename TargetType, size_t Rank = TargetType::Depth>
635 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
636 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
637 && (!LessThan<size_t(SourceType::CurrentRange), size_t(TargetType::CurrentRange)>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
638 {};
639 template <typename SourceType, typename TargetType>
640 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
641
642 template <typename TypeChain>
643 struct TypeListIndexer
644 {
645 const TypeChain & obj;
646 TypeListIndexer(const TypeChain & obj) :obj(obj){}
Kern Handae1570262015-09-25 00:42:38 -0700647 template<size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700648 const TypeChain & getObj(std::true_type)
649 {
650 return obj;
651 }
Kern Handae1570262015-09-25 00:42:38 -0700652 template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700653 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
654 {
655 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
656 }
Kern Handae1570262015-09-25 00:42:38 -0700657 template <size_t N>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700658 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
659 {
660 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
661 }
662 };
663
664 template <typename TypeChain>
665 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
666 {
667 return TypeListIndexer<TypeChain>(obj);
668 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700669
670 template <size_t Rank, typename ValueType, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1, ValueType>>>
671 constexpr Ret shift_left(const index<Rank, ValueType>& other) noexcept
672 {
673 Ret ret;
674 for (size_t i = 0; i < Rank - 1; ++i)
675 {
676 ret[i] = other[i + 1];
677 }
678 return ret;
679 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700680}
681
682template <typename IndexType>
683class bounds_iterator;
684
685template <typename SizeType, size_t... Ranges>
686class static_bounds {
687public:
Kosov Eugene3402b922015-09-28 21:20:02 +0300688 static_bounds(const details::BoundsRanges<SizeType, Ranges...> &) {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700689 }
690};
691
692template <typename SizeType, size_t FirstRange, size_t... RestRanges>
693class static_bounds<SizeType, FirstRange, RestRanges...>
694{
695 using MyRanges = details::BoundsRanges <SizeType, FirstRange, RestRanges... >;
696 static_assert(std::is_integral<SizeType>::value
697 && details::SizeTypeTraits<SizeType>::max_value <= SIZE_MAX, "SizeType must be an integral type and its numeric limits must be smaller than SIZE_MAX");
698
699 MyRanges m_ranges;
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700700 constexpr static_bounds(const MyRanges & range) : m_ranges(range) { }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700701
702 template <typename SizeType2, size_t... Ranges2>
703 friend class static_bounds;
704public:
Kern Handae1570262015-09-25 00:42:38 -0700705 static const size_t rank = MyRanges::Depth;
706 static const size_t dynamic_rank = MyRanges::DynamicNum;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700707 static const SizeType static_size = static_cast<SizeType>(MyRanges::TotalSize);
708
709 using size_type = SizeType;
710 using index_type = index<rank, size_type>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700711 using const_index_type = std::add_const_t<index_type>;
712 using iterator = bounds_iterator<const_index_type>;
713 using const_iterator = bounds_iterator<const_index_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700714 using difference_type = ptrdiff_t;
715 using sliced_type = static_bounds<SizeType, RestRanges...>;
716 using mapping_type = contiguous_mapping_tag;
717public:
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700718 constexpr static_bounds(const static_bounds &) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700719
720 template <typename OtherSizeType, size_t... Ranges, typename Dummy = std::enable_if_t<
721 details::BoundsRangeConvertible<details::BoundsRanges<OtherSizeType, Ranges...>, details::BoundsRanges <SizeType, FirstRange, RestRanges... >>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700722 constexpr static_bounds(const static_bounds<OtherSizeType, Ranges...> &other):
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700723 m_ranges(other.m_ranges)
724 {
725 }
726
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700727 constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700728 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700729 fail_fast_assert(MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
730 fail_fast_assert(m_ranges.totalSize() <= details::SizeTypeTraits<size_type>::max_value, "Size of the range is larger than the max element of the size type");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700731 }
732
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700733 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700734
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700735 constexpr static_bounds & operator = (const static_bounds & otherBounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700736 {
737 new(&m_ranges) MyRanges (otherBounds.m_ranges);
738 return *this;
739 }
740
Neil MacIntoshd5316802015-09-30 21:54:08 -0700741 constexpr sliced_type slice() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700742 {
743 return sliced_type{static_cast<const details::BoundsRanges<SizeType, RestRanges...> &>(m_ranges)};
744 }
745
Neil MacIntoshd5316802015-09-30 21:54:08 -0700746 constexpr size_type stride() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700747 {
748 return rank > 1 ? slice().size() : 1;
749 }
750
Neil MacIntoshd5316802015-09-30 21:54:08 -0700751 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700752 {
753 return static_cast<size_type>(m_ranges.totalSize());
754 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700755
Neil MacIntoshd5316802015-09-30 21:54:08 -0700756 constexpr size_type total_size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700757 {
758 return static_cast<size_type>(m_ranges.totalSize());
759 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700760
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700761 constexpr size_type linearize(const index_type & idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700762 {
763 return m_ranges.linearize(idx);
764 }
765
Neil MacIntoshd5316802015-09-30 21:54:08 -0700766 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700767 {
768 return m_ranges.contains(idx) != -1;
769 }
770
Neil MacIntoshd5316802015-09-30 21:54:08 -0700771 constexpr size_type operator[](size_t index) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700772 {
773 return m_ranges.elementNum(index);
774 }
775
Kern Handae1570262015-09-25 00:42:38 -0700776 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700777 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700778 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700779 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700780 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
781 }
782
Neil MacIntoshd5316802015-09-30 21:54:08 -0700783 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700784 {
Anna Gringauzefdf86432015-10-14 10:46:22 -0700785 size_type extents[rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700786 m_ranges.serialize(extents);
Anna Gringauzedb384972015-10-05 12:34:23 -0700787 return{ extents };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700788 }
789
790 template <typename OtherSizeTypes, size_t... Ranges>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700791 constexpr bool operator == (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700792 {
793 return this->size() == rhs.size();
794 }
795
796 template <typename OtherSizeTypes, size_t... Ranges>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700797 constexpr bool operator != (const static_bounds<OtherSizeTypes, Ranges...> & rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700798 {
799 return !(*this == rhs);
800 }
801
Neil MacIntoshd5316802015-09-30 21:54:08 -0700802 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700803 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700804 return const_iterator(*this, index_type{});
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700805 }
806
Neil MacIntoshd5316802015-09-30 21:54:08 -0700807 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700808 {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700809 return const_iterator(*this, this->index_bounds());
810 }
811};
812
Kern Handae1570262015-09-25 00:42:38 -0700813template <size_t Rank, typename SizeType = size_t>
Anna Gringauzedb384972015-10-05 12:34:23 -0700814class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700815{
Kern Handae1570262015-09-25 00:42:38 -0700816 template <size_t OtherRank, typename OtherSizeType>
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700817 friend class strided_bounds;
818
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700819public:
Anna Gringauzedb384972015-10-05 12:34:23 -0700820 static const size_t rank = Rank;
Anna Gringauzefdf86432015-10-14 10:46:22 -0700821 using reference = SizeType&;
822 using const_reference = const SizeType&;
823 using size_type = SizeType;
824 using difference_type = SizeType;
825 using value_type = SizeType;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700826 using index_type = index<rank, size_type>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700827 using const_index_type = std::add_const_t<index_type>;
828 using iterator = bounds_iterator<const_index_type>;
829 using const_iterator = bounds_iterator<const_index_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700830 static const int dynamic_rank = rank;
831 static const size_t static_size = dynamic_range;
832 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
833 using mapping_type = generalized_mapping_tag;
Anna Gringauzedb384972015-10-05 12:34:23 -0700834 constexpr strided_bounds(const strided_bounds &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700835
836 template <typename OtherSizeType>
Anna Gringauzedb384972015-10-05 12:34:23 -0700837 constexpr strided_bounds(const strided_bounds<rank, OtherSizeType> &other) noexcept
838 : m_extents(other.extents), m_strides(other.strides)
839 {}
840 constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept
841 : m_extents(extents), m_strides(strides)
842 {}
Neil MacIntoshd5316802015-09-30 21:54:08 -0700843 constexpr index_type strides() const noexcept
Anna Gringauzedb384972015-10-05 12:34:23 -0700844 {
845 return m_strides;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700846 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700847 constexpr size_type total_size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700848 {
849 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700850 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700851 {
852 ret += (m_extents[i] - 1) * m_strides[i];
853 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700854 return ret + 1;
855 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700856 constexpr size_type size() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700857 {
858 size_type ret = 1;
Kern Handae1570262015-09-25 00:42:38 -0700859 for (size_t i = 0; i < rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -0700860 {
861 ret *= m_extents[i];
862 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700863 return ret;
864 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700865 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700866 {
Kern Handae1570262015-09-25 00:42:38 -0700867 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700868 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700869 if (idx[i] < 0 || idx[i] >= m_extents[i])
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700870 return false;
871 }
872 return true;
873 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700874 constexpr size_type linearize(const index_type & idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700875 {
876 size_type ret = 0;
Kern Handae1570262015-09-25 00:42:38 -0700877 for (size_t i = 0; i < rank; i++)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700878 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700879 fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700880 ret += idx[i] * m_strides[i];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700881 }
882 return ret;
883 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700884 constexpr size_type stride() const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700885 {
886 return m_strides[0];
887 }
888 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -0700889 constexpr sliced_type slice() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700890 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700891 return{ details::shift_left(m_extents), details::shift_left(m_strides) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700892 }
Kern Handae1570262015-09-25 00:42:38 -0700893 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700894 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700895 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700896 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
Anna Gringauzedb384972015-10-05 12:34:23 -0700897 return m_extents[Dim];
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700898 }
Neil MacIntoshd5316802015-09-30 21:54:08 -0700899 constexpr index_type index_bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700900 {
Anna Gringauzedb384972015-10-05 12:34:23 -0700901 return m_extents;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700902 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700903 constexpr const_iterator begin() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700904 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700905 return const_iterator{ *this, index_type{} };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700906 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700907 constexpr const_iterator end() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700908 {
909 return const_iterator{ *this, index_bounds() };
910 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700911private:
Anna Gringauzedb384972015-10-05 12:34:23 -0700912 index_type m_extents;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700913 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700914};
915
916template <typename T>
917struct is_bounds : std::integral_constant<bool, false> {};
918template <typename SizeType, size_t... Ranges>
919struct is_bounds<static_bounds<SizeType, Ranges...>> : std::integral_constant<bool, true> {};
Kern Handae1570262015-09-25 00:42:38 -0700920template <size_t Rank, typename SizeType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700921struct is_bounds<strided_bounds<Rank, SizeType>> : std::integral_constant<bool, true> {};
922
923template <typename IndexType>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700924class bounds_iterator: public std::iterator<std::random_access_iterator_tag, IndexType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700925{
926private:
Anna Gringauzea4654a42015-10-16 12:15:22 -0700927 using Base = std::iterator <std::random_access_iterator_tag, IndexType>;
928
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700929public:
Kern Handae1570262015-09-25 00:42:38 -0700930 static const size_t rank = IndexType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700931 using typename Base::reference;
932 using typename Base::pointer;
933 using typename Base::difference_type;
934 using typename Base::value_type;
935 using index_type = value_type;
Anna Gringauzedb384972015-10-05 12:34:23 -0700936 using index_size_type = typename IndexType::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700937 template <typename Bounds>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700938 explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
939 : boundary(bnd.index_bounds()), curr(std::move(curr))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700940 {
941 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
942 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700943
944 constexpr reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700945 {
946 return curr;
947 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700948
949 constexpr pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700950 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700951 return &curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700952 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700953
954 constexpr bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700955 {
Kern Handae1570262015-09-25 00:42:38 -0700956 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700957 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700958 if (curr[i] < boundary[i] - 1)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700959 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700960 curr[i]++;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700961 return *this;
962 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700963 curr[i] = 0;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700964 }
965 // If we're here we've wrapped over - set to past-the-end.
Anna Gringauzea4654a42015-10-16 12:15:22 -0700966 curr = boundary;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700967 return *this;
968 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700969
970 constexpr bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700971 {
972 auto ret = *this;
973 ++(*this);
974 return ret;
975 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700976
977 constexpr bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700978 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700979 if (!less(curr, boundary))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700980 {
Anna Gringauzea4654a42015-10-16 12:15:22 -0700981 // if at the past-the-end, set to last element
982 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700983 {
984 curr[i] = boundary[i] - 1;
985 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700986 return *this;
987 }
988 for (size_t i = rank; i-- > 0;)
989 {
990 if (curr[i] >= 1)
991 {
992 curr[i]--;
993 return *this;
994 }
995 curr[i] = boundary[i] - 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700996 }
997 // If we're here the preconditions were violated
998 // "pre: there exists s such that r == ++s"
999 fail_fast_assert(false);
1000 return *this;
1001 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001002
1003 constexpr bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001004 {
1005 auto ret = *this;
1006 --(*this);
1007 return ret;
1008 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001009
1010 constexpr bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001011 {
1012 bounds_iterator ret{ *this };
1013 return ret += n;
1014 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001015
1016 constexpr bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001017 {
1018 auto linear_idx = linearize(curr) + n;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001019 std::remove_const_t<value_type> stride;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001020 stride[rank - 1] = 1;
Kern Handae1570262015-09-25 00:42:38 -07001021 for (size_t i = rank - 1; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001022 {
1023 stride[i] = stride[i + 1] * boundary[i + 1];
1024 }
Kern Handae1570262015-09-25 00:42:38 -07001025 for (size_t i = 0; i < rank; ++i)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001026 {
1027 curr[i] = linear_idx / stride[i];
1028 linear_idx = linear_idx % stride[i];
1029 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001030 fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001031 return *this;
1032 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001033
1034 constexpr bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001035 {
1036 bounds_iterator ret{ *this };
1037 return ret -= n;
1038 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001039
1040 constexpr bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001041 {
1042 return *this += -n;
1043 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001044
1045 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001046 {
1047 return linearize(curr) - linearize(rhs.curr);
1048 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001049
1050 constexpr reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001051 {
1052 return *(*this + n);
1053 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001054
1055 constexpr bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001056 {
1057 return curr == rhs.curr;
1058 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001059
1060 constexpr bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001061 {
1062 return !(*this == rhs);
1063 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001064
1065 constexpr bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001066 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001067 return less(curr, rhs.curr);
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001068 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001069
1070 constexpr bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001071 {
1072 return !(rhs < *this);
1073 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001074
1075 constexpr bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001076 {
1077 return rhs < *this;
1078 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001079
1080 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001081 {
1082 return !(rhs > *this);
1083 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001084
Neil MacIntoshd5316802015-09-30 21:54:08 -07001085 void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001086 {
1087 std::swap(boundary, rhs.boundary);
1088 std::swap(curr, rhs.curr);
1089 }
1090private:
Anna Gringauzea4654a42015-10-16 12:15:22 -07001091 constexpr bool less(index_type& one, index_type& other) const noexcept
1092 {
1093 for (size_t i = 0; i < rank; ++i)
1094 {
1095 if (one[i] < other[i])
1096 return true;
1097 }
1098 return false;
1099 }
1100
1101 constexpr index_size_type linearize(const value_type& idx) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001102 {
1103 // TODO: Smarter impl.
1104 // Check if past-the-end
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001105 index_size_type multiplier = 1;
1106 index_size_type res = 0;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001107 if (!less(idx, boundary))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001108 {
1109 res = 1;
Kern Handae1570262015-09-25 00:42:38 -07001110 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001111 {
1112 res += (idx[i] - 1) * multiplier;
1113 multiplier *= boundary[i];
1114 }
1115 }
1116 else
1117 {
Kern Handae1570262015-09-25 00:42:38 -07001118 for (size_t i = rank; i-- > 0;)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001119 {
1120 res += idx[i] * multiplier;
1121 multiplier *= boundary[i];
1122 }
1123 }
1124 return res;
1125 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001126
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001127 value_type boundary;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001128 std::remove_const_t<value_type> curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001129};
1130
1131template <typename SizeType>
Anna Gringauzea4654a42015-10-16 12:15:22 -07001132class bounds_iterator<index<1, SizeType>> : public std::iterator<std::random_access_iterator_tag, index<1, SizeType>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001133{
Anna Gringauzea4654a42015-10-16 12:15:22 -07001134 using Base = std::iterator<std::random_access_iterator_tag, index<1, SizeType>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001135
1136public:
1137 using typename Base::reference;
1138 using typename Base::pointer;
1139 using typename Base::difference_type;
1140 using typename Base::value_type;
1141 using index_type = value_type;
Anna Gringauzedb384972015-10-05 12:34:23 -07001142 using index_size_type = typename index_type::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001143
1144 template <typename Bounds>
Anna Gringauzea4654a42015-10-16 12:15:22 -07001145 constexpr explicit bounds_iterator(const Bounds&, value_type curr) noexcept
1146 : curr(std::move(curr))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001147 {}
Anna Gringauzea4654a42015-10-16 12:15:22 -07001148
1149 constexpr reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001150 {
1151 return curr;
1152 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001153
1154 constexpr pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001155 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001156 &curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001157 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001158
1159 constexpr bounds_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001160 {
1161 ++curr;
1162 return *this;
1163 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001164
1165 constexpr bounds_iterator operator++(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001166 {
1167 auto ret = *this;
1168 ++(*this);
1169 return ret;
1170 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001171
1172 constexpr bounds_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001173 {
1174 curr--;
1175 return *this;
1176 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001177
1178 constexpr bounds_iterator operator--(int) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001179 {
1180 auto ret = *this;
1181 --(*this);
1182 return ret;
1183 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001184
1185 constexpr bounds_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001186 {
1187 bounds_iterator ret{ *this };
1188 return ret += n;
1189 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001190
1191 constexpr bounds_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001192 {
1193 curr += n;
1194 return *this;
1195 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001196
1197 constexpr bounds_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001198 {
1199 bounds_iterator ret{ *this };
1200 return ret -= n;
1201 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001202
1203 constexpr bounds_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001204 {
1205 return *this += -n;
1206 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001207
1208 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001209 {
1210 return curr[0] - rhs.curr[0];
1211 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001212
1213 constexpr reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001214 {
1215 return curr + n;
1216 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001217
1218 constexpr bool operator==(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001219 {
1220 return curr == rhs.curr;
1221 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001222
1223 constexpr bool operator!=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001224 {
1225 return !(*this == rhs);
1226 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001227
1228 constexpr bool operator<(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001229 {
1230 return curr[0] < rhs.curr[0];
1231 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001232
1233 constexpr bool operator<=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001234 {
1235 return !(rhs < *this);
1236 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001237
1238 constexpr bool operator>(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001239 {
1240 return rhs < *this;
1241 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001242
1243 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001244 {
1245 return !(rhs > *this);
1246 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001247
1248 constexpr void swap(bounds_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001249 {
1250 std::swap(curr, rhs.curr);
1251 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001252
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001253private:
Anna Gringauzea4654a42015-10-16 12:15:22 -07001254 std::remove_const_t<value_type> curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001255};
1256
1257template <typename IndexType>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001258bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001259{
1260 return rhs + n;
1261}
1262
1263/*
1264** begin definitions of basic_array_view
1265*/
1266namespace details
1267{
1268 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001269 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 -07001270 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001271 return bnd.strides();
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001272 }
1273
Neil MacIntosh99746e22015-09-27 16:53:58 -07001274 // Make a stride vector from bounds, assuming contiguous memory.
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001275 template <typename Bounds>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001276 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 -07001277 {
1278 auto extents = bnd.index_bounds();
Anna Gringauzefdf86432015-10-14 10:46:22 -07001279 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001280
1281 stride[Bounds::rank - 1] = 1;
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001282 for (size_t i = 1; i < Bounds::rank; ++i)
Anna Gringauzedb384972015-10-05 12:34:23 -07001283 {
Anna Gringauze546f8cc2015-10-05 21:04:56 -07001284 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
Anna Gringauzedb384972015-10-05 12:34:23 -07001285 }
1286 return{ stride };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001287 }
1288
1289 template <typename BoundsSrc, typename BoundsDest>
1290 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1291 {
1292 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1293 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1294 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");
1295 fail_fast_assert(src.size() == dest.size());
1296 }
1297
1298
1299} // namespace details
1300
1301template <typename ArrayView>
1302class contiguous_array_view_iterator;
1303template <typename ArrayView>
1304class general_array_view_iterator;
1305enum class byte : std::uint8_t {};
1306
1307template <typename ValueType, typename BoundsType>
1308class basic_array_view
1309{
1310public:
Kern Handae1570262015-09-25 00:42:38 -07001311 static const size_t rank = BoundsType::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001312 using bounds_type = BoundsType;
1313 using size_type = typename bounds_type::size_type;
1314 using index_type = typename bounds_type::index_type;
1315 using value_type = ValueType;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001316 using const_value_type = std::add_const_t<value_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001317 using pointer = ValueType*;
1318 using reference = ValueType&;
1319 using iterator = std::conditional_t<std::is_same<typename BoundsType::mapping_type, contiguous_mapping_tag>::value, contiguous_array_view_iterator<basic_array_view>, general_array_view_iterator<basic_array_view>>;
Anna Gringauzea4654a42015-10-16 12:15:22 -07001320 using const_iterator = std::conditional_t<std::is_same<typename BoundsType::mapping_type, contiguous_mapping_tag>::value, contiguous_array_view_iterator<basic_array_view<const_value_type, BoundsType>>, general_array_view_iterator<basic_array_view<const_value_type, BoundsType>>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001321 using reverse_iterator = std::reverse_iterator<iterator>;
1322 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1323 using sliced_type = std::conditional_t<rank == 1, value_type, basic_array_view<value_type, typename BoundsType::sliced_type>>;
1324
1325private:
1326 pointer m_pdata;
1327 bounds_type m_bounds;
1328
1329public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07001330 constexpr bounds_type bounds() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001331 {
1332 return m_bounds;
1333 }
Kern Handae1570262015-09-25 00:42:38 -07001334 template <size_t Dim = 0>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001335 constexpr size_type extent() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001336 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001337 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001338 return m_bounds.template extent<Dim>();
1339 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001340 constexpr size_type size() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001341 {
1342 return m_bounds.size();
1343 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001344 constexpr reference operator[](const index_type& idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001345 {
1346 return m_pdata[m_bounds.linearize(idx)];
1347 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001348 constexpr pointer data() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001349 {
1350 return m_pdata;
1351 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001352 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001353 constexpr Ret operator[](size_type idx) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001354 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001355 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001356 const size_type ridx = idx * m_bounds.stride();
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001357
1358 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001359 return Ret {m_pdata + ridx, m_bounds.slice()};
1360 }
1361
Neil MacIntoshd5316802015-09-30 21:54:08 -07001362 constexpr operator bool () const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001363 {
1364 return m_pdata != nullptr;
1365 }
1366
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001367 constexpr iterator begin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001368 {
1369 return iterator {this, true};
1370 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001371 constexpr iterator end() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001372 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001373 return iterator {this, false};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001374 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001375 constexpr const_iterator cbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001376 {
1377 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), true};
1378 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001379 constexpr const_iterator cend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001380 {
Anna Gringauzea4654a42015-10-16 12:15:22 -07001381 return const_iterator {reinterpret_cast<const basic_array_view<const value_type, bounds_type> *>(this), false};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001382 }
1383
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001384 constexpr reverse_iterator rbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001385 {
1386 return reverse_iterator {end()};
1387 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001388 constexpr reverse_iterator rend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001389 {
1390 return reverse_iterator {begin()};
1391 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001392 constexpr const_reverse_iterator crbegin() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001393 {
1394 return const_reverse_iterator {cend()};
1395 }
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001396 constexpr const_reverse_iterator crend() const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001397 {
1398 return const_reverse_iterator {cbegin()};
1399 }
1400
1401 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 -07001402 constexpr bool operator== (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001403 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001404 return m_bounds.size() == other.m_bounds.size() &&
1405 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001406 }
1407
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001408 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001409 constexpr bool operator!= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001410 {
1411 return !(*this == other);
1412 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001413
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001414 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001415 constexpr bool operator< (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001416 {
1417 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1418 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001419
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001420 template <typename OtherValueType, typename OtherBoundsType, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001421 constexpr bool operator<= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001422 {
1423 return !(other < *this);
1424 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001425
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001426 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 -07001427 constexpr bool operator> (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001428 {
1429 return (other < *this);
1430 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001431
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001432 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 -07001433 constexpr bool operator>= (const basic_array_view<OtherValueType, OtherBoundsType> & other) const noexcept
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001434 {
1435 return !(*this < other);
1436 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001437
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001438public:
1439 template <typename OtherValueType, typename OtherBounds,
1440 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value
1441 && std::is_convertible<OtherBounds, bounds_type>::value>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001442 constexpr basic_array_view(const basic_array_view<OtherValueType, OtherBounds> & other ) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001443 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
1444 {
1445 }
1446protected:
1447
Neil MacIntoshd5316802015-09-30 21:54:08 -07001448 constexpr basic_array_view(pointer data, bounds_type bound) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001449 : m_pdata(data)
1450 , m_bounds(std::move(bound))
1451 {
1452 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1453 }
1454 template <typename T>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001455 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 -07001456 : m_pdata(reinterpret_cast<pointer>(data))
1457 , m_bounds(std::move(bound))
1458 {
1459 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1460 }
1461 template <typename DestBounds>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001462 constexpr basic_array_view<value_type, DestBounds> as_array_view(const DestBounds &bounds)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001463 {
1464 details::verifyBoundsReshape(m_bounds, bounds);
1465 return {m_pdata, bounds};
1466 }
1467private:
1468
1469 friend iterator;
1470 friend const_iterator;
1471 template <typename ValueType2, typename BoundsType2>
1472 friend class basic_array_view;
1473};
1474
1475template <size_t DimSize = dynamic_range>
1476struct dim
1477{
1478 static const size_t value = DimSize;
1479};
1480template <>
1481struct dim<dynamic_range>
1482{
1483 static const size_t value = dynamic_range;
1484 const size_t dvalue;
1485 dim(size_t size) : dvalue(size) {}
1486};
1487
1488template <typename ValueTypeOpt, size_t FirstDimension = dynamic_range, size_t... RestDimensions>
1489class array_view;
Kern Handae1570262015-09-25 00:42:38 -07001490template <typename ValueTypeOpt, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001491class strided_array_view;
1492
1493namespace details
1494{
1495 template <typename T, typename = std::true_type>
1496 struct ArrayViewTypeTraits
1497 {
1498 using value_type = T;
1499 using size_type = size_t;
1500 };
1501
1502 template <typename Traits>
1503 struct ArrayViewTypeTraits<Traits, typename std::is_reference<typename Traits::array_view_traits &>::type>
1504 {
1505 using value_type = typename Traits::array_view_traits::value_type;
1506 using size_type = typename Traits::array_view_traits::size_type;
1507 };
1508
1509 template <typename T, typename SizeType, size_t... Ranks>
1510 struct ArrayViewArrayTraits {
1511 using type = array_view<T, Ranks...>;
1512 using value_type = T;
1513 using bounds_type = static_bounds<SizeType, Ranks...>;
1514 using pointer = T*;
1515 using reference = T&;
1516 };
1517 template <typename T, typename SizeType, size_t N, size_t... Ranks>
1518 struct ArrayViewArrayTraits<T[N], SizeType, Ranks...> : ArrayViewArrayTraits<T, SizeType, Ranks..., N> {};
1519
1520 template <typename BoundsType>
1521 BoundsType newBoundsHelperImpl(size_t totalSize, std::true_type) // dynamic size
1522 {
1523 fail_fast_assert(totalSize <= details::SizeTypeTraits<typename BoundsType::size_type>::max_value);
1524 return BoundsType{static_cast<typename BoundsType::size_type>(totalSize)};
1525 }
1526 template <typename BoundsType>
1527 BoundsType newBoundsHelperImpl(size_t totalSize, std::false_type) // static size
1528 {
1529 fail_fast_assert(BoundsType::static_size == totalSize);
1530 return {};
1531 }
1532 template <typename BoundsType>
1533 BoundsType newBoundsHelper(size_t totalSize)
1534 {
1535 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1536 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1537 }
1538
1539 struct Sep{};
1540
1541 template <typename T, typename... Args>
1542 T static_as_array_view_helper(Sep, Args... args)
1543 {
1544 return T{static_cast<typename T::size_type>(args)...};
1545 }
1546 template <typename T, typename Arg, typename... Args>
1547 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)
1548 {
1549 return static_as_array_view_helper<T>(args...);
1550 }
1551 template <typename T, typename... Args>
1552 T static_as_array_view_helper(dim<dynamic_range> val, Args ... args)
1553 {
1554 return static_as_array_view_helper<T>(args..., val.dvalue);
1555 }
1556
1557 template <typename SizeType, typename ...Dimensions>
1558 struct static_as_array_view_static_bounds_helper
1559 {
1560 using type = static_bounds<SizeType, (Dimensions::value)...>;
1561 };
1562
1563 template <typename T>
1564 struct is_array_view_oracle : std::false_type
1565 {};
1566 template <typename ValueType, size_t FirstDimension, size_t... RestDimensions>
1567 struct is_array_view_oracle<array_view<ValueType, FirstDimension, RestDimensions...>> : std::true_type
1568 {};
Kern Handae1570262015-09-25 00:42:38 -07001569 template <typename ValueType, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001570 struct is_array_view_oracle<strided_array_view<ValueType, Rank>> : std::true_type
1571 {};
1572 template <typename T>
1573 struct is_array_view : is_array_view_oracle<std::remove_cv_t<T>>
1574 {};
1575
1576}
1577
1578
1579template <typename ValueType, typename SizeType>
1580struct array_view_options
1581{
1582 struct array_view_traits
1583 {
1584 using value_type = ValueType;
1585 using size_type = SizeType;
1586 };
1587};
1588
1589template <typename ValueTypeOpt, size_t FirstDimension, size_t... RestDimensions>
1590class array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
1591 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>
1592{
1593 template <typename ValueTypeOpt2, size_t FirstDimension2, size_t... RestDimensions2>
1594 friend class array_view;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001595 using Base = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001596 static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001597
1598public:
1599 using typename Base::bounds_type;
1600 using typename Base::size_type;
1601 using typename Base::pointer;
1602 using typename Base::value_type;
1603 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001604 using typename Base::iterator;
1605 using typename Base::const_iterator;
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001606 using typename Base::reference;
Neil MacIntosh383dc502015-09-14 15:41:40 -07001607 using Base::rank;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001608
1609public:
1610 // basic
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001611 constexpr array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001612 {
1613 }
1614
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001615 constexpr array_view(std::nullptr_t) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001616 {
1617 }
1618
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001619 constexpr array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001620 {
1621 fail_fast_assert(size == 0);
1622 }
1623
1624 // default
1625 template <size_t DynamicRank = bounds_type::dynamic_rank, typename Dummy = std::enable_if_t<DynamicRank != 0>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001626 constexpr array_view() : Base(nullptr, bounds_type())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001627 {
1628 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001629
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001630 // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
1631 template <typename T, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
Anna Gringauze18cd9802015-09-14 16:34:26 -07001632 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type (*)[], typename Base::value_type (*)[]>::value
1633 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001634 constexpr array_view(T * const & data, size_type size) : Base(data, typename Helper::bounds_type{size})
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001635 {
1636 }
1637
1638 // from n-dimensions static array
1639 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, N>,
1640 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], typename Base::value_type(*)[]>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001641 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001642 constexpr array_view (T (&arr)[N]) : Base(arr, typename Helper::bounds_type())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001643 {
1644 }
1645
1646 // from n-dimensions static array with size
1647 template <typename T, size_t N, typename Helper = details::ArrayViewArrayTraits<T, size_type, dynamic_range>,
1648 typename Dummy = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], typename Base::value_type(*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001649 && std::is_convertible<typename Helper::bounds_type, typename Base::bounds_type>::value >>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001650 constexpr array_view(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{ size })
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001651 {
1652 fail_fast_assert(size <= N);
1653 }
1654
1655 // from std array
1656 template <size_t N, typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<size_type, N>, typename Base::bounds_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001657 constexpr array_view (std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<size_type, N>())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001658 {
1659 }
1660
1661 template <size_t N, typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<size_type, N>, typename Base::bounds_type>::value && std::is_const<value_type>::value>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001662 constexpr array_view (const std::array<std::remove_const_t<value_type>, N> & arr) : Base(arr.data(), static_bounds<size_type, N>())
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001663 {
1664 }
1665
1666
1667 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1668 template <typename Ptr,
1669 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
1670 && details::LessThan<Base::bounds_type::dynamic_rank, 2>::value>> // remove literal 0 case
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001671 constexpr array_view (pointer begin, Ptr end) : Base(begin, details::newBoundsHelper<typename Base::bounds_type>(static_cast<pointer>(end) - begin))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001672 {
1673 }
1674
1675 // from containers. It must has .size() and .data() two function signatures
1676 template <typename Cont, typename DataType = typename Cont::value_type, typename SizeType = typename Cont::size_type,
1677 typename Dummy = std::enable_if_t<!details::is_array_view<Cont>::value
Anna Gringauze18cd9802015-09-14 16:34:26 -07001678 && std::is_convertible<DataType (*)[], typename Base::value_type (*)[]>::value
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001679 && std::is_convertible<static_bounds<SizeType, dynamic_range>, typename Base::bounds_type>::value
1680 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001681 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001682 constexpr array_view (Cont& cont) : Base(static_cast<pointer>(cont.data()), details::newBoundsHelper<typename Base::bounds_type>(cont.size()))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001683 {
1684
1685 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001686
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001687 constexpr array_view(const array_view &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001688
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001689 // convertible
1690 template <typename OtherValueTypeOpt, size_t... OtherDimensions,
1691 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type, FirstDimension, RestDimensions...>>,
1692 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, static_bounds<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type, OtherDimensions...>>,
1693 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1694 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001695 constexpr array_view(const array_view<OtherValueTypeOpt, OtherDimensions...> &av) : Base(static_cast<const typename array_view<OtherValueTypeOpt, OtherDimensions...>::Base &>(av)) {} // static_cast is required
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001696
1697 // reshape
1698 template <typename... Dimensions2>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001699 constexpr array_view<ValueTypeOpt, Dimensions2::value...> as_array_view(Dimensions2... dims)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001700 {
1701 static_assert(sizeof...(Dimensions2) > 0, "the target array_view must have at least one dimension.");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001702 using BoundsType = typename array_view<ValueTypeOpt, (Dimensions2::value)...>::bounds_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001703 auto tobounds = details::static_as_array_view_helper<BoundsType>(dims..., details::Sep{});
1704 details::verifyBoundsReshape(this->bounds(), tobounds);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001705 return {this->data(), tobounds};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001706 }
1707
1708 // to bytes array
1709 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001710 constexpr auto as_bytes() const noexcept ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001711 array_view<array_view_options<const byte, size_type>, static_cast<size_t>(details::StaticSizeHelper<size_type, Base::bounds_type::static_size, sizeof(value_type)>::value)>
1712 {
1713 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001714 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001715 }
1716
1717 template <bool Enabled = std::is_standard_layout<std::decay_t<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type>>::value>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001718 constexpr auto as_writeable_bytes() const noexcept ->
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001719 array_view<array_view_options<byte, size_type>, static_cast<size_t>(details::StaticSizeHelper<size_type, Base::bounds_type::static_size, sizeof(value_type)>::value)>
1720 {
1721 static_assert(Enabled, "The value_type of array_view must be standarded layout");
Anna Gringauze18cd9802015-09-14 16:34:26 -07001722 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001723 }
1724
Anna Gringauze18cd9802015-09-14 16:34:26 -07001725
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001726 // from bytes array
1727 template<typename U, bool IsByte = std::is_same<value_type, const byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001728 constexpr auto as_array_view() const noexcept -> array_view<const U, (Base::bounds_type::dynamic_rank == 0 ? Base::bounds_type::static_size / sizeof(U) : static_cast<size_type>(dynamic_range))>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001729 {
1730 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1731 "Target type must be standard layout and its size must match the byte array size");
1732 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001733 return { reinterpret_cast<const U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001734 }
1735
1736 template<typename U, bool IsByte = std::is_same<value_type, byte>::value, typename Dummy = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001737 constexpr auto as_array_view() const noexcept -> array_view<U, (Base::bounds_type::dynamic_rank == 0 ? Base::bounds_type::static_size / sizeof(U) : static_cast<size_type>(dynamic_range))>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001738 {
1739 static_assert(std::is_standard_layout<U>::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0),
1740 "Target type must be standard layout and its size must match the byte array size");
1741 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Anna Gringauze18cd9802015-09-14 16:34:26 -07001742 return { reinterpret_cast<U*>(this->data()), this->bytes() / sizeof(U) };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001743 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001744
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001745 // section on linear space
1746 template<size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001747 constexpr array_view<ValueTypeOpt, Count> first() 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()); // ensures we only check condition when needed
Anna Gringauze18cd9802015-09-14 16:34:26 -07001751 return { this->data(), Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001752 }
1753
Neil MacIntoshd5316802015-09-30 21:54:08 -07001754 constexpr array_view<ValueTypeOpt, dynamic_range> first(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(), count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001758 }
1759
1760 template<size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001761 constexpr array_view<ValueTypeOpt, Count> last() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001762 {
1763 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1764 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001765 return { this->data() + this->size() - Count, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001766 }
1767
Neil MacIntoshd5316802015-09-30 21:54:08 -07001768 constexpr array_view<ValueTypeOpt, dynamic_range> last(size_type count) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001769 {
1770 fail_fast_assert(count <= this->size());
Anna Gringauze18cd9802015-09-14 16:34:26 -07001771 return { this->data() + this->size() - count, count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001772 }
1773
1774 template<size_t Offset, size_t Count>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001775 constexpr array_view<ValueTypeOpt, Count> sub() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001776 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001777 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");
1778 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 -07001779 return { this->data() + Offset, Count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001780 }
1781
Neil MacIntoshd5316802015-09-30 21:54:08 -07001782 constexpr array_view<ValueTypeOpt, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001783 {
Neil MacIntosh05e6b6d2015-09-20 19:18:12 -07001784 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1785 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001786 }
1787
1788 // size
Neil MacIntoshd5316802015-09-30 21:54:08 -07001789 constexpr size_type length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001790 {
1791 return this->size();
1792 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001793 constexpr size_type used_length() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001794 {
1795 return length();
1796 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001797 constexpr size_type bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001798 {
1799 return sizeof(value_type) * this->size();
1800 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07001801 constexpr size_type used_bytes() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001802 {
1803 return bytes();
1804 }
1805
1806 // section
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001807 constexpr strided_array_view<ValueTypeOpt, rank> section(index_type origin, index_type extents) const
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001808 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001809 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001810 return{ &this->operator[](origin), size, strided_bounds<rank, size_type> {extents, details::make_stride(Base::bounds())} };
1811 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001812
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001813 constexpr reference operator[](const index_type& idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001814 {
1815 return Base::operator[](idx);
1816 }
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001817
Anna Gringauze1a864982015-09-14 18:55:06 -07001818 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001819 constexpr array_view<ValueTypeOpt, RestDimensions...> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001820 {
1821 auto ret = Base::operator[](idx);
1822 return{ ret.data(), ret.bounds() };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001823 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001824
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001825 using Base::operator==;
1826 using Base::operator!=;
1827 using Base::operator<;
1828 using Base::operator<=;
1829 using Base::operator>;
1830 using Base::operator>=;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001831};
1832
1833template <typename T, size_t... Dimensions>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001834constexpr 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 -07001835{
1836 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), details::static_as_array_view_helper<static_bounds<size_t, Dimensions...>>(args..., details::Sep{})};
1837}
1838
1839template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001840constexpr auto as_array_view (T * arr, size_t len) -> typename details::ArrayViewArrayTraits<T, size_t, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001841{
1842 return {arr, len};
1843}
1844
1845template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001846constexpr auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits<T, size_t, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001847{
1848 return {arr};
1849}
1850
1851template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001852constexpr array_view<const T, N> as_array_view(const std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001853{
1854 return {arr};
1855}
1856
1857template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001858constexpr array_view<const T, N> as_array_view(const std::array<T, N> &&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001859
1860template <typename T, size_t N>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001861constexpr array_view<T, N> as_array_view(std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001862{
1863 return {arr};
1864}
1865
1866template <typename T>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001867constexpr array_view<T, dynamic_range> as_array_view(T *begin, T *end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001868{
1869 return {begin, end};
1870}
1871
1872template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001873constexpr 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 -07001874 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
1875{
1876 return {arr.data(), arr.size()};
1877}
1878
1879template <typename Cont>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001880constexpr 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 -07001881 array_view<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
1882
Kern Handae1570262015-09-25 00:42:38 -07001883template <typename ValueTypeOpt, size_t Rank>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001884class strided_array_view : public basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>
1885{
1886 using Base = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001887
Kern Handae1570262015-09-25 00:42:38 -07001888 template<typename OtherValueOpt, size_t OtherRank>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001889 friend class strided_array_view;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001890public:
1891 using Base::rank;
1892 using typename Base::bounds_type;
1893 using typename Base::size_type;
1894 using typename Base::pointer;
1895 using typename Base::value_type;
1896 using typename Base::index_type;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001897 using typename Base::iterator;
1898 using typename Base::const_iterator;
Anna Gringauze9dac1782015-09-14 19:08:03 -07001899 using typename Base::reference;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001900
1901 // from static array of size N
1902 template<size_type N>
1903 strided_array_view(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds))
1904 {
1905 fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries");
1906 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001907
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001908 // from raw data
1909 strided_array_view(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds))
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001910 {
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001911 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001912 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001913
1914 // from array view
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001915 template <size_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001916 strided_array_view(array_view<ValueTypeOpt, Dimensions...> av, bounds_type bounds) : Base(av.data(), std::move(bounds))
1917 {
1918 fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries");
1919 }
1920
1921 // convertible
1922 template <typename OtherValueTypeOpt,
1923 typename BaseType = basic_array_view<typename details::ArrayViewTypeTraits<ValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<ValueTypeOpt>::size_type>>,
1924 typename OtherBaseType = basic_array_view<typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::value_type, strided_bounds<Rank, typename details::ArrayViewTypeTraits<OtherValueTypeOpt>::size_type>>,
1925 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1926 >
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001927 constexpr strided_array_view(const strided_array_view<OtherValueTypeOpt, Rank> &av): Base(static_cast<const typename strided_array_view<OtherValueTypeOpt, Rank>::Base &>(av)) // static_cast is required
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001928 {
1929 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001930
1931 // convert from bytes
Anna Gringauze1a864982015-09-14 18:55:06 -07001932 template <typename OtherValueType>
1933 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 -07001934 {
1935 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
1936 auto d = sizeof(OtherValueType) / sizeof(value_type);
1937
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001938 size_type size = this->bounds().total_size() / d;
1939 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 -07001940 }
1941
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001942 strided_array_view section(index_type origin, index_type extents) const
1943 {
Neil MacIntoshef6cc652015-09-14 21:26:17 +00001944 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001945 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}};
1946 }
1947
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001948 constexpr reference operator[](const index_type& idx) const
Anna Gringauze9dac1782015-09-14 19:08:03 -07001949 {
1950 return Base::operator[](idx);
1951 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001952
1953 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07001954 constexpr strided_array_view<value_type, rank-1> operator[](size_type idx) const
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001955 {
1956 auto ret = Base::operator[](idx);
1957 return{ ret.data(), ret.bounds().total_size(), ret.bounds() };
1958 }
1959
1960private:
1961 static index_type resize_extent(const index_type& extent, size_t d)
1962 {
1963 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");
1964
1965 index_type ret = extent;
1966 ret[rank - 1] /= d;
1967
1968 return ret;
1969 }
1970
1971 template <bool Enabled = (rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Kosov Eugene3402b922015-09-28 21:20:02 +03001972 static index_type resize_stride(const index_type& strides, size_t , void * = 0)
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001973 {
1974 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1975
1976 return strides;
1977 }
1978
1979 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
1980 static index_type resize_stride(const index_type& strides, size_t d)
1981 {
1982 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1983 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");
1984
Neil MacIntosh99746e22015-09-27 16:53:58 -07001985 for (size_t i = rank - 1; i > 0; --i)
1986 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 -07001987
1988 index_type ret = strides / d;
1989 ret[rank - 1] = 1;
1990
1991 return ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001992 }
1993};
1994
1995template <typename ArrayView>
1996class contiguous_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
1997{
1998 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
1999public:
2000 using typename Base::reference;
2001 using typename Base::pointer;
2002 using typename Base::difference_type;
2003private:
2004 template <typename ValueType, typename Bounds>
2005 friend class basic_array_view;
2006 pointer m_pdata;
2007 const ArrayView * m_validator;
2008 void validateThis() const
2009 {
Neil MacIntosh383dc502015-09-14 15:41:40 -07002010 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 -07002011 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07002012 contiguous_array_view_iterator (const ArrayView *container, bool isbegin) :
2013 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002014public:
Neil MacIntoshd5316802015-09-30 21:54:08 -07002015 reference operator*() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002016 {
2017 validateThis();
2018 return *m_pdata;
2019 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002020 pointer operator->() const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002021 {
2022 validateThis();
2023 return m_pdata;
2024 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002025 contiguous_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002026 {
2027 ++m_pdata;
2028 return *this;
2029 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002030 contiguous_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002031 {
2032 auto ret = *this;
2033 ++(*this);
2034 return ret;
2035 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002036 contiguous_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002037 {
2038 --m_pdata;
2039 return *this;
2040 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002041 contiguous_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002042 {
2043 auto ret = *this;
2044 --(*this);
2045 return ret;
2046 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002047 contiguous_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002048 {
2049 contiguous_array_view_iterator ret{ *this };
2050 return ret += n;
2051 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002052 contiguous_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002053 {
2054 m_pdata += n;
2055 return *this;
2056 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002057 contiguous_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002058 {
2059 contiguous_array_view_iterator ret{ *this };
2060 return ret -= n;
2061 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002062 contiguous_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002063 {
2064 return *this += -n;
2065 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002066 difference_type operator-(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002067 {
2068 fail_fast_assert(m_validator == rhs.m_validator);
2069 return m_pdata - rhs.m_pdata;
2070 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002071 reference operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002072 {
2073 return *(*this + n);
2074 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002075 bool operator==(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002076 {
2077 fail_fast_assert(m_validator == rhs.m_validator);
2078 return m_pdata == rhs.m_pdata;
2079 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002080 bool operator!=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002081 {
2082 return !(*this == rhs);
2083 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002084 bool operator<(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002085 {
2086 fail_fast_assert(m_validator == rhs.m_validator);
2087 return m_pdata < rhs.m_pdata;
2088 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002089 bool operator<=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002090 {
2091 return !(rhs < *this);
2092 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002093 bool operator>(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002094 {
2095 return rhs < *this;
2096 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002097 bool operator>=(const contiguous_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002098 {
2099 return !(rhs > *this);
2100 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002101 void swap(contiguous_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002102 {
2103 std::swap(m_pdata, rhs.m_pdata);
2104 std::swap(m_validator, rhs.m_validator);
2105 }
2106};
2107
2108template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07002109contiguous_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 -07002110{
2111 return rhs + n;
2112}
2113
2114template <typename ArrayView>
2115class general_array_view_iterator : public std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>
2116{
2117 using Base = std::iterator<std::random_access_iterator_tag, typename ArrayView::value_type>;
2118public:
2119 using typename Base::reference;
2120 using typename Base::pointer;
2121 using typename Base::difference_type;
2122 using typename Base::value_type;
2123private:
2124 template <typename ValueType, typename Bounds>
2125 friend class basic_array_view;
2126 const ArrayView * m_container;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07002127 typename ArrayView::bounds_type::iterator m_itr;
Anna Gringauzea4654a42015-10-16 12:15:22 -07002128 general_array_view_iterator(const ArrayView *container, bool isbegin) :
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002129 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
2130 {
2131 }
2132public:
Anna Gringauzea4654a42015-10-16 12:15:22 -07002133 reference operator*() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002134 {
2135 return (*m_container)[*m_itr];
2136 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07002137 pointer operator->() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002138 {
2139 return &(*m_container)[*m_itr];
2140 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002141 general_array_view_iterator& operator++() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002142 {
2143 ++m_itr;
2144 return *this;
2145 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002146 general_array_view_iterator operator++(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002147 {
2148 auto ret = *this;
2149 ++(*this);
2150 return ret;
2151 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002152 general_array_view_iterator& operator--() noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002153 {
2154 --m_itr;
2155 return *this;
2156 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002157 general_array_view_iterator operator--(int)noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002158 {
2159 auto ret = *this;
2160 --(*this);
2161 return ret;
2162 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002163 general_array_view_iterator operator+(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002164 {
2165 general_array_view_iterator ret{ *this };
2166 return ret += n;
2167 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002168 general_array_view_iterator& operator+=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002169 {
2170 m_itr += n;
2171 return *this;
2172 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002173 general_array_view_iterator operator-(difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002174 {
2175 general_array_view_iterator ret{ *this };
2176 return ret -= n;
2177 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002178 general_array_view_iterator& operator-=(difference_type n) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002179 {
2180 return *this += -n;
2181 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002182 difference_type operator-(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002183 {
2184 fail_fast_assert(m_container == rhs.m_container);
2185 return m_itr - rhs.m_itr;
2186 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002187 value_type operator[](difference_type n) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002188 {
2189 return (*m_container)[m_itr[n]];;
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 fail_fast_assert(m_container == rhs.m_container);
2194 return m_itr == rhs.m_itr;
2195 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002196 bool operator !=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002197 {
2198 return !(*this == rhs);
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 fail_fast_assert(m_container == rhs.m_container);
2203 return m_itr < rhs.m_itr;
2204 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002205 bool operator<=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002206 {
2207 return !(rhs < *this);
2208 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002209 bool operator>(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002210 {
2211 return rhs < *this;
2212 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002213 bool operator>=(const general_array_view_iterator& rhs) const noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002214 {
2215 return !(rhs > *this);
2216 }
Neil MacIntoshd5316802015-09-30 21:54:08 -07002217 void swap(general_array_view_iterator& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002218 {
2219 std::swap(m_itr, rhs.m_itr);
2220 std::swap(m_container, rhs.m_container);
2221 }
2222};
2223
2224template <typename ArrayView>
Neil MacIntoshd5316802015-09-30 21:54:08 -07002225general_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 -07002226{
2227 return rhs + n;
2228}
2229
Neil MacIntoshef626fd2015-09-29 16:41:37 -07002230} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002231
Neil MacIntoshd5316802015-09-30 21:54:08 -07002232#ifdef _MSC_VER
2233
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002234#undef constexpr
2235#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002236
Neil MacIntoshd5316802015-09-30 21:54:08 -07002237#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002238#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07002239
2240#ifndef GSL_THROWS_FOR_TESTING
2241#pragma undef noexcept
2242#endif // GSL_THROWS_FOR_TESTING
2243
Neil MacIntosh9a297122015-09-14 15:11:07 -07002244#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002245
Neil MacIntoshd5316802015-09-30 21:54:08 -07002246#endif // _MSC_VER
2247
2248#if defined(GSL_THROWS_FOR_TESTING)
2249#undef noexcept
2250#endif // GSL_THROWS_FOR_TESTING
2251
Treb Connell51da1362015-09-24 18:08:34 -07002252
2253#endif // GSL_ARRAY_VIEW_H