blob: cbc766bddaadf2023ed9950a405febc110c38e82 [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
Neil MacIntoshb63ec942015-11-04 12:42:27 -080019#ifndef GSL_SPAN_H
20#define GSL_SPAN_H
Treb Connell51da1362015-09-24 18:08:34 -070021
Olaf van der Spek550361c2015-11-12 10:23:56 +010022#include <algorithm>
23#include <array>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070024#include <cstddef>
25#include <cstdint>
Olaf van der Spek550361c2015-11-12 10:23:56 +010026#include <functional>
27#include <iterator>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070028#include <limits>
Olaf van der Spek550361c2015-11-12 10:23:56 +010029#include <new>
Anna Gringauze2cdedda2015-10-15 13:19:24 -070030#include <numeric>
Olaf van der Spek550361c2015-11-12 10:23:56 +010031#include <stdexcept>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070032#include <type_traits>
33#include <utility>
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
Neil MacIntoshe9a96022015-11-03 18:56:55 -080046#pragma push_macro("GSL_MSVC_HAS_VARIADIC_CTOR_BUG")
47#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
48
49
Neil MacIntoshd5316802015-09-30 21:54:08 -070050// noexcept is not understood
51#ifndef GSL_THROWS_FOR_TESTING
52#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070053#endif
54
Neil MacIntoshd5316802015-09-30 21:54:08 -070055// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070056#pragma warning(push)
57#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
Neil MacIntosha998a9b2015-11-12 18:57:23 -080058#pragma warning(disable: 4512) // warns that assignment op could not be generated
Neil MacIntoshd5316802015-09-30 21:54:08 -070059
Neil MacIntosh9a297122015-09-14 15:11:07 -070060#endif // _MSC_VER <= 1800
61
Neil MacIntoshd5316802015-09-30 21:54:08 -070062#endif // _MSC_VER
63
64// In order to test the library, we need it to throw exceptions that we can catch
65#ifdef GSL_THROWS_FOR_TESTING
66#define noexcept /* nothing */
67#endif // GSL_THROWS_FOR_TESTING
68
69
Neil MacIntoshef626fd2015-09-29 16:41:37 -070070namespace gsl {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070071
72/*
73** begin definitions of index and bounds
74*/
75namespace details
76{
Neil MacIntosh68064d62015-11-03 19:17:11 -080077 template <typename SizeType>
78 struct SizeTypeTraits
79 {
80 static const SizeType max_value = std::numeric_limits<SizeType>::max();
81 };
Anna Gringauze1c208b32015-10-16 17:40:57 -070082
83
Neil MacIntosh68064d62015-11-03 19:17:11 -080084 template<typename... Ts>
85 class are_integral : public std::integral_constant<bool, true> {};
Anna Gringauze1c208b32015-10-16 17:40:57 -070086
Neil MacIntosh68064d62015-11-03 19:17:11 -080087 template<typename T, typename... Ts>
88 class are_integral<T, Ts...> : public std::integral_constant<bool, std::is_integral<T>::value && are_integral<Ts...>::value> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070089}
90
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070091template <size_t Rank>
Anna Gringauzedb384972015-10-05 12:34:23 -070092class index final
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070093{
Neil MacIntosh68064d62015-11-03 19:17:11 -080094 static_assert(Rank > 0, "Rank must be greater than 0!");
Anna Gringauzedb384972015-10-05 12:34:23 -070095
Neil MacIntosh68064d62015-11-03 19:17:11 -080096 template <size_t OtherRank>
97 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -070098
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070099public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800100 static const size_t rank = Rank;
101 using value_type = std::ptrdiff_t;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700102 using size_type = value_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800103 using reference = std::add_lvalue_reference_t<value_type>;
104 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700105
Neil MacIntosh68064d62015-11-03 19:17:11 -0800106 constexpr index() noexcept
107 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700108
Neil MacIntosh68064d62015-11-03 19:17:11 -0800109 constexpr index(const value_type(&values)[Rank]) noexcept
110 {
111 std::copy(values, values + Rank, elems);
112 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700113
Anna Gringauze8aa42482015-11-11 12:41:11 -0800114#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
115 template<typename T, typename... Ts,
116 typename = std::enable_if_t<((sizeof...(Ts) + 1) == Rank) &&
117 std::is_integral<T>::value &&
118 details::are_integral<Ts...>::value>>
119 constexpr index(T t, Ts... ds) : index({ static_cast<value_type>(t), static_cast<value_type>(ds)... })
120 {}
121#else
122 template<typename... Ts,
123 typename = std::enable_if_t<(sizeof...(Ts) == Rank) && details::are_integral<Ts...>::value>>
124 constexpr index(Ts... ds) noexcept : elems{ static_cast<value_type>(ds)... }
125 {}
126#endif
Anna Gringauzedb384972015-10-05 12:34:23 -0700127
Neil MacIntosh68064d62015-11-03 19:17:11 -0800128 constexpr index(const index& other) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700129
Neil MacIntosh68064d62015-11-03 19:17:11 -0800130 constexpr index& operator=(const index& rhs) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700131
Neil MacIntosh68064d62015-11-03 19:17:11 -0800132 // Preconditions: component_idx < rank
133 constexpr reference operator[](size_t component_idx)
134 {
135 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
136 return elems[component_idx];
137 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700138
Neil MacIntosh68064d62015-11-03 19:17:11 -0800139 // Preconditions: component_idx < rank
140 constexpr const_reference operator[](size_t component_idx) const noexcept
141 {
142 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
143 return elems[component_idx];
144 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700145
Neil MacIntosh68064d62015-11-03 19:17:11 -0800146 constexpr bool operator==(const index& rhs) const noexcept
147 {
148 return std::equal(elems, elems + rank, rhs.elems);
149 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700150
Neil MacIntosh68064d62015-11-03 19:17:11 -0800151 constexpr bool operator!=(const index& rhs) const noexcept
152 {
153 return !(this == rhs);
154 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700155
Neil MacIntosh68064d62015-11-03 19:17:11 -0800156 constexpr index operator+() const noexcept
157 {
158 return *this;
159 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700160
Neil MacIntosh68064d62015-11-03 19:17:11 -0800161 constexpr index operator-() const noexcept
162 {
163 index ret = *this;
164 std::transform(ret, ret + rank, ret, std::negate<value_type>{});
165 return ret;
166 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700167
Neil MacIntosh68064d62015-11-03 19:17:11 -0800168 constexpr index operator+(const index& rhs) const noexcept
169 {
170 index ret = *this;
171 ret += rhs;
172 return ret;
173 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700174
Neil MacIntosh68064d62015-11-03 19:17:11 -0800175 constexpr index operator-(const index& rhs) const noexcept
176 {
177 index ret = *this;
178 ret -= rhs;
179 return ret;
180 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700181
Neil MacIntosh68064d62015-11-03 19:17:11 -0800182 constexpr index& operator+=(const index& rhs) noexcept
183 {
184 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<value_type>{});
185 return *this;
186 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700187
Neil MacIntosh68064d62015-11-03 19:17:11 -0800188 constexpr index& operator-=(const index& rhs) noexcept
189 {
190 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<value_type>{});
191 return *this;
192 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700193
Neil MacIntosh68064d62015-11-03 19:17:11 -0800194 constexpr index operator*(value_type v) const noexcept
195 {
196 index ret = *this;
197 ret *= v;
198 return ret;
199 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700200
Neil MacIntosh68064d62015-11-03 19:17:11 -0800201 constexpr index operator/(value_type v) const noexcept
202 {
203 index ret = *this;
204 ret /= v;
205 return ret;
206 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700207
Neil MacIntosh68064d62015-11-03 19:17:11 -0800208 friend constexpr index operator*(value_type v, const index& rhs) noexcept
209 {
210 return rhs * v;
211 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700212
Neil MacIntosh68064d62015-11-03 19:17:11 -0800213 constexpr index& operator*=(value_type v) noexcept
214 {
215 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies<value_type>{}(x, v); });
216 return *this;
217 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700218
Neil MacIntosh68064d62015-11-03 19:17:11 -0800219 constexpr index& operator/=(value_type v) noexcept
220 {
221 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<value_type>{}(x, v); });
222 return *this;
223 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700224
Anna Gringauzedb384972015-10-05 12:34:23 -0700225private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800226 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700227};
228
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700229#ifndef _MSC_VER
230
231struct static_bounds_dynamic_range_t
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700232{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800233 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
234 constexpr operator T() const noexcept
235 {
236 return static_cast<T>(-1);
237 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700238
Neil MacIntosh68064d62015-11-03 19:17:11 -0800239 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
240 constexpr bool operator ==(T other) const noexcept
241 {
242 return static_cast<T>(-1) == other;
243 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700244
Neil MacIntosh68064d62015-11-03 19:17:11 -0800245 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
246 constexpr bool operator !=(T other) const noexcept
247 {
248 return static_cast<T>(-1) != other;
249 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700250
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700251};
252
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700253template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
254constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
255{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800256 return right == left;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700257}
258
259template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
260constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
261{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800262 return right != left;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700263}
264
265constexpr static_bounds_dynamic_range_t dynamic_range{};
266#else
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700267const std::ptrdiff_t dynamic_range = -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700268#endif
269
270struct generalized_mapping_tag {};
271struct contiguous_mapping_tag : generalized_mapping_tag {};
272
273namespace details
274{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700275
Neil MacIntosh68064d62015-11-03 19:17:11 -0800276 template <std::ptrdiff_t Left, std::ptrdiff_t Right>
277 struct LessThan
278 {
279 static const bool value = Left < Right;
280 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700281
Neil MacIntosh68064d62015-11-03 19:17:11 -0800282 template <std::ptrdiff_t... Ranges>
283 struct BoundsRanges {
284 using size_type = std::ptrdiff_t;
285 static const size_type Depth = 0;
286 static const size_type DynamicNum = 0;
287 static const size_type CurrentRange = 1;
288 static const size_type TotalSize = 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700289
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700290 // TODO : following signature is for work around VS bug
291 template <typename OtherRange>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800292 BoundsRanges(const OtherRange&, bool /* firstLevel */)
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700293 {}
Neil MacIntosh68064d62015-11-03 19:17:11 -0800294
295 BoundsRanges (const BoundsRanges&) = default;
Vladislav Yaroslavlev995cfdf2015-11-12 10:46:21 +0300296 BoundsRanges& operator=(const BoundsRanges&) = default;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800297 BoundsRanges(const std::ptrdiff_t* const) { }
298 BoundsRanges() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700299
300
Neil MacIntosh68064d62015-11-03 19:17:11 -0800301 template <typename T, size_t Dim>
302 void serialize(T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700303 {}
304
Neil MacIntosh68064d62015-11-03 19:17:11 -0800305 template <typename T, size_t Dim>
306 size_type linearize(const T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700307 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800308 return 0;
309 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700310
Neil MacIntosh68064d62015-11-03 19:17:11 -0800311 template <typename T, size_t Dim>
312 bool contains(const T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700313 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800314 return 0;
315 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700316
Neil MacIntosh68064d62015-11-03 19:17:11 -0800317 size_type totalSize() const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700318 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800319 return TotalSize;
320 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700321
Neil MacIntosh68064d62015-11-03 19:17:11 -0800322 bool operator==(const BoundsRanges&) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700323 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800324 return true;
325 }
326 };
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700327
Neil MacIntosh68064d62015-11-03 19:17:11 -0800328 template <std::ptrdiff_t... RestRanges>
329 struct BoundsRanges <dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>{
330 using Base = BoundsRanges <RestRanges... >;
331 using size_type = std::ptrdiff_t;
332 static const size_t Depth = Base::Depth + 1;
333 static const size_t DynamicNum = Base::DynamicNum + 1;
334 static const size_type CurrentRange = dynamic_range;
335 static const size_type TotalSize = dynamic_range;
336 const size_type m_bound;
337
338 BoundsRanges (const BoundsRanges&) = default;
339
340 BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
341 {
342 fail_fast_assert(0 <= *arr);
343 }
344
345 BoundsRanges() : m_bound(0) {}
346
347 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
348 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other, bool /* firstLevel */ = true) :
349 Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false), m_bound(other.totalSize())
350 {}
351
352 template <typename T, size_t Dim = 0>
353 void serialize(T& arr) const
354 {
355 arr[Dim] = elementNum();
356 this->Base::template serialize<T, Dim + 1>(arr);
357 }
358
359 template <typename T, size_t Dim = 0>
360 size_type linearize(const T& arr) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700361 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800362 const size_type index = this->Base::totalSize() * arr[Dim];
363 fail_fast_assert(index < m_bound);
364 return index + this->Base::template linearize<T, Dim + 1>(arr);
365 }
366
367 template <typename T, size_t Dim = 0>
368 size_type contains(const T & arr) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700369 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800370 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
371 if (last == -1)
372 return -1;
373 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
374 return cur < m_bound ? cur + last : -1;
375 }
376
377 size_type totalSize() const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700378 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800379 return m_bound;
380 }
381
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700382 size_type elementNum() const noexcept
383 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800384 return totalSize() / this->Base::totalSize();
385 }
386
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700387 size_type elementNum(size_t dim) const noexcept
388 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800389 if (dim > 0)
390 return this->Base::elementNum(dim - 1);
391 else
392 return elementNum();
393 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700394
Neil MacIntosh68064d62015-11-03 19:17:11 -0800395 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700396 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800397 return m_bound == rhs.m_bound && static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
398 }
399 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700400
Neil MacIntosh68064d62015-11-03 19:17:11 -0800401 template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
402 struct BoundsRanges <CurRange, RestRanges...> : BoundsRanges<RestRanges...>
403 {
404 using Base = BoundsRanges <RestRanges... >;
405 using size_type = std::ptrdiff_t;
406 static const size_t Depth = Base::Depth + 1;
407 static const size_t DynamicNum = Base::DynamicNum;
408 static const size_type CurrentRange = CurRange;
409 static const size_type TotalSize = Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize;
410
411 BoundsRanges (const BoundsRanges&) = default;
412 BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) { }
413 BoundsRanges() = default;
414
415 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
416 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>&other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
417 {
418 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
419 }
420
421 template <typename T, size_t Dim = 0>
422 void serialize(T& arr) const
423 {
424 arr[Dim] = elementNum();
425 this->Base::template serialize<T, Dim + 1>(arr);
426 }
427
428 template <typename T, size_t Dim = 0>
429 size_type linearize(const T& arr) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700430 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800431 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
432 return this->Base::totalSize() * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
433 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700434
Neil MacIntosh68064d62015-11-03 19:17:11 -0800435 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700436 size_type contains(const T& arr) const
437 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800438 if (arr[Dim] >= CurrentRange)
439 return -1;
440 const size_type last = this->Base::template contains<T, Dim + 1>(arr);
441 if (last == -1)
442 return -1;
443 return this->Base::totalSize() * arr[Dim] + last;
444 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700445
Neil MacIntosh68064d62015-11-03 19:17:11 -0800446 size_type totalSize() const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700447 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800448 return CurrentRange * this->Base::totalSize();
449 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700450
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700451 size_type elementNum() const noexcept
452 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800453 return CurrentRange;
454 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700455
Neil MacIntosh68064d62015-11-03 19:17:11 -0800456 size_type elementNum(size_t dim) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700457 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800458 if (dim > 0)
459 return this->Base::elementNum(dim - 1);
460 else
461 return elementNum();
462 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700463
Neil MacIntosh68064d62015-11-03 19:17:11 -0800464 bool operator== (const BoundsRanges& rhs) const noexcept
465 {
466 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
467 }
468 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700469
Neil MacIntosh68064d62015-11-03 19:17:11 -0800470 template <typename SourceType, typename TargetType, size_t Rank>
471 struct BoundsRangeConvertible2;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700472
Neil MacIntosh68064d62015-11-03 19:17:11 -0800473 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
474 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700475
Neil MacIntosh68064d62015-11-03 19:17:11 -0800476 template <size_t Rank, typename SourceType, typename TargetType>
477 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
478
479 template <typename SourceType, typename TargetType, size_t Rank>
480 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
481 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
482 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
483 {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700484
Neil MacIntosh68064d62015-11-03 19:17:11 -0800485 template <typename SourceType, typename TargetType>
486 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700487
Neil MacIntosh68064d62015-11-03 19:17:11 -0800488 template <typename SourceType, typename TargetType, std::ptrdiff_t Rank = TargetType::Depth>
489 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
490 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
491 && (!LessThan<SourceType::CurrentRange, TargetType::CurrentRange>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
492 {};
493 template <typename SourceType, typename TargetType>
494 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700495
Neil MacIntosh68064d62015-11-03 19:17:11 -0800496 template <typename TypeChain>
497 struct TypeListIndexer
498 {
499 const TypeChain & obj;
500 TypeListIndexer(const TypeChain & obj) :obj(obj){}
501 template<size_t N>
502 const TypeChain & getObj(std::true_type)
503 {
504 return obj;
505 }
506 template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
507 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
508 {
509 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
510 }
511 template <size_t N>
512 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
513 {
514 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
515 }
516 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700517
Neil MacIntosh68064d62015-11-03 19:17:11 -0800518 template <typename TypeChain>
519 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
520 {
521 return TypeListIndexer<TypeChain>(obj);
522 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700523
Neil MacIntosh68064d62015-11-03 19:17:11 -0800524 template <size_t Rank, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1>>>
525 constexpr Ret shift_left(const index<Rank>& other) noexcept
526 {
527 Ret ret{};
528 for (size_t i = 0; i < Rank - 1; ++i)
529 {
530 ret[i] = other[i + 1];
531 }
532 return ret;
533 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700534}
535
536template <typename IndexType>
537class bounds_iterator;
538
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700539template <std::ptrdiff_t... Ranges>
540class static_bounds
541{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700542public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800543 static_bounds(const details::BoundsRanges<Ranges...>&) {
544 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700545};
546
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700547template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
548class static_bounds<FirstRange, RestRanges...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700549{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800550 using MyRanges = details::BoundsRanges<FirstRange, RestRanges... >;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700551
Neil MacIntosh68064d62015-11-03 19:17:11 -0800552 MyRanges m_ranges;
553 constexpr static_bounds(const MyRanges& range) : m_ranges(range)
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700554 {}
Neil MacIntosh68064d62015-11-03 19:17:11 -0800555
556 template <std::ptrdiff_t... OtherRanges>
557 friend class static_bounds;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700558
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700559public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800560 static const size_t rank = MyRanges::Depth;
561 static const size_t dynamic_rank = MyRanges::DynamicNum;
562 static const std::ptrdiff_t static_size = MyRanges::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700563
Neil MacIntosh68064d62015-11-03 19:17:11 -0800564 using size_type = std::ptrdiff_t;
565 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700566 using const_index_type = std::add_const_t<index_type>;
567 using iterator = bounds_iterator<const_index_type>;
568 using const_iterator = bounds_iterator<const_index_type>;
569 using difference_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800570 using sliced_type = static_bounds<RestRanges...>;
571 using mapping_type = contiguous_mapping_tag;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700572
Neil MacIntosh68064d62015-11-03 19:17:11 -0800573 constexpr static_bounds(const static_bounds&) = default;
574
575 template <std::ptrdiff_t... Ranges, typename Dummy = std::enable_if_t<
576 details::BoundsRangeConvertible<details::BoundsRanges<Ranges...>, details::BoundsRanges <FirstRange, RestRanges... >>::value>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700577 constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
578 {}
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700579
Neil MacIntosh68064d62015-11-03 19:17:11 -0800580 constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges((const std::ptrdiff_t*)il.begin())
581 {
582 fail_fast_assert((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
583 fail_fast_assert(m_ranges.totalSize() <= PTRDIFF_MAX, "Size of the range is larger than the max element of the size type");
584 }
585
586 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700587
Neil MacIntosh68064d62015-11-03 19:17:11 -0800588 constexpr static_bounds& operator=(const static_bounds& otherBounds)
589 {
590 new(&m_ranges) MyRanges (otherBounds.m_ranges);
591 return *this;
592 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700593
Neil MacIntosh68064d62015-11-03 19:17:11 -0800594 constexpr sliced_type slice() const noexcept
595 {
596 return sliced_type{static_cast<const details::BoundsRanges<RestRanges...> &>(m_ranges)};
597 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700598
Neil MacIntosh68064d62015-11-03 19:17:11 -0800599 constexpr size_type stride() const noexcept
600 {
601 return rank > 1 ? slice().size() : 1;
602 }
603
604 constexpr size_type size() const noexcept
605 {
606 return m_ranges.totalSize();
607 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700608
Neil MacIntosh68064d62015-11-03 19:17:11 -0800609 constexpr size_type total_size() const noexcept
610 {
611 return m_ranges.totalSize();
612 }
613
614 constexpr size_type linearize(const index_type & idx) const
615 {
616 return m_ranges.linearize(idx);
617 }
618
619 constexpr bool contains(const index_type& idx) const noexcept
620 {
621 return m_ranges.contains(idx) != -1;
622 }
623
624 constexpr size_type operator[](size_t index) const noexcept
625 {
626 return m_ranges.elementNum(index);
627 }
628
629 template <size_t Dim = 0>
630 constexpr size_type extent() const noexcept
631 {
632 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
633 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
634 }
635
636 constexpr index_type index_bounds() const noexcept
637 {
638 size_type extents[rank] = {};
639 m_ranges.serialize(extents);
640 return{ extents };
641 }
642
643 template <std::ptrdiff_t... Ranges>
644 constexpr bool operator == (const static_bounds<Ranges...>& rhs) const noexcept
645 {
646 return this->size() == rhs.size();
647 }
648
649 template <std::ptrdiff_t... Ranges>
650 constexpr bool operator != (const static_bounds<Ranges...>& rhs) const noexcept
651 {
652 return !(*this == rhs);
653 }
654
655 constexpr const_iterator begin() const noexcept
656 {
657 return const_iterator(*this, index_type{});
658 }
659
660 constexpr const_iterator end() const noexcept
661 {
662 return const_iterator(*this, this->index_bounds());
663 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700664};
665
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700666template <size_t Rank>
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700667class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700668{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800669 template <size_t OtherRank>
670 friend class strided_bounds;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700671
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700672public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800673 static const size_t rank = Rank;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700674 using value_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800675 using reference = std::add_lvalue_reference_t<value_type>;
676 using const_reference = std::add_const_t<reference>;
677 using size_type = value_type;
678 using difference_type = value_type;
679 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700680 using const_index_type = std::add_const_t<index_type>;
681 using iterator = bounds_iterator<const_index_type>;
682 using const_iterator = bounds_iterator<const_index_type>;
683 static const value_type dynamic_rank = rank;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800684 static const value_type static_size = dynamic_range;
685 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
686 using mapping_type = generalized_mapping_tag;
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700687
Neil MacIntosh68064d62015-11-03 19:17:11 -0800688 constexpr strided_bounds(const strided_bounds &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700689
Vladislav Yaroslavlev557e6692015-11-12 10:44:41 +0300690 constexpr strided_bounds & operator=(const strided_bounds &) noexcept = default;
691
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700692 constexpr strided_bounds(const value_type(&values)[rank], index_type strides)
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700693 : m_extents(values), m_strides(std::move(strides))
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700694 {}
695
Neil MacIntosh68064d62015-11-03 19:17:11 -0800696 constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept
697 : m_extents(extents), m_strides(strides)
698 {}
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700699
Neil MacIntosh68064d62015-11-03 19:17:11 -0800700 constexpr index_type strides() const noexcept
701 {
702 return m_strides;
703 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700704
Neil MacIntosh68064d62015-11-03 19:17:11 -0800705 constexpr size_type total_size() const noexcept
706 {
707 size_type ret = 0;
708 for (size_t i = 0; i < rank; ++i)
709 {
710 ret += (m_extents[i] - 1) * m_strides[i];
711 }
712 return ret + 1;
713 }
714
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700715 constexpr size_type size() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800716 {
717 size_type ret = 1;
718 for (size_t i = 0; i < rank; ++i)
719 {
720 ret *= m_extents[i];
721 }
722 return ret;
723 }
724
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700725 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800726 {
727 for (size_t i = 0; i < rank; ++i)
728 {
729 if (idx[i] < 0 || idx[i] >= m_extents[i])
730 return false;
731 }
732 return true;
733 }
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700734
Neil MacIntosh68064d62015-11-03 19:17:11 -0800735 constexpr size_type linearize(const index_type& idx) const noexcept
736 {
737 size_type ret = 0;
738 for (size_t i = 0; i < rank; i++)
739 {
740 fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
741 ret += idx[i] * m_strides[i];
742 }
743 return ret;
744 }
745
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700746 constexpr size_type stride() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800747 {
748 return m_strides[0];
749 }
750
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700751 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800752 constexpr sliced_type slice() const
753 {
754 return{ details::shift_left(m_extents), details::shift_left(m_strides) };
755 }
756
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700757 template <size_t Dim = 0>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800758 constexpr size_type extent() const noexcept
759 {
760 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
761 return m_extents[Dim];
762 }
763
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700764 constexpr index_type index_bounds() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800765 {
766 return m_extents;
767 }
768 constexpr const_iterator begin() const noexcept
769 {
770 return const_iterator{ *this, index_type{} };
771 }
772
773 constexpr const_iterator end() const noexcept
774 {
775 return const_iterator{ *this, index_bounds() };
776 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700777
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700778private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800779 index_type m_extents;
780 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700781};
782
783template <typename T>
784struct is_bounds : std::integral_constant<bool, false> {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700785template <std::ptrdiff_t... Ranges>
786struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true> {};
787template <size_t Rank>
788struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700789
790template <typename IndexType>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700791class bounds_iterator: public std::iterator<std::random_access_iterator_tag, IndexType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700792{
793private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800794 using Base = std::iterator <std::random_access_iterator_tag, IndexType>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700795
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700796public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800797 static const size_t rank = IndexType::rank;
798 using typename Base::reference;
799 using typename Base::pointer;
800 using typename Base::difference_type;
801 using typename Base::value_type;
802 using index_type = value_type;
803 using index_size_type = typename IndexType::value_type;
804 template <typename Bounds>
805 explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
806 : boundary(bnd.index_bounds()), curr(std::move(curr))
807 {
808 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
809 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700810
Neil MacIntosh68064d62015-11-03 19:17:11 -0800811 constexpr reference operator*() const noexcept
812 {
813 return curr;
814 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700815
Neil MacIntosh68064d62015-11-03 19:17:11 -0800816 constexpr pointer operator->() const noexcept
817 {
818 return &curr;
819 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700820
Neil MacIntosh68064d62015-11-03 19:17:11 -0800821 constexpr bounds_iterator& operator++() noexcept
822 {
823 for (size_t i = rank; i-- > 0;)
824 {
825 if (curr[i] < boundary[i] - 1)
826 {
827 curr[i]++;
828 return *this;
829 }
830 curr[i] = 0;
831 }
832 // If we're here we've wrapped over - set to past-the-end.
833 curr = boundary;
834 return *this;
835 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700836
Neil MacIntosh68064d62015-11-03 19:17:11 -0800837 constexpr bounds_iterator operator++(int) noexcept
838 {
839 auto ret = *this;
840 ++(*this);
841 return ret;
842 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700843
Neil MacIntosh68064d62015-11-03 19:17:11 -0800844 constexpr bounds_iterator& operator--() noexcept
845 {
846 if (!less(curr, boundary))
847 {
848 // if at the past-the-end, set to last element
849 for (size_t i = 0; i < rank; ++i)
850 {
851 curr[i] = boundary[i] - 1;
852 }
853 return *this;
854 }
855 for (size_t i = rank; i-- > 0;)
856 {
857 if (curr[i] >= 1)
858 {
859 curr[i]--;
860 return *this;
861 }
862 curr[i] = boundary[i] - 1;
863 }
864 // If we're here the preconditions were violated
865 // "pre: there exists s such that r == ++s"
866 fail_fast_assert(false);
867 return *this;
868 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700869
Neil MacIntosh68064d62015-11-03 19:17:11 -0800870 constexpr bounds_iterator operator--(int) noexcept
871 {
872 auto ret = *this;
873 --(*this);
874 return ret;
875 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700876
Neil MacIntosh68064d62015-11-03 19:17:11 -0800877 constexpr bounds_iterator operator+(difference_type n) const noexcept
878 {
879 bounds_iterator ret{ *this };
880 return ret += n;
881 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700882
Neil MacIntosh68064d62015-11-03 19:17:11 -0800883 constexpr bounds_iterator& operator+=(difference_type n) noexcept
884 {
885 auto linear_idx = linearize(curr) + n;
886 std::remove_const_t<value_type> stride = 0;
887 stride[rank - 1] = 1;
888 for (size_t i = rank - 1; i-- > 0;)
889 {
890 stride[i] = stride[i + 1] * boundary[i + 1];
891 }
892 for (size_t i = 0; i < rank; ++i)
893 {
894 curr[i] = linear_idx / stride[i];
895 linear_idx = linear_idx % stride[i];
896 }
897 fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "index is out of bounds of the array");
898 return *this;
899 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700900
Neil MacIntosh68064d62015-11-03 19:17:11 -0800901 constexpr bounds_iterator operator-(difference_type n) const noexcept
902 {
903 bounds_iterator ret{ *this };
904 return ret -= n;
905 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700906
Neil MacIntosh68064d62015-11-03 19:17:11 -0800907 constexpr bounds_iterator& operator-=(difference_type n) noexcept
908 {
909 return *this += -n;
910 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700911
Neil MacIntosh68064d62015-11-03 19:17:11 -0800912 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
913 {
914 return linearize(curr) - linearize(rhs.curr);
915 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700916
Neil MacIntosh68064d62015-11-03 19:17:11 -0800917 constexpr value_type operator[](difference_type n) const noexcept
918 {
919 return *(*this + n);
920 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700921
Neil MacIntosh68064d62015-11-03 19:17:11 -0800922 constexpr bool operator==(const bounds_iterator& rhs) const noexcept
923 {
924 return curr == rhs.curr;
925 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700926
Neil MacIntosh68064d62015-11-03 19:17:11 -0800927 constexpr bool operator!=(const bounds_iterator& rhs) const noexcept
928 {
929 return !(*this == rhs);
930 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700931
Neil MacIntosh68064d62015-11-03 19:17:11 -0800932 constexpr bool operator<(const bounds_iterator& rhs) const noexcept
933 {
934 return less(curr, rhs.curr);
935 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700936
Neil MacIntosh68064d62015-11-03 19:17:11 -0800937 constexpr bool operator<=(const bounds_iterator& rhs) const noexcept
938 {
939 return !(rhs < *this);
940 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700941
Neil MacIntosh68064d62015-11-03 19:17:11 -0800942 constexpr bool operator>(const bounds_iterator& rhs) const noexcept
943 {
944 return rhs < *this;
945 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700946
Neil MacIntosh68064d62015-11-03 19:17:11 -0800947 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept
948 {
949 return !(rhs > *this);
950 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700951
Neil MacIntosh68064d62015-11-03 19:17:11 -0800952 void swap(bounds_iterator& rhs) noexcept
953 {
954 std::swap(boundary, rhs.boundary);
955 std::swap(curr, rhs.curr);
956 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700957private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800958 constexpr bool less(index_type& one, index_type& other) const noexcept
959 {
960 for (size_t i = 0; i < rank; ++i)
961 {
962 if (one[i] < other[i])
963 return true;
964 }
965 return false;
966 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700967
Neil MacIntosh68064d62015-11-03 19:17:11 -0800968 constexpr index_size_type linearize(const value_type& idx) const noexcept
969 {
970 // TODO: Smarter impl.
971 // Check if past-the-end
972 index_size_type multiplier = 1;
973 index_size_type res = 0;
974 if (!less(idx, boundary))
975 {
976 res = 1;
977 for (size_t i = rank; i-- > 0;)
978 {
979 res += (idx[i] - 1) * multiplier;
980 multiplier *= boundary[i];
981 }
982 }
983 else
984 {
985 for (size_t i = rank; i-- > 0;)
986 {
987 res += idx[i] * multiplier;
988 multiplier *= boundary[i];
989 }
990 }
991 return res;
992 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700993
Neil MacIntosh68064d62015-11-03 19:17:11 -0800994 value_type boundary;
995 std::remove_const_t<value_type> curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700996};
997
998template <typename IndexType>
Neil MacIntoshd5316802015-09-30 21:54:08 -0700999bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001000{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001001 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001002}
1003
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001004//
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001005// begin definitions of basic_span
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001006//
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001007namespace details
1008{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001009 template <typename Bounds>
1010 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
1011 {
1012 return bnd.strides();
1013 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001014
Neil MacIntosh68064d62015-11-03 19:17:11 -08001015 // Make a stride vector from bounds, assuming contiguous memory.
1016 template <typename Bounds>
1017 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
1018 {
1019 auto extents = bnd.index_bounds();
1020 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001021
Neil MacIntosh68064d62015-11-03 19:17:11 -08001022 stride[Bounds::rank - 1] = 1;
1023 for (size_t i = 1; i < Bounds::rank; ++i)
1024 {
1025 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
1026 }
1027 return{ stride };
1028 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001029
Neil MacIntosh68064d62015-11-03 19:17:11 -08001030 template <typename BoundsSrc, typename BoundsDest>
1031 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1032 {
1033 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1034 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1035 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");
1036 fail_fast_assert(src.size() == dest.size());
1037 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001038
1039
1040} // namespace details
1041
Anna Gringauze8aa42482015-11-11 12:41:11 -08001042template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001043class contiguous_span_iterator;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001044template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001045class general_span_iterator;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001046enum class byte : std::uint8_t {};
1047
1048template <typename ValueType, typename BoundsType>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001049class basic_span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001050{
1051public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001052 static const size_t rank = BoundsType::rank;
1053 using bounds_type = BoundsType;
1054 using size_type = typename bounds_type::size_type;
1055 using index_type = typename bounds_type::index_type;
1056 using value_type = ValueType;
1057 using const_value_type = std::add_const_t<value_type>;
1058 using pointer = ValueType*;
1059 using reference = ValueType&;
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001060 using iterator = std::conditional_t<std::is_same<typename BoundsType::mapping_type, contiguous_mapping_tag>::value, contiguous_span_iterator<basic_span>, general_span_iterator<basic_span>>;
1061 using const_iterator = std::conditional_t<std::is_same<typename BoundsType::mapping_type, contiguous_mapping_tag>::value, contiguous_span_iterator<basic_span<const_value_type, BoundsType>>, general_span_iterator<basic_span<const_value_type, BoundsType>>>;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001062 using reverse_iterator = std::reverse_iterator<iterator>;
1063 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001064 using sliced_type = std::conditional_t<rank == 1, value_type, basic_span<value_type, typename BoundsType::sliced_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001065
1066private:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001067 pointer m_pdata;
1068 bounds_type m_bounds;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001069
1070public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001071 constexpr bounds_type bounds() const noexcept
1072 {
1073 return m_bounds;
1074 }
1075 template <size_t Dim = 0>
1076 constexpr size_type extent() const noexcept
1077 {
1078 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
1079 return m_bounds.template extent<Dim>();
1080 }
1081 constexpr size_type size() const noexcept
1082 {
1083 return m_bounds.size();
1084 }
1085 constexpr reference operator[](const index_type& idx) const
1086 {
1087 return m_pdata[m_bounds.linearize(idx)];
1088 }
1089 constexpr pointer data() const noexcept
1090 {
1091 return m_pdata;
1092 }
1093 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
1094 constexpr Ret operator[](size_type idx) const
1095 {
1096 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
1097 const size_type ridx = idx * m_bounds.stride();
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001098
Neil MacIntosh68064d62015-11-03 19:17:11 -08001099 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
1100 return Ret {m_pdata + ridx, m_bounds.slice()};
1101 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001102
Neil MacIntosh68064d62015-11-03 19:17:11 -08001103 constexpr operator bool () const noexcept
1104 {
1105 return m_pdata != nullptr;
1106 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001107
Neil MacIntosh68064d62015-11-03 19:17:11 -08001108 constexpr iterator begin() const
1109 {
1110 return iterator {this, true};
1111 }
1112 constexpr iterator end() const
1113 {
1114 return iterator {this, false};
1115 }
1116 constexpr const_iterator cbegin() const
1117 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001118 return const_iterator {reinterpret_cast<const basic_span<const value_type, bounds_type> *>(this), true};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001119 }
1120 constexpr const_iterator cend() const
1121 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001122 return const_iterator {reinterpret_cast<const basic_span<const value_type, bounds_type> *>(this), false};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001123 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001124
Neil MacIntosh68064d62015-11-03 19:17:11 -08001125 constexpr reverse_iterator rbegin() const
1126 {
1127 return reverse_iterator {end()};
1128 }
1129 constexpr reverse_iterator rend() const
1130 {
1131 return reverse_iterator {begin()};
1132 }
1133 constexpr const_reverse_iterator crbegin() const
1134 {
1135 return const_reverse_iterator {cend()};
1136 }
1137 constexpr const_reverse_iterator crend() const
1138 {
1139 return const_reverse_iterator {cbegin()};
1140 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001141
Neil MacIntosh68064d62015-11-03 19:17:11 -08001142 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 MacIntoshb63ec942015-11-04 12:42:27 -08001143 constexpr bool operator== (const basic_span<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001144 {
1145 return m_bounds.size() == other.m_bounds.size() &&
1146 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
1147 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001148
Neil MacIntosh68064d62015-11-03 19:17:11 -08001149 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 MacIntoshb63ec942015-11-04 12:42:27 -08001150 constexpr bool operator!= (const basic_span<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001151 {
1152 return !(*this == other);
1153 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001154
Neil MacIntosh68064d62015-11-03 19:17:11 -08001155 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 MacIntoshb63ec942015-11-04 12:42:27 -08001156 constexpr bool operator< (const basic_span<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001157 {
1158 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1159 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001160
Neil MacIntosh68064d62015-11-03 19:17:11 -08001161 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 MacIntoshb63ec942015-11-04 12:42:27 -08001162 constexpr bool operator<= (const basic_span<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001163 {
1164 return !(other < *this);
1165 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001166
Neil MacIntosh68064d62015-11-03 19:17:11 -08001167 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 MacIntoshb63ec942015-11-04 12:42:27 -08001168 constexpr bool operator> (const basic_span<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001169 {
1170 return (other < *this);
1171 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001172
Neil MacIntosh68064d62015-11-03 19:17:11 -08001173 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 MacIntoshb63ec942015-11-04 12:42:27 -08001174 constexpr bool operator>= (const basic_span<OtherValueType, OtherBoundsType> & other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001175 {
1176 return !(*this < other);
1177 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001178
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001179public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001180 template <typename OtherValueType, typename OtherBounds,
1181 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value
1182 && std::is_convertible<OtherBounds, bounds_type>::value>>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001183 constexpr basic_span(const basic_span<OtherValueType, OtherBounds> & other ) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001184 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
1185 {
1186 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001187protected:
1188
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001189 constexpr basic_span(pointer data, bounds_type bound) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001190 : m_pdata(data)
1191 , m_bounds(std::move(bound))
1192 {
1193 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1194 }
1195 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001196 constexpr basic_span(T *data, std::enable_if_t<std::is_same<value_type, std::remove_all_extents_t<T>>::value, bounds_type> bound) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001197 : m_pdata(reinterpret_cast<pointer>(data))
1198 , m_bounds(std::move(bound))
1199 {
1200 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1201 }
1202 template <typename DestBounds>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001203 constexpr basic_span<value_type, DestBounds> as_span(const DestBounds &bounds)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001204 {
1205 details::verifyBoundsReshape(m_bounds, bounds);
1206 return {m_pdata, bounds};
1207 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001208private:
1209
Neil MacIntosh68064d62015-11-03 19:17:11 -08001210 friend iterator;
1211 friend const_iterator;
1212 template <typename ValueType2, typename BoundsType2>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001213 friend class basic_span;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001214};
1215
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001216template <std::ptrdiff_t DimSize = dynamic_range>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001217struct dim
1218{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001219 static const std::ptrdiff_t value = DimSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001220};
1221template <>
1222struct dim<dynamic_range>
1223{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001224 static const std::ptrdiff_t value = dynamic_range;
1225 const std::ptrdiff_t dvalue;
1226 dim(std::ptrdiff_t size) : dvalue(size) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001227};
1228
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001229template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range, std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001230class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001231
1232template <typename ValueType, size_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001233class strided_span;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001234
1235namespace details
1236{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001237 template <typename T, typename = std::true_type>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001238 struct SpanTypeTraits
Neil MacIntosh68064d62015-11-03 19:17:11 -08001239 {
1240 using value_type = T;
1241 using size_type = size_t;
1242 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001243
Neil MacIntosh68064d62015-11-03 19:17:11 -08001244 template <typename Traits>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001245 struct SpanTypeTraits<Traits, typename std::is_reference<typename Traits::span_traits &>::type>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001246 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001247 using value_type = typename Traits::span_traits::value_type;
1248 using size_type = typename Traits::span_traits::size_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001249 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001250
Neil MacIntosh68064d62015-11-03 19:17:11 -08001251 template <typename T, std::ptrdiff_t... Ranks>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001252 struct SpanArrayTraits {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001253 using type = span<T, Ranks...>;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001254 using value_type = T;
1255 using bounds_type = static_bounds<Ranks...>;
1256 using pointer = T*;
1257 using reference = T&;
1258 };
1259 template <typename T, std::ptrdiff_t N, std::ptrdiff_t... Ranks>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001260 struct SpanArrayTraits<T[N], Ranks...> : SpanArrayTraits<T, Ranks..., N> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001261
Neil MacIntosh68064d62015-11-03 19:17:11 -08001262 template <typename BoundsType>
1263 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
1264 {
1265 fail_fast_assert(totalSize <= PTRDIFF_MAX);
1266 return BoundsType{totalSize};
1267 }
1268 template <typename BoundsType>
1269 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
1270 {
1271 fail_fast_assert(BoundsType::static_size == totalSize);
1272 return {};
1273 }
1274 template <typename BoundsType>
1275 BoundsType newBoundsHelper(std::ptrdiff_t totalSize)
1276 {
1277 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1278 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1279 }
1280
1281 struct Sep{};
1282
1283 template <typename T, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001284 T static_as_span_helper(Sep, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001285 {
1286 return T{static_cast<typename T::size_type>(args)...};
1287 }
1288 template <typename T, typename Arg, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001289 std::enable_if_t<!std::is_same<Arg, dim<dynamic_range>>::value && !std::is_same<Arg, Sep>::value, T> static_as_span_helper(Arg, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001290 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001291 return static_as_span_helper<T>(args...);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001292 }
1293 template <typename T, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001294 T static_as_span_helper(dim<dynamic_range> val, Args ... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001295 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001296 return static_as_span_helper<T>(args..., val.dvalue);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001297 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001298
Neil MacIntosh68064d62015-11-03 19:17:11 -08001299 template <typename ...Dimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001300 struct static_as_span_static_bounds_helper
Neil MacIntosh68064d62015-11-03 19:17:11 -08001301 {
1302 using type = static_bounds<(Dimensions::value)...>;
1303 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001304
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001305 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001306 struct is_span_oracle : std::false_type
Neil MacIntosh68064d62015-11-03 19:17:11 -08001307 {};
1308
1309 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001310 struct is_span_oracle<span<ValueType, FirstDimension, RestDimensions...>> : std::true_type
Neil MacIntosh68064d62015-11-03 19:17:11 -08001311 {};
1312
1313 template <typename ValueType, std::ptrdiff_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001314 struct is_span_oracle<strided_span<ValueType, Rank>> : std::true_type
Neil MacIntosh68064d62015-11-03 19:17:11 -08001315 {};
1316
1317 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001318 struct is_span : is_span_oracle<std::remove_cv_t<T>>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001319 {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001320
1321}
1322
1323
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001324template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001325class span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001326{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001327 template <typename ValueType2, std::ptrdiff_t FirstDimension2, std::ptrdiff_t... RestDimensions2>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001328 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001329
Anna Gringauze8aa42482015-11-11 12:41:11 -08001330public:
1331 using BoundsType = static_bounds<FirstDimension, RestDimensions...>;
1332 static const size_t rank = BoundsType::rank;
1333 using bounds_type = BoundsType;
1334 using size_type = typename bounds_type::size_type;
1335 using index_type = typename bounds_type::index_type;
1336 using value_type = ValueType;
1337 using const_value_type = std::add_const_t<value_type>;
1338 using pointer = ValueType*;
1339 using reference = ValueType&;
1340 using iterator = contiguous_span_iterator<span>;
1341 using const_span = span<const_value_type, FirstDimension, RestDimensions...>;
1342 using const_iterator = contiguous_span_iterator<const_span>;
1343 using reverse_iterator = std::reverse_iterator<iterator>;
1344 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1345 using sliced_type = std::conditional_t<rank == 1, value_type, span<value_type, RestDimensions...>>;
1346
1347private:
1348 pointer m_pdata;
1349 bounds_type m_bounds;
1350
1351 friend iterator;
1352 friend const_iterator;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001353
1354public:
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001355
Anna Gringauze8aa42482015-11-11 12:41:11 -08001356 constexpr span(pointer data, bounds_type bound) noexcept
1357 : m_pdata(data), m_bounds(std::move(bound))
1358 {
1359 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1360 }
1361
1362 constexpr span(pointer ptr, size_type size) : span(ptr, bounds_type{ size })
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001363 {}
1364
Anna Gringauze8aa42482015-11-11 12:41:11 -08001365 constexpr span(std::nullptr_t) : span(nullptr, bounds_type{})
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001366 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001367
Anna Gringauze8aa42482015-11-11 12:41:11 -08001368 constexpr span(std::nullptr_t, size_type size) : span(nullptr, bounds_type{})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001369 {
1370 fail_fast_assert(size == 0);
1371 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001372
Neil MacIntosh68064d62015-11-03 19:17:11 -08001373 // default
1374 template <std::ptrdiff_t DynamicRank = bounds_type::dynamic_rank, typename = std::enable_if_t<DynamicRank != 0>>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001375 constexpr span() : span(nullptr, bounds_type())
Neil MacIntosh68064d62015-11-03 19:17:11 -08001376 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001377
Neil MacIntosh68064d62015-11-03 19:17:11 -08001378 // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
Anna Gringauze8aa42482015-11-11 12:41:11 -08001379 template <typename T, typename Helper = details::SpanArrayTraits<T, dynamic_range>
1380 /*typename Dummy = std::enable_if_t<std::is_convertible<Helper::value_type (*)[], value_type (*)[]>::value>*/
1381 >
1382 constexpr span(T* const& data, size_type size) : span(data, typename Helper::bounds_type{size})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001383 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001384
Neil MacIntosh68064d62015-11-03 19:17:11 -08001385 // from n-dimensions static array
Anna Gringauze8aa42482015-11-11 12:41:11 -08001386 template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>,
1387 typename = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value>
1388 >
1389 constexpr span (T (&arr)[N]) : span(arr, typename Helper::bounds_type())
Neil MacIntosh68064d62015-11-03 19:17:11 -08001390 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001391
Neil MacIntosh68064d62015-11-03 19:17:11 -08001392 // from n-dimensions static array with size
Anna Gringauze8aa42482015-11-11 12:41:11 -08001393 template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>,
1394 typename = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001395 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001396 constexpr span(T(&arr)[N], size_type size) : span(arr, typename Helper::bounds_type{size})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001397 {
1398 fail_fast_assert(size <= N);
1399 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001400
Neil MacIntosh68064d62015-11-03 19:17:11 -08001401 // from std array
1402 template <size_t N,
Anna Gringauze8aa42482015-11-11 12:41:11 -08001403 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, bounds_type>::value>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001404 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001405 constexpr span (std::array<std::remove_const_t<value_type>, N> & arr) : span(arr.data(), static_bounds<N>())
Neil MacIntosh68064d62015-11-03 19:17:11 -08001406 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001407
Neil MacIntosh68064d62015-11-03 19:17:11 -08001408 template <size_t N,
Anna Gringauze8aa42482015-11-11 12:41:11 -08001409 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, bounds_type>::value
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001410 && std::is_const<value_type>::value>
1411 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001412 constexpr span (const std::array<std::remove_const_t<value_type>, N> & arr) : span(arr.data(), static_bounds<N>())
Neil MacIntosh68064d62015-11-03 19:17:11 -08001413 {}
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001414
Neil MacIntosh68064d62015-11-03 19:17:11 -08001415 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1416 template <typename Ptr,
1417 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
Anna Gringauze8aa42482015-11-11 12:41:11 -08001418 && details::LessThan<bounds_type::dynamic_rank, 2>::value>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001419 > // remove literal 0 case
Anna Gringauze8aa42482015-11-11 12:41:11 -08001420 constexpr span (pointer begin, Ptr end) : span(begin, details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001421 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001422
Neil MacIntosh68064d62015-11-03 19:17:11 -08001423 // from containers. It must has .size() and .data() two function signatures
1424 template <typename Cont, typename DataType = typename Cont::value_type,
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001425 typename Dummy = std::enable_if_t<!details::is_span<Cont>::value
Anna Gringauze8aa42482015-11-11 12:41:11 -08001426 && std::is_convertible<DataType (*)[], value_type (*)[]>::value
Neil MacIntosh68064d62015-11-03 19:17:11 -08001427 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
1428 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001429 constexpr span (Cont& cont) : span(static_cast<pointer>(cont.data()), details::newBoundsHelper<bounds_type>(cont.size()))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001430 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001431
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001432 constexpr span(const span &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001433
Neil MacIntosh68064d62015-11-03 19:17:11 -08001434 // convertible
1435 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
Anna Gringauze8aa42482015-11-11 12:41:11 -08001436 typename OtherBounds = static_bounds<OtherDimensions...>,
1437 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType, ValueType>::value && std::is_convertible<OtherBounds, bounds_type>::value>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001438 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001439 constexpr span(const span<OtherValueType, OtherDimensions...>& other)
1440 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001441 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001442
Neil MacIntosh68064d62015-11-03 19:17:11 -08001443 // reshape
Neil MacIntosh14d50a62015-11-03 12:44:09 -08001444 // DimCount here is a workaround for a bug in MSVC 2015
1445 template <typename... Dimensions2, size_t DimCount = sizeof...(Dimensions2), typename = std::enable_if_t<(DimCount > 0)>>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001446 constexpr span<ValueType, Dimensions2::value...> as_span(Dimensions2... dims)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001447 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001448 using BoundsType = typename span<ValueType, (Dimensions2::value)...>::bounds_type;
1449 auto tobounds = details::static_as_span_helper<BoundsType>(dims..., details::Sep{});
Neil MacIntosh68064d62015-11-03 19:17:11 -08001450 details::verifyBoundsReshape(this->bounds(), tobounds);
1451 return {this->data(), tobounds};
1452 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001453
Neil MacIntosh68064d62015-11-03 19:17:11 -08001454 // to bytes array
1455 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001456 auto as_bytes() const noexcept -> span<const byte>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001457 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001458 static_assert(Enabled, "The value_type of span must be standarded layout");
Neil MacIntosh68064d62015-11-03 19:17:11 -08001459 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
1460 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001461
Neil MacIntosh68064d62015-11-03 19:17:11 -08001462 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001463 auto as_writeable_bytes() const noexcept -> span<byte>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001464 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001465 static_assert(Enabled, "The value_type of span must be standarded layout");
Neil MacIntosh68064d62015-11-03 19:17:11 -08001466 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
1467 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001468
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001469 // from bytes array
Neil MacIntosh68064d62015-11-03 19:17:11 -08001470 template<typename U, bool IsByte = std::is_same<value_type, const byte>::value, typename = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001471 constexpr auto as_span() const noexcept -> span<const U, (bounds_type::static_size != dynamic_range ? static_cast<std::ptrdiff_t>(static_cast<size_t>(bounds_type::static_size) / sizeof(U)) : dynamic_range)>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001472 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001473 static_assert(std::is_standard_layout<U>::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast<size_type>(sizeof(U)) == 0),
Neil MacIntosh68064d62015-11-03 19:17:11 -08001474 "Target type must be standard layout and its size must match the byte array size");
1475 fail_fast_assert((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX);
1476 return { reinterpret_cast<const U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
1477 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001478
Neil MacIntosh68064d62015-11-03 19:17:11 -08001479 template<typename U, bool IsByte = std::is_same<value_type, byte>::value, typename = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001480 constexpr auto as_span() const noexcept -> span<U, (bounds_type::static_size != dynamic_range ? static_cast<ptrdiff_t>(static_cast<size_t>(bounds_type::static_size) / sizeof(U)) : dynamic_range)>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001481 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001482 static_assert(std::is_standard_layout<U>::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast<size_t>(sizeof(U)) == 0),
Neil MacIntosh68064d62015-11-03 19:17:11 -08001483 "Target type must be standard layout and its size must match the byte array size");
1484 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
1485 return { reinterpret_cast<U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
1486 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001487
Neil MacIntosh68064d62015-11-03 19:17:11 -08001488 // section on linear space
1489 template<std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001490 constexpr span<ValueType, Count> first() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001491 {
1492 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1493 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size()); // ensures we only check condition when needed
1494 return { this->data(), Count };
1495 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001496
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001497 constexpr span<ValueType, dynamic_range> first(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001498 {
1499 fail_fast_assert(count <= this->size());
1500 return { this->data(), count };
1501 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001502
Neil MacIntosh68064d62015-11-03 19:17:11 -08001503 template<std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001504 constexpr span<ValueType, Count> last() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001505 {
1506 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1507 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
1508 return { this->data() + this->size() - Count, Count };
1509 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001510
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001511 constexpr span<ValueType, dynamic_range> last(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001512 {
1513 fail_fast_assert(count <= this->size());
1514 return { this->data() + this->size() - count, count };
1515 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001516
Neil MacIntosh68064d62015-11-03 19:17:11 -08001517 template<std::ptrdiff_t Offset, std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001518 constexpr span<ValueType, Count> sub() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001519 {
1520 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");
1521 fail_fast_assert(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
1522 return { this->data() + Offset, Count };
1523 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001524
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001525 constexpr span<ValueType, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001526 {
1527 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1528 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
1529 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001530
Neil MacIntosh68064d62015-11-03 19:17:11 -08001531 // size
1532 constexpr size_type length() const noexcept
1533 {
1534 return this->size();
1535 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001536
Neil MacIntosh68064d62015-11-03 19:17:11 -08001537 constexpr size_type used_length() const noexcept
1538 {
1539 return length();
1540 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001541
Neil MacIntosh68064d62015-11-03 19:17:11 -08001542 constexpr size_type bytes() const noexcept
1543 {
1544 return sizeof(value_type) * this->size();
1545 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001546
Neil MacIntosh68064d62015-11-03 19:17:11 -08001547 constexpr size_type used_bytes() const noexcept
1548 {
1549 return bytes();
1550 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001551
Neil MacIntosh68064d62015-11-03 19:17:11 -08001552 // section
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001553 constexpr strided_span<ValueType, rank> section(index_type origin, index_type extents) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001554 {
1555 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze8aa42482015-11-11 12:41:11 -08001556 return{ &this->operator[](origin), size, strided_bounds<rank> {extents, details::make_stride(bounds())} };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001557 }
1558
Anna Gringauze8aa42482015-11-11 12:41:11 -08001559 constexpr reference operator[](const index_type& idx) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001560 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001561 return m_pdata[m_bounds.linearize(idx)];
Neil MacIntosh68064d62015-11-03 19:17:11 -08001562 }
1563
Anna Gringauze8aa42482015-11-11 12:41:11 -08001564 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
1565 constexpr Ret operator[](size_type idx) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001566 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001567 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
1568 const size_type ridx = idx * m_bounds.stride();
1569
1570 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
1571 return Ret{ m_pdata + ridx, m_bounds.slice() };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001572 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001573
Anna Gringauze8aa42482015-11-11 12:41:11 -08001574 constexpr bounds_type bounds() const noexcept
1575 {
1576 return m_bounds;
1577 }
1578
1579 template <size_t Dim = 0>
1580 constexpr size_type extent() const noexcept
1581 {
1582 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
1583 return m_bounds.template extent<Dim>();
1584 }
1585
1586 constexpr size_type size() const noexcept
1587 {
1588 return m_bounds.size();
1589 }
1590
1591 constexpr pointer data() const noexcept
1592 {
1593 return m_pdata;
1594 }
1595
1596 constexpr operator bool() const noexcept
1597 {
1598 return m_pdata != nullptr;
1599 }
1600
1601 constexpr iterator begin() const
1602 {
1603 return iterator{ this, true };
1604 }
1605
1606 constexpr iterator end() const
1607 {
1608 return iterator{ this, false };
1609 }
1610
1611 constexpr const_iterator cbegin() const
1612 {
1613 return const_iterator{ reinterpret_cast<const const_span*>(this), true };
1614 }
1615
1616 constexpr const_iterator cend() const
1617 {
1618 return const_iterator{ reinterpret_cast<const const_span*>(this), false };
1619 }
1620
1621 constexpr reverse_iterator rbegin() const
1622 {
1623 return reverse_iterator{ end() };
1624 }
1625
1626 constexpr reverse_iterator rend() const
1627 {
1628 return reverse_iterator{ begin() };
1629 }
1630
1631 constexpr const_reverse_iterator crbegin() const
1632 {
1633 return const_reverse_iterator{ cend() };
1634 }
1635
1636 constexpr const_reverse_iterator crend() const
1637 {
1638 return const_reverse_iterator{ cbegin() };
1639 }
1640
1641 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1642 constexpr bool operator== (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1643 {
1644 return m_bounds.size() == other.m_bounds.size() &&
1645 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
1646 }
1647
1648 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1649 constexpr bool operator!= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1650 {
1651 return !(*this == other);
1652 }
1653
1654 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1655 constexpr bool operator< (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1656 {
1657 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1658 }
1659
1660 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1661 constexpr bool operator<= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1662 {
1663 return !(other < *this);
1664 }
1665
1666 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1667 constexpr bool operator> (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1668 {
1669 return (other < *this);
1670 }
1671
1672 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1673 constexpr bool operator>= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1674 {
1675 return !(*this < other);
1676 }
1677
1678private:
1679
1680 template <typename T>
1681 constexpr span(T *data, std::enable_if_t<std::is_same<value_type, std::remove_all_extents_t<T>>::value, bounds_type> bound) noexcept
1682 : m_pdata(reinterpret_cast<pointer>(data)), m_bounds(std::move(bound))
1683 {
1684 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1685 }
1686
1687 template <std::ptrdiff_t... OtherDimensions>
1688 constexpr span<value_type, OtherDimensions...> as_span(const static_bounds<OtherDimensions...> &bounds)
1689 {
1690 details::verifyBoundsReshape(m_bounds, bounds);
1691 return{ m_pdata, bounds };
1692 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001693};
1694
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001695template <typename T, std::ptrdiff_t... Dimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001696constexpr auto as_span(T* const& ptr, dim<Dimensions>... args) -> span<std::remove_all_extents_t<T>, Dimensions...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001697{
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001698 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), details::static_as_span_helper<static_bounds<Dimensions...>>(args..., details::Sep{})};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001699}
1700
1701template <typename T>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001702constexpr auto as_span (T* arr, std::ptrdiff_t len) -> typename details::SpanArrayTraits<T, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001703{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001704 return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001705}
1706
1707template <typename T, size_t N>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001708constexpr auto as_span (T (&arr)[N]) -> typename details::SpanArrayTraits<T, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001709{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001710 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001711}
1712
1713template <typename T, size_t N>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001714constexpr span<const T, N> as_span(const std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001715{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001716 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001717}
1718
1719template <typename T, size_t N>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001720constexpr span<const T, N> as_span(const std::array<T, N> &&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001721
1722template <typename T, size_t N>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001723constexpr span<T, N> as_span(std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001724{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001725 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001726}
1727
1728template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001729constexpr span<T, dynamic_range> as_span(T *begin, T *end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001730{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001731 return {begin, end};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001732}
1733
1734template <typename Cont>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001735constexpr auto as_span(Cont &arr) -> std::enable_if_t<!details::is_span<std::decay_t<Cont>>::value,
1736 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001737{
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001738 fail_fast_assert(arr.size() < PTRDIFF_MAX);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001739 return {arr.data(), static_cast<std::ptrdiff_t>(arr.size())};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001740}
1741
1742template <typename Cont>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001743constexpr auto as_span(Cont &&arr) -> std::enable_if_t<!details::is_span<std::decay_t<Cont>>::value,
1744 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001745
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001746template <typename ValueType, size_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001747class strided_span : public basic_span<ValueType, strided_bounds<Rank>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001748{
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001749 using Base = basic_span<ValueType, strided_bounds<Rank>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001750
Neil MacIntosh68064d62015-11-03 19:17:11 -08001751 template<typename OtherValue, size_t OtherRank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001752 friend class strided_span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001753
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001754public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001755 using Base::rank;
1756 using typename Base::bounds_type;
1757 using typename Base::size_type;
1758 using typename Base::pointer;
1759 using typename Base::value_type;
1760 using typename Base::index_type;
1761 using typename Base::iterator;
1762 using typename Base::const_iterator;
1763 using typename Base::reference;
1764
1765 // from static array of size N
1766 template<size_type N>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001767 strided_span(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001768 {
1769 fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries");
1770 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001771
Neil MacIntosh68064d62015-11-03 19:17:11 -08001772 // from raw data
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001773 strided_span(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001774 {
1775 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
1776 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001777
Neil MacIntosh68064d62015-11-03 19:17:11 -08001778 // from array view
1779 template <std::ptrdiff_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001780 strided_span(span<ValueType, Dimensions...> av, bounds_type bounds) : Base(av.data(), std::move(bounds))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001781 {
1782 fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries");
1783 }
1784
1785 // convertible
1786 template <typename OtherValueType,
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001787 typename BaseType = basic_span<ValueType, strided_bounds<Rank>>,
1788 typename OtherBaseType = basic_span<OtherValueType, strided_bounds<Rank>>,
Neil MacIntosh68064d62015-11-03 19:17:11 -08001789 typename Dummy = std::enable_if_t<std::is_convertible<OtherBaseType, BaseType>::value>
1790 >
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001791 constexpr strided_span(const strided_span<OtherValueType, Rank> &av) : Base(static_cast<const typename strided_span<OtherValueType, Rank>::Base &>(av)) // static_cast is required
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001792 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001793
Neil MacIntosh68064d62015-11-03 19:17:11 -08001794 // convert from bytes
1795 template <typename OtherValueType>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001796 strided_span<typename std::enable_if<std::is_same<value_type, const byte>::value, OtherValueType>::type, rank> as_strided_span() const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001797 {
1798 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
1799 auto d = static_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001800
Neil MacIntosh68064d62015-11-03 19:17:11 -08001801 size_type size = this->bounds().total_size() / d;
1802 return{ (OtherValueType*)this->data(), size, bounds_type{ resize_extent(this->bounds().index_bounds(), d), resize_stride(this->bounds().strides(), d)} };
1803 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001804
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001805 strided_span section(index_type origin, index_type extents) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001806 {
1807 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
1808 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}};
1809 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001810
Neil MacIntosh68064d62015-11-03 19:17:11 -08001811 constexpr reference operator[](const index_type& idx) const
1812 {
1813 return Base::operator[](idx);
1814 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001815
Neil MacIntosh68064d62015-11-03 19:17:11 -08001816 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001817 constexpr strided_span<value_type, rank-1> operator[](size_type idx) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001818 {
1819 auto ret = Base::operator[](idx);
1820 return{ ret.data(), ret.bounds().total_size(), ret.bounds() };
1821 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001822
1823private:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001824 static index_type resize_extent(const index_type& extent, std::ptrdiff_t d)
1825 {
1826 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");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001827
Neil MacIntosh68064d62015-11-03 19:17:11 -08001828 index_type ret = extent;
1829 ret[rank - 1] /= d;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001830
Neil MacIntosh68064d62015-11-03 19:17:11 -08001831 return ret;
1832 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001833
Neil MacIntosh68064d62015-11-03 19:17:11 -08001834 template <bool Enabled = (rank == 1), typename Dummy = std::enable_if_t<Enabled>>
1835 static index_type resize_stride(const index_type& strides, std::ptrdiff_t , void * = 0)
1836 {
1837 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001838
Neil MacIntosh68064d62015-11-03 19:17:11 -08001839 return strides;
1840 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001841
Neil MacIntosh68064d62015-11-03 19:17:11 -08001842 template <bool Enabled = (rank > 1), typename Dummy = std::enable_if_t<Enabled>>
1843 static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
1844 {
1845 fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1846 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");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001847
Neil MacIntosh68064d62015-11-03 19:17:11 -08001848 for (size_t i = rank - 1; i > 0; --i)
1849 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 -07001850
Neil MacIntosh68064d62015-11-03 19:17:11 -08001851 index_type ret = strides / d;
1852 ret[rank - 1] = 1;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001853
Neil MacIntosh68064d62015-11-03 19:17:11 -08001854 return ret;
1855 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001856};
1857
Anna Gringauze8aa42482015-11-11 12:41:11 -08001858template <class Span>
1859class contiguous_span_iterator : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001860{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001861 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001862public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001863 using typename Base::reference;
1864 using typename Base::pointer;
1865 using typename Base::difference_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001866
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001867private:
Anna Gringauze8aa42482015-11-11 12:41:11 -08001868 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
1869 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001870
1871 pointer m_pdata;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001872 const Span* m_validator;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001873 void validateThis() const
1874 {
1875 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");
1876 }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001877 contiguous_span_iterator (const Span* container, bool isbegin) :
Neil MacIntosh68064d62015-11-03 19:17:11 -08001878 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001879public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001880 reference operator*() const noexcept
1881 {
1882 validateThis();
1883 return *m_pdata;
1884 }
1885 pointer operator->() const noexcept
1886 {
1887 validateThis();
1888 return m_pdata;
1889 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001890 contiguous_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001891 {
1892 ++m_pdata;
1893 return *this;
1894 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001895 contiguous_span_iterator operator++(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001896 {
1897 auto ret = *this;
1898 ++(*this);
1899 return ret;
1900 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001901 contiguous_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001902 {
1903 --m_pdata;
1904 return *this;
1905 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001906 contiguous_span_iterator operator--(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001907 {
1908 auto ret = *this;
1909 --(*this);
1910 return ret;
1911 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001912 contiguous_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001913 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001914 contiguous_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001915 return ret += n;
1916 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001917 contiguous_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001918 {
1919 m_pdata += n;
1920 return *this;
1921 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001922 contiguous_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001923 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001924 contiguous_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001925 return ret -= n;
1926 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001927 contiguous_span_iterator& operator-=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001928 {
1929 return *this += -n;
1930 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001931 difference_type operator-(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001932 {
1933 fail_fast_assert(m_validator == rhs.m_validator);
1934 return m_pdata - rhs.m_pdata;
1935 }
1936 reference operator[](difference_type n) const noexcept
1937 {
1938 return *(*this + n);
1939 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001940 bool operator==(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001941 {
1942 fail_fast_assert(m_validator == rhs.m_validator);
1943 return m_pdata == rhs.m_pdata;
1944 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001945 bool operator!=(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001946 {
1947 return !(*this == rhs);
1948 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001949 bool operator<(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001950 {
1951 fail_fast_assert(m_validator == rhs.m_validator);
1952 return m_pdata < rhs.m_pdata;
1953 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001954 bool operator<=(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001955 {
1956 return !(rhs < *this);
1957 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001958 bool operator>(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001959 {
1960 return rhs < *this;
1961 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001962 bool operator>=(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001963 {
1964 return !(rhs > *this);
1965 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001966 void swap(contiguous_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001967 {
1968 std::swap(m_pdata, rhs.m_pdata);
1969 std::swap(m_validator, rhs.m_validator);
1970 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001971};
1972
Anna Gringauze8aa42482015-11-11 12:41:11 -08001973template <typename Span>
1974contiguous_span_iterator<Span> operator+(typename contiguous_span_iterator<Span>::difference_type n, const contiguous_span_iterator<Span>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001975{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001976 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001977}
1978
Anna Gringauze8aa42482015-11-11 12:41:11 -08001979template <typename Span>
1980class general_span_iterator : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001981{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001982 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001983public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001984 using typename Base::reference;
1985 using typename Base::pointer;
1986 using typename Base::difference_type;
1987 using typename Base::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001988private:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001989 template <typename ValueType, typename Bounds>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001990 friend class basic_span;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001991
Anna Gringauze8aa42482015-11-11 12:41:11 -08001992 const Span * m_container;
1993 typename Span::bounds_type::iterator m_itr;
1994 general_span_iterator(const Span *container, bool isbegin) :
Neil MacIntosh68064d62015-11-03 19:17:11 -08001995 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
1996 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001997public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001998 reference operator*() noexcept
1999 {
2000 return (*m_container)[*m_itr];
2001 }
2002 pointer operator->() noexcept
2003 {
2004 return &(*m_container)[*m_itr];
2005 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002006 general_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002007 {
2008 ++m_itr;
2009 return *this;
2010 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002011 general_span_iterator operator++(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002012 {
2013 auto ret = *this;
2014 ++(*this);
2015 return ret;
2016 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002017 general_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002018 {
2019 --m_itr;
2020 return *this;
2021 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002022 general_span_iterator operator--(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002023 {
2024 auto ret = *this;
2025 --(*this);
2026 return ret;
2027 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002028 general_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002029 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002030 general_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08002031 return ret += n;
2032 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002033 general_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002034 {
2035 m_itr += n;
2036 return *this;
2037 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002038 general_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002039 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002040 general_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08002041 return ret -= n;
2042 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002043 general_span_iterator& operator-=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002044 {
2045 return *this += -n;
2046 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002047 difference_type operator-(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002048 {
2049 fail_fast_assert(m_container == rhs.m_container);
2050 return m_itr - rhs.m_itr;
2051 }
2052 value_type operator[](difference_type n) const noexcept
2053 {
2054 return (*m_container)[m_itr[n]];;
2055 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002056 bool operator==(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002057 {
2058 fail_fast_assert(m_container == rhs.m_container);
2059 return m_itr == rhs.m_itr;
2060 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002061 bool operator !=(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002062 {
2063 return !(*this == rhs);
2064 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002065 bool operator<(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002066 {
2067 fail_fast_assert(m_container == rhs.m_container);
2068 return m_itr < rhs.m_itr;
2069 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002070 bool operator<=(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002071 {
2072 return !(rhs < *this);
2073 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002074 bool operator>(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002075 {
2076 return rhs < *this;
2077 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002078 bool operator>=(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002079 {
2080 return !(rhs > *this);
2081 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002082 void swap(general_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002083 {
2084 std::swap(m_itr, rhs.m_itr);
2085 std::swap(m_container, rhs.m_container);
2086 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002087};
2088
Anna Gringauze8aa42482015-11-11 12:41:11 -08002089template <typename Span>
2090general_span_iterator<Span> operator+(typename general_span_iterator<Span>::difference_type n, const general_span_iterator<Span>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002091{
Neil MacIntosh68064d62015-11-03 19:17:11 -08002092 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002093}
2094
Neil MacIntoshef626fd2015-09-29 16:41:37 -07002095} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002096
Neil MacIntoshd5316802015-09-30 21:54:08 -07002097#ifdef _MSC_VER
2098
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002099#undef constexpr
2100#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002101
Neil MacIntoshd5316802015-09-30 21:54:08 -07002102#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002103#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07002104
2105#ifndef GSL_THROWS_FOR_TESTING
2106#pragma undef noexcept
2107#endif // GSL_THROWS_FOR_TESTING
2108
Neil MacIntoshe9a96022015-11-03 18:56:55 -08002109#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
2110#pragma pop_macro("GSL_MSVC_HAS_VARIADIC_CTOR_BUG")
2111
2112
Neil MacIntosh9a297122015-09-14 15:11:07 -07002113#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002114
Neil MacIntoshd5316802015-09-30 21:54:08 -07002115#endif // _MSC_VER
2116
2117#if defined(GSL_THROWS_FOR_TESTING)
2118#undef noexcept
2119#endif // GSL_THROWS_FOR_TESTING
2120
Treb Connell51da1362015-09-24 18:08:34 -07002121
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002122#endif // GSL_SPAN_H