blob: 7fd711ca5c6112d1e66681f5a5ce74e11f7a3534 [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
Neil MacIntoshd5316802015-09-30 21:54:08 -070042// VS 2013 workarounds
43#if _MSC_VER <= 1800
44
Neil MacIntosh292f81e2015-11-17 15:07:51 -080045// needed in span.h
Neil MacIntoshe9a96022015-11-03 18:56:55 -080046#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
47
Neil MacIntoshd5316802015-09-30 21:54:08 -070048// noexcept is not understood
49#ifndef GSL_THROWS_FOR_TESTING
Neil MacIntosh292f81e2015-11-17 15:07:51 -080050#pragma push_macro("noexcept")
Neil MacIntoshd5316802015-09-30 21:54:08 -070051#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070052#endif
53
Neil MacIntoshd5316802015-09-30 21:54:08 -070054// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070055#pragma warning(push)
56#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
Neil MacIntosha998a9b2015-11-12 18:57:23 -080057#pragma warning(disable: 4512) // warns that assignment op could not be generated
Neil MacIntoshd5316802015-09-30 21:54:08 -070058
Neil MacIntosh9a297122015-09-14 15:11:07 -070059#endif // _MSC_VER <= 1800
60
Neil MacIntoshd5316802015-09-30 21:54:08 -070061#endif // _MSC_VER
62
63// In order to test the library, we need it to throw exceptions that we can catch
64#ifdef GSL_THROWS_FOR_TESTING
Neil MacIntosh292f81e2015-11-17 15:07:51 -080065
66#ifdef _MSC_VER
67#pragma push_macro("noexcept")
68#endif
69
Neil MacIntoshd5316802015-09-30 21:54:08 -070070#define noexcept /* nothing */
Neil MacIntosh292f81e2015-11-17 15:07:51 -080071
Neil MacIntoshd5316802015-09-30 21:54:08 -070072#endif // GSL_THROWS_FOR_TESTING
73
74
Neil MacIntoshef626fd2015-09-29 16:41:37 -070075namespace gsl {
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070076
77/*
78** begin definitions of index and bounds
79*/
80namespace details
81{
Neil MacIntosh68064d62015-11-03 19:17:11 -080082 template <typename SizeType>
83 struct SizeTypeTraits
84 {
85 static const SizeType max_value = std::numeric_limits<SizeType>::max();
86 };
Anna Gringauze1c208b32015-10-16 17:40:57 -070087
88
Neil MacIntosh68064d62015-11-03 19:17:11 -080089 template<typename... Ts>
90 class are_integral : public std::integral_constant<bool, true> {};
Anna Gringauze1c208b32015-10-16 17:40:57 -070091
Neil MacIntosh68064d62015-11-03 19:17:11 -080092 template<typename T, typename... Ts>
93 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 -070094}
95
Neil MacIntoshf45fedb2015-10-15 14:29:35 -070096template <size_t Rank>
Anna Gringauzedb384972015-10-05 12:34:23 -070097class index final
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070098{
Neil MacIntosh68064d62015-11-03 19:17:11 -080099 static_assert(Rank > 0, "Rank must be greater than 0!");
Anna Gringauzedb384972015-10-05 12:34:23 -0700100
Neil MacIntosh68064d62015-11-03 19:17:11 -0800101 template <size_t OtherRank>
102 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -0700103
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700104public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800105 static const size_t rank = Rank;
106 using value_type = std::ptrdiff_t;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700107 using size_type = value_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800108 using reference = std::add_lvalue_reference_t<value_type>;
109 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700110
Neil MacIntosh68064d62015-11-03 19:17:11 -0800111 constexpr index() noexcept
112 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700113
Neil MacIntosh68064d62015-11-03 19:17:11 -0800114 constexpr index(const value_type(&values)[Rank]) noexcept
115 {
116 std::copy(values, values + Rank, elems);
117 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700118
Anna Gringauze8aa42482015-11-11 12:41:11 -0800119#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
120 template<typename T, typename... Ts,
121 typename = std::enable_if_t<((sizeof...(Ts) + 1) == Rank) &&
122 std::is_integral<T>::value &&
123 details::are_integral<Ts...>::value>>
124 constexpr index(T t, Ts... ds) : index({ static_cast<value_type>(t), static_cast<value_type>(ds)... })
125 {}
126#else
127 template<typename... Ts,
128 typename = std::enable_if_t<(sizeof...(Ts) == Rank) && details::are_integral<Ts...>::value>>
129 constexpr index(Ts... ds) noexcept : elems{ static_cast<value_type>(ds)... }
130 {}
131#endif
Anna Gringauzedb384972015-10-05 12:34:23 -0700132
Neil MacIntosh68064d62015-11-03 19:17:11 -0800133 constexpr index(const index& other) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700134
Neil MacIntosh68064d62015-11-03 19:17:11 -0800135 constexpr index& operator=(const index& rhs) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700136
Neil MacIntosh68064d62015-11-03 19:17:11 -0800137 // Preconditions: component_idx < rank
138 constexpr reference operator[](size_t component_idx)
139 {
140 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
141 return elems[component_idx];
142 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700143
Neil MacIntosh68064d62015-11-03 19:17:11 -0800144 // Preconditions: component_idx < rank
145 constexpr const_reference operator[](size_t component_idx) const noexcept
146 {
147 fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
148 return elems[component_idx];
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 std::equal(elems, elems + rank, rhs.elems);
154 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700155
Neil MacIntosh68064d62015-11-03 19:17:11 -0800156 constexpr bool operator!=(const index& rhs) const noexcept
157 {
158 return !(this == rhs);
159 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700160
Neil MacIntosh68064d62015-11-03 19:17:11 -0800161 constexpr index operator+() const noexcept
162 {
163 return *this;
164 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700165
Neil MacIntosh68064d62015-11-03 19:17:11 -0800166 constexpr index operator-() const noexcept
167 {
168 index ret = *this;
169 std::transform(ret, ret + rank, ret, std::negate<value_type>{});
170 return ret;
171 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700172
Neil MacIntosh68064d62015-11-03 19:17:11 -0800173 constexpr index operator+(const index& rhs) const noexcept
174 {
175 index ret = *this;
176 ret += rhs;
177 return ret;
178 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700179
Neil MacIntosh68064d62015-11-03 19:17:11 -0800180 constexpr index operator-(const index& rhs) const noexcept
181 {
182 index ret = *this;
183 ret -= rhs;
184 return ret;
185 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700186
Neil MacIntosh68064d62015-11-03 19:17:11 -0800187 constexpr index& operator+=(const index& rhs) noexcept
188 {
189 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<value_type>{});
190 return *this;
191 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700192
Neil MacIntosh68064d62015-11-03 19:17:11 -0800193 constexpr index& operator-=(const index& rhs) noexcept
194 {
195 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<value_type>{});
196 return *this;
197 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700198
Neil MacIntosh68064d62015-11-03 19:17:11 -0800199 constexpr index operator*(value_type v) const noexcept
200 {
201 index ret = *this;
202 ret *= v;
203 return ret;
204 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700205
Neil MacIntosh68064d62015-11-03 19:17:11 -0800206 constexpr index operator/(value_type v) const noexcept
207 {
208 index ret = *this;
209 ret /= v;
210 return ret;
211 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700212
Neil MacIntosh68064d62015-11-03 19:17:11 -0800213 friend constexpr index operator*(value_type v, const index& rhs) noexcept
214 {
215 return rhs * v;
216 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700217
Neil MacIntosh68064d62015-11-03 19:17:11 -0800218 constexpr index& operator*=(value_type v) noexcept
219 {
220 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies<value_type>{}(x, v); });
221 return *this;
222 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700223
Neil MacIntosh68064d62015-11-03 19:17:11 -0800224 constexpr index& operator/=(value_type v) noexcept
225 {
226 std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<value_type>{}(x, v); });
227 return *this;
228 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700229
Anna Gringauzedb384972015-10-05 12:34:23 -0700230private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800231 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700232};
233
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700234#ifndef _MSC_VER
235
236struct static_bounds_dynamic_range_t
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700237{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800238 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
239 constexpr operator T() const noexcept
240 {
241 return static_cast<T>(-1);
242 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700243
Neil MacIntosh68064d62015-11-03 19:17:11 -0800244 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
245 constexpr bool operator ==(T other) const noexcept
246 {
247 return static_cast<T>(-1) == other;
248 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700249
Neil MacIntosh68064d62015-11-03 19:17:11 -0800250 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
251 constexpr bool operator !=(T other) const noexcept
252 {
253 return static_cast<T>(-1) != other;
254 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700255
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700256};
257
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700258template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
259constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
260{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800261 return right == left;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700262}
263
264template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
265constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
266{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800267 return right != left;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700268}
269
270constexpr static_bounds_dynamic_range_t dynamic_range{};
271#else
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700272const std::ptrdiff_t dynamic_range = -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700273#endif
274
275struct generalized_mapping_tag {};
276struct contiguous_mapping_tag : generalized_mapping_tag {};
277
278namespace details
279{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700280
Neil MacIntosh68064d62015-11-03 19:17:11 -0800281 template <std::ptrdiff_t Left, std::ptrdiff_t Right>
282 struct LessThan
283 {
284 static const bool value = Left < Right;
285 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700286
Neil MacIntosh68064d62015-11-03 19:17:11 -0800287 template <std::ptrdiff_t... Ranges>
288 struct BoundsRanges {
289 using size_type = std::ptrdiff_t;
290 static const size_type Depth = 0;
291 static const size_type DynamicNum = 0;
292 static const size_type CurrentRange = 1;
293 static const size_type TotalSize = 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700294
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700295 // TODO : following signature is for work around VS bug
296 template <typename OtherRange>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800297 BoundsRanges(const OtherRange&, bool /* firstLevel */)
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700298 {}
Neil MacIntosh68064d62015-11-03 19:17:11 -0800299
300 BoundsRanges (const BoundsRanges&) = default;
Vladislav Yaroslavlev995cfdf2015-11-12 10:46:21 +0300301 BoundsRanges& operator=(const BoundsRanges&) = default;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800302 BoundsRanges(const std::ptrdiff_t* const) { }
303 BoundsRanges() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700304
305
Neil MacIntosh68064d62015-11-03 19:17:11 -0800306 template <typename T, size_t Dim>
307 void serialize(T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700308 {}
309
Neil MacIntosh68064d62015-11-03 19:17:11 -0800310 template <typename T, size_t Dim>
311 size_type linearize(const T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700312 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800313 return 0;
314 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700315
Neil MacIntosh68064d62015-11-03 19:17:11 -0800316 template <typename T, size_t Dim>
317 bool contains(const T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700318 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800319 return 0;
320 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700321
Neil MacIntosh68064d62015-11-03 19:17:11 -0800322 size_type totalSize() const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700323 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800324 return TotalSize;
325 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700326
Neil MacIntosh68064d62015-11-03 19:17:11 -0800327 bool operator==(const BoundsRanges&) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700328 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800329 return true;
330 }
331 };
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700332
Neil MacIntosh68064d62015-11-03 19:17:11 -0800333 template <std::ptrdiff_t... RestRanges>
334 struct BoundsRanges <dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>{
335 using Base = BoundsRanges <RestRanges... >;
336 using size_type = std::ptrdiff_t;
337 static const size_t Depth = Base::Depth + 1;
338 static const size_t DynamicNum = Base::DynamicNum + 1;
339 static const size_type CurrentRange = dynamic_range;
340 static const size_type TotalSize = dynamic_range;
341 const size_type m_bound;
342
343 BoundsRanges (const BoundsRanges&) = default;
344
345 BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
346 {
347 fail_fast_assert(0 <= *arr);
348 }
349
350 BoundsRanges() : m_bound(0) {}
351
352 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
353 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other, bool /* firstLevel */ = true) :
354 Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false), m_bound(other.totalSize())
355 {}
356
357 template <typename T, size_t Dim = 0>
358 void serialize(T& arr) const
359 {
360 arr[Dim] = elementNum();
361 this->Base::template serialize<T, Dim + 1>(arr);
362 }
363
364 template <typename T, size_t Dim = 0>
365 size_type linearize(const T& arr) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700366 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800367 const size_type index = this->Base::totalSize() * arr[Dim];
368 fail_fast_assert(index < m_bound);
369 return index + this->Base::template linearize<T, Dim + 1>(arr);
370 }
371
372 template <typename T, size_t Dim = 0>
373 size_type contains(const T & arr) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700374 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800375 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
376 if (last == -1)
377 return -1;
378 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
379 return cur < m_bound ? cur + last : -1;
380 }
381
382 size_type totalSize() const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700383 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800384 return m_bound;
385 }
386
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700387 size_type elementNum() const noexcept
388 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800389 return totalSize() / this->Base::totalSize();
390 }
391
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700392 size_type elementNum(size_t dim) const noexcept
393 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800394 if (dim > 0)
395 return this->Base::elementNum(dim - 1);
396 else
397 return elementNum();
398 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700399
Neil MacIntosh68064d62015-11-03 19:17:11 -0800400 bool operator == (const BoundsRanges & rhs) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700401 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800402 return m_bound == rhs.m_bound && static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
403 }
404 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700405
Neil MacIntosh68064d62015-11-03 19:17:11 -0800406 template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
407 struct BoundsRanges <CurRange, RestRanges...> : BoundsRanges<RestRanges...>
408 {
409 using Base = BoundsRanges <RestRanges... >;
410 using size_type = std::ptrdiff_t;
411 static const size_t Depth = Base::Depth + 1;
412 static const size_t DynamicNum = Base::DynamicNum;
413 static const size_type CurrentRange = CurRange;
414 static const size_type TotalSize = Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize;
415
416 BoundsRanges (const BoundsRanges&) = default;
417 BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) { }
418 BoundsRanges() = default;
419
420 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
421 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>&other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
422 {
423 fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
424 }
425
426 template <typename T, size_t Dim = 0>
427 void serialize(T& arr) const
428 {
429 arr[Dim] = elementNum();
430 this->Base::template serialize<T, Dim + 1>(arr);
431 }
432
433 template <typename T, size_t Dim = 0>
434 size_type linearize(const T& arr) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700435 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800436 fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
437 return this->Base::totalSize() * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
438 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700439
Neil MacIntosh68064d62015-11-03 19:17:11 -0800440 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700441 size_type contains(const T& arr) const
442 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800443 if (arr[Dim] >= CurrentRange)
444 return -1;
445 const size_type last = this->Base::template contains<T, Dim + 1>(arr);
446 if (last == -1)
447 return -1;
448 return this->Base::totalSize() * arr[Dim] + last;
449 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700450
Neil MacIntosh68064d62015-11-03 19:17:11 -0800451 size_type totalSize() const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700452 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800453 return CurrentRange * this->Base::totalSize();
454 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700455
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700456 size_type elementNum() const noexcept
457 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800458 return CurrentRange;
459 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700460
Neil MacIntosh68064d62015-11-03 19:17:11 -0800461 size_type elementNum(size_t dim) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700462 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800463 if (dim > 0)
464 return this->Base::elementNum(dim - 1);
465 else
466 return elementNum();
467 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700468
Neil MacIntosh68064d62015-11-03 19:17:11 -0800469 bool operator== (const BoundsRanges& rhs) const noexcept
470 {
471 return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
472 }
473 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700474
Neil MacIntosh68064d62015-11-03 19:17:11 -0800475 template <typename SourceType, typename TargetType, size_t Rank>
476 struct BoundsRangeConvertible2;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700477
Neil MacIntosh68064d62015-11-03 19:17:11 -0800478 template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
479 auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700480
Neil MacIntosh68064d62015-11-03 19:17:11 -0800481 template <size_t Rank, typename SourceType, typename TargetType>
482 auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
483
484 template <typename SourceType, typename TargetType, size_t Rank>
485 struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
486 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
487 && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
488 {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700489
Neil MacIntosh68064d62015-11-03 19:17:11 -0800490 template <typename SourceType, typename TargetType>
491 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700492
Neil MacIntosh68064d62015-11-03 19:17:11 -0800493 template <typename SourceType, typename TargetType, std::ptrdiff_t Rank = TargetType::Depth>
494 struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(),
495 std::integral_constant<bool, SourceType::Depth == TargetType::Depth
496 && (!LessThan<SourceType::CurrentRange, TargetType::CurrentRange>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>()))
497 {};
498 template <typename SourceType, typename TargetType>
499 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700500
Neil MacIntosh68064d62015-11-03 19:17:11 -0800501 template <typename TypeChain>
502 struct TypeListIndexer
503 {
504 const TypeChain & obj;
505 TypeListIndexer(const TypeChain & obj) :obj(obj){}
506 template<size_t N>
507 const TypeChain & getObj(std::true_type)
508 {
509 return obj;
510 }
511 template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
512 auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
513 {
514 return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
515 }
516 template <size_t N>
517 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
518 {
519 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
520 }
521 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700522
Neil MacIntosh68064d62015-11-03 19:17:11 -0800523 template <typename TypeChain>
524 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
525 {
526 return TypeListIndexer<TypeChain>(obj);
527 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700528
Neil MacIntosh68064d62015-11-03 19:17:11 -0800529 template <size_t Rank, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1>>>
530 constexpr Ret shift_left(const index<Rank>& other) noexcept
531 {
532 Ret ret{};
533 for (size_t i = 0; i < Rank - 1; ++i)
534 {
535 ret[i] = other[i + 1];
536 }
537 return ret;
538 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700539}
540
541template <typename IndexType>
542class bounds_iterator;
543
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700544template <std::ptrdiff_t... Ranges>
545class static_bounds
546{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700547public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800548 static_bounds(const details::BoundsRanges<Ranges...>&) {
549 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700550};
551
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700552template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
553class static_bounds<FirstRange, RestRanges...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700554{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800555 using MyRanges = details::BoundsRanges<FirstRange, RestRanges... >;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700556
Neil MacIntosh68064d62015-11-03 19:17:11 -0800557 MyRanges m_ranges;
558 constexpr static_bounds(const MyRanges& range) : m_ranges(range)
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700559 {}
Neil MacIntosh68064d62015-11-03 19:17:11 -0800560
561 template <std::ptrdiff_t... OtherRanges>
562 friend class static_bounds;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700563
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700564public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800565 static const size_t rank = MyRanges::Depth;
566 static const size_t dynamic_rank = MyRanges::DynamicNum;
567 static const std::ptrdiff_t static_size = MyRanges::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700568
Neil MacIntosh68064d62015-11-03 19:17:11 -0800569 using size_type = std::ptrdiff_t;
570 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700571 using const_index_type = std::add_const_t<index_type>;
572 using iterator = bounds_iterator<const_index_type>;
573 using const_iterator = bounds_iterator<const_index_type>;
574 using difference_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800575 using sliced_type = static_bounds<RestRanges...>;
576 using mapping_type = contiguous_mapping_tag;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700577
Neil MacIntosh68064d62015-11-03 19:17:11 -0800578 constexpr static_bounds(const static_bounds&) = default;
579
580 template <std::ptrdiff_t... Ranges, typename Dummy = std::enable_if_t<
581 details::BoundsRangeConvertible<details::BoundsRanges<Ranges...>, details::BoundsRanges <FirstRange, RestRanges... >>::value>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700582 constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
583 {}
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700584
Neil MacIntosh68064d62015-11-03 19:17:11 -0800585 constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges((const std::ptrdiff_t*)il.begin())
586 {
587 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");
588 fail_fast_assert(m_ranges.totalSize() <= PTRDIFF_MAX, "Size of the range is larger than the max element of the size type");
589 }
590
591 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700592
Neil MacIntosh68064d62015-11-03 19:17:11 -0800593 constexpr static_bounds& operator=(const static_bounds& otherBounds)
594 {
595 new(&m_ranges) MyRanges (otherBounds.m_ranges);
596 return *this;
597 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700598
Neil MacIntosh68064d62015-11-03 19:17:11 -0800599 constexpr sliced_type slice() const noexcept
600 {
601 return sliced_type{static_cast<const details::BoundsRanges<RestRanges...> &>(m_ranges)};
602 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700603
Neil MacIntosh68064d62015-11-03 19:17:11 -0800604 constexpr size_type stride() const noexcept
605 {
606 return rank > 1 ? slice().size() : 1;
607 }
608
609 constexpr size_type size() const noexcept
610 {
611 return m_ranges.totalSize();
612 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700613
Neil MacIntosh68064d62015-11-03 19:17:11 -0800614 constexpr size_type total_size() const noexcept
615 {
616 return m_ranges.totalSize();
617 }
618
619 constexpr size_type linearize(const index_type & idx) const
620 {
621 return m_ranges.linearize(idx);
622 }
623
624 constexpr bool contains(const index_type& idx) const noexcept
625 {
626 return m_ranges.contains(idx) != -1;
627 }
628
629 constexpr size_type operator[](size_t index) const noexcept
630 {
631 return m_ranges.elementNum(index);
632 }
633
634 template <size_t Dim = 0>
635 constexpr size_type extent() const noexcept
636 {
637 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
638 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
639 }
640
641 constexpr index_type index_bounds() const noexcept
642 {
643 size_type extents[rank] = {};
644 m_ranges.serialize(extents);
645 return{ extents };
646 }
647
648 template <std::ptrdiff_t... Ranges>
649 constexpr bool operator == (const static_bounds<Ranges...>& rhs) const noexcept
650 {
651 return this->size() == rhs.size();
652 }
653
654 template <std::ptrdiff_t... Ranges>
655 constexpr bool operator != (const static_bounds<Ranges...>& rhs) const noexcept
656 {
657 return !(*this == rhs);
658 }
659
660 constexpr const_iterator begin() const noexcept
661 {
662 return const_iterator(*this, index_type{});
663 }
664
665 constexpr const_iterator end() const noexcept
666 {
667 return const_iterator(*this, this->index_bounds());
668 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700669};
670
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700671template <size_t Rank>
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700672class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700673{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800674 template <size_t OtherRank>
675 friend class strided_bounds;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700676
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700677public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800678 static const size_t rank = Rank;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700679 using value_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800680 using reference = std::add_lvalue_reference_t<value_type>;
681 using const_reference = std::add_const_t<reference>;
682 using size_type = value_type;
683 using difference_type = value_type;
684 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700685 using const_index_type = std::add_const_t<index_type>;
686 using iterator = bounds_iterator<const_index_type>;
687 using const_iterator = bounds_iterator<const_index_type>;
688 static const value_type dynamic_rank = rank;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800689 static const value_type static_size = dynamic_range;
690 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
691 using mapping_type = generalized_mapping_tag;
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700692
Neil MacIntosh68064d62015-11-03 19:17:11 -0800693 constexpr strided_bounds(const strided_bounds &) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700694
Vladislav Yaroslavlev557e6692015-11-12 10:44:41 +0300695 constexpr strided_bounds & operator=(const strided_bounds &) noexcept = default;
696
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700697 constexpr strided_bounds(const value_type(&values)[rank], index_type strides)
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700698 : m_extents(values), m_strides(std::move(strides))
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700699 {}
700
Neil MacIntosh68064d62015-11-03 19:17:11 -0800701 constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept
702 : m_extents(extents), m_strides(strides)
703 {}
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700704
Neil MacIntosh68064d62015-11-03 19:17:11 -0800705 constexpr index_type strides() const noexcept
706 {
707 return m_strides;
708 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700709
Neil MacIntosh68064d62015-11-03 19:17:11 -0800710 constexpr size_type total_size() const noexcept
711 {
712 size_type ret = 0;
713 for (size_t i = 0; i < rank; ++i)
714 {
715 ret += (m_extents[i] - 1) * m_strides[i];
716 }
717 return ret + 1;
718 }
719
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700720 constexpr size_type size() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800721 {
722 size_type ret = 1;
723 for (size_t i = 0; i < rank; ++i)
724 {
725 ret *= m_extents[i];
726 }
727 return ret;
728 }
729
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700730 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800731 {
732 for (size_t i = 0; i < rank; ++i)
733 {
734 if (idx[i] < 0 || idx[i] >= m_extents[i])
735 return false;
736 }
737 return true;
738 }
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700739
Neil MacIntosh68064d62015-11-03 19:17:11 -0800740 constexpr size_type linearize(const index_type& idx) const noexcept
741 {
742 size_type ret = 0;
743 for (size_t i = 0; i < rank; i++)
744 {
745 fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
746 ret += idx[i] * m_strides[i];
747 }
748 return ret;
749 }
750
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700751 constexpr size_type stride() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800752 {
753 return m_strides[0];
754 }
755
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700756 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800757 constexpr sliced_type slice() const
758 {
759 return{ details::shift_left(m_extents), details::shift_left(m_strides) };
760 }
761
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700762 template <size_t Dim = 0>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800763 constexpr size_type extent() const noexcept
764 {
765 static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
766 return m_extents[Dim];
767 }
768
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700769 constexpr index_type index_bounds() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800770 {
771 return m_extents;
772 }
773 constexpr const_iterator begin() const noexcept
774 {
775 return const_iterator{ *this, index_type{} };
776 }
777
778 constexpr const_iterator end() const noexcept
779 {
780 return const_iterator{ *this, index_bounds() };
781 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700782
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700783private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800784 index_type m_extents;
785 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700786};
787
788template <typename T>
789struct is_bounds : std::integral_constant<bool, false> {};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700790template <std::ptrdiff_t... Ranges>
791struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true> {};
792template <size_t Rank>
793struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700794
795template <typename IndexType>
Anna Gringauzea4654a42015-10-16 12:15:22 -0700796class bounds_iterator: public std::iterator<std::random_access_iterator_tag, IndexType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700797{
798private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800799 using Base = std::iterator <std::random_access_iterator_tag, IndexType>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700800
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700801public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800802 static const size_t rank = IndexType::rank;
803 using typename Base::reference;
804 using typename Base::pointer;
805 using typename Base::difference_type;
806 using typename Base::value_type;
807 using index_type = value_type;
808 using index_size_type = typename IndexType::value_type;
809 template <typename Bounds>
810 explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
811 : boundary(bnd.index_bounds()), curr(std::move(curr))
812 {
813 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
814 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700815
Neil MacIntosh68064d62015-11-03 19:17:11 -0800816 constexpr reference 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 pointer operator->() const noexcept
822 {
823 return &curr;
824 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700825
Neil MacIntosh68064d62015-11-03 19:17:11 -0800826 constexpr bounds_iterator& operator++() noexcept
827 {
828 for (size_t i = rank; i-- > 0;)
829 {
830 if (curr[i] < boundary[i] - 1)
831 {
832 curr[i]++;
833 return *this;
834 }
835 curr[i] = 0;
836 }
837 // If we're here we've wrapped over - set to past-the-end.
838 curr = boundary;
839 return *this;
840 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700841
Neil MacIntosh68064d62015-11-03 19:17:11 -0800842 constexpr bounds_iterator operator++(int) noexcept
843 {
844 auto ret = *this;
845 ++(*this);
846 return ret;
847 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700848
Neil MacIntosh68064d62015-11-03 19:17:11 -0800849 constexpr bounds_iterator& operator--() noexcept
850 {
851 if (!less(curr, boundary))
852 {
853 // if at the past-the-end, set to last element
854 for (size_t i = 0; i < rank; ++i)
855 {
856 curr[i] = boundary[i] - 1;
857 }
858 return *this;
859 }
860 for (size_t i = rank; i-- > 0;)
861 {
862 if (curr[i] >= 1)
863 {
864 curr[i]--;
865 return *this;
866 }
867 curr[i] = boundary[i] - 1;
868 }
869 // If we're here the preconditions were violated
870 // "pre: there exists s such that r == ++s"
871 fail_fast_assert(false);
872 return *this;
873 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700874
Neil MacIntosh68064d62015-11-03 19:17:11 -0800875 constexpr bounds_iterator operator--(int) noexcept
876 {
877 auto ret = *this;
878 --(*this);
879 return ret;
880 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700881
Neil MacIntosh68064d62015-11-03 19:17:11 -0800882 constexpr bounds_iterator operator+(difference_type n) const noexcept
883 {
884 bounds_iterator ret{ *this };
885 return ret += n;
886 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700887
Neil MacIntosh68064d62015-11-03 19:17:11 -0800888 constexpr bounds_iterator& operator+=(difference_type n) noexcept
889 {
890 auto linear_idx = linearize(curr) + n;
891 std::remove_const_t<value_type> stride = 0;
892 stride[rank - 1] = 1;
893 for (size_t i = rank - 1; i-- > 0;)
894 {
895 stride[i] = stride[i + 1] * boundary[i + 1];
896 }
897 for (size_t i = 0; i < rank; ++i)
898 {
899 curr[i] = linear_idx / stride[i];
900 linear_idx = linear_idx % stride[i];
901 }
902 fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "index is out of bounds of the array");
903 return *this;
904 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700905
Neil MacIntosh68064d62015-11-03 19:17:11 -0800906 constexpr bounds_iterator operator-(difference_type n) const noexcept
907 {
908 bounds_iterator ret{ *this };
909 return ret -= n;
910 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700911
Neil MacIntosh68064d62015-11-03 19:17:11 -0800912 constexpr bounds_iterator& operator-=(difference_type n) noexcept
913 {
914 return *this += -n;
915 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700916
Neil MacIntosh68064d62015-11-03 19:17:11 -0800917 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
918 {
919 return linearize(curr) - linearize(rhs.curr);
920 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700921
Neil MacIntosh68064d62015-11-03 19:17:11 -0800922 constexpr value_type operator[](difference_type n) const noexcept
923 {
924 return *(*this + n);
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 curr == rhs.curr;
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 !(*this == rhs);
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 less(curr, rhs.curr);
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 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept
953 {
954 return !(rhs > *this);
955 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700956
Neil MacIntosh68064d62015-11-03 19:17:11 -0800957 void swap(bounds_iterator& rhs) noexcept
958 {
959 std::swap(boundary, rhs.boundary);
960 std::swap(curr, rhs.curr);
961 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700962private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800963 constexpr bool less(index_type& one, index_type& other) const noexcept
964 {
965 for (size_t i = 0; i < rank; ++i)
966 {
967 if (one[i] < other[i])
968 return true;
969 }
970 return false;
971 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700972
Neil MacIntosh68064d62015-11-03 19:17:11 -0800973 constexpr index_size_type linearize(const value_type& idx) const noexcept
974 {
975 // TODO: Smarter impl.
976 // Check if past-the-end
977 index_size_type multiplier = 1;
978 index_size_type res = 0;
979 if (!less(idx, boundary))
980 {
981 res = 1;
982 for (size_t i = rank; i-- > 0;)
983 {
984 res += (idx[i] - 1) * multiplier;
985 multiplier *= boundary[i];
986 }
987 }
988 else
989 {
990 for (size_t i = rank; i-- > 0;)
991 {
992 res += idx[i] * multiplier;
993 multiplier *= boundary[i];
994 }
995 }
996 return res;
997 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700998
Neil MacIntosh68064d62015-11-03 19:17:11 -0800999 value_type boundary;
1000 std::remove_const_t<value_type> curr;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001001};
1002
1003template <typename IndexType>
Neil MacIntoshd5316802015-09-30 21:54:08 -07001004bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001005{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001006 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001007}
1008
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001009//
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001010// begin definitions of basic_span
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001011//
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001012namespace details
1013{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001014 template <typename Bounds>
1015 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
1016 {
1017 return bnd.strides();
1018 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001019
Neil MacIntosh68064d62015-11-03 19:17:11 -08001020 // Make a stride vector from bounds, assuming contiguous memory.
1021 template <typename Bounds>
1022 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
1023 {
1024 auto extents = bnd.index_bounds();
1025 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001026
Neil MacIntosh68064d62015-11-03 19:17:11 -08001027 stride[Bounds::rank - 1] = 1;
1028 for (size_t i = 1; i < Bounds::rank; ++i)
1029 {
1030 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
1031 }
1032 return{ stride };
1033 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001034
Neil MacIntosh68064d62015-11-03 19:17:11 -08001035 template <typename BoundsSrc, typename BoundsDest>
1036 void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
1037 {
1038 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
1039 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
1040 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");
1041 fail_fast_assert(src.size() == dest.size());
1042 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001043
1044
1045} // namespace details
1046
Anna Gringauze8aa42482015-11-11 12:41:11 -08001047template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001048class contiguous_span_iterator;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001049template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001050class general_span_iterator;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001051enum class byte : std::uint8_t {};
1052
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001053template <std::ptrdiff_t DimSize = dynamic_range>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001054struct dim
1055{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001056 static const std::ptrdiff_t value = DimSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001057};
1058template <>
1059struct dim<dynamic_range>
1060{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001061 static const std::ptrdiff_t value = dynamic_range;
1062 const std::ptrdiff_t dvalue;
1063 dim(std::ptrdiff_t size) : dvalue(size) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001064};
1065
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001066template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range, std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001067class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001068
1069template <typename ValueType, size_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001070class strided_span;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001071
1072namespace details
1073{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001074 template <typename T, typename = std::true_type>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001075 struct SpanTypeTraits
Neil MacIntosh68064d62015-11-03 19:17:11 -08001076 {
1077 using value_type = T;
1078 using size_type = size_t;
1079 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001080
Neil MacIntosh68064d62015-11-03 19:17:11 -08001081 template <typename Traits>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001082 struct SpanTypeTraits<Traits, typename std::is_reference<typename Traits::span_traits &>::type>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001083 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001084 using value_type = typename Traits::span_traits::value_type;
1085 using size_type = typename Traits::span_traits::size_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001086 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001087
Neil MacIntosh68064d62015-11-03 19:17:11 -08001088 template <typename T, std::ptrdiff_t... Ranks>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001089 struct SpanArrayTraits {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001090 using type = span<T, Ranks...>;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001091 using value_type = T;
1092 using bounds_type = static_bounds<Ranks...>;
1093 using pointer = T*;
1094 using reference = T&;
1095 };
1096 template <typename T, std::ptrdiff_t N, std::ptrdiff_t... Ranks>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001097 struct SpanArrayTraits<T[N], Ranks...> : SpanArrayTraits<T, Ranks..., N> {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001098
Neil MacIntosh68064d62015-11-03 19:17:11 -08001099 template <typename BoundsType>
1100 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
1101 {
1102 fail_fast_assert(totalSize <= PTRDIFF_MAX);
1103 return BoundsType{totalSize};
1104 }
1105 template <typename BoundsType>
1106 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
1107 {
1108 fail_fast_assert(BoundsType::static_size == totalSize);
1109 return {};
1110 }
1111 template <typename BoundsType>
1112 BoundsType newBoundsHelper(std::ptrdiff_t totalSize)
1113 {
1114 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
1115 return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
1116 }
1117
1118 struct Sep{};
1119
1120 template <typename T, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001121 T static_as_span_helper(Sep, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001122 {
1123 return T{static_cast<typename T::size_type>(args)...};
1124 }
1125 template <typename T, typename Arg, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001126 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 -08001127 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001128 return static_as_span_helper<T>(args...);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001129 }
1130 template <typename T, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001131 T static_as_span_helper(dim<dynamic_range> val, Args ... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001132 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001133 return static_as_span_helper<T>(args..., val.dvalue);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001134 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001135
Neil MacIntosh68064d62015-11-03 19:17:11 -08001136 template <typename ...Dimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001137 struct static_as_span_static_bounds_helper
Neil MacIntosh68064d62015-11-03 19:17:11 -08001138 {
1139 using type = static_bounds<(Dimensions::value)...>;
1140 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001141
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001142 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001143 struct is_span_oracle : std::false_type
Neil MacIntosh68064d62015-11-03 19:17:11 -08001144 {};
1145
1146 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001147 struct is_span_oracle<span<ValueType, FirstDimension, RestDimensions...>> : std::true_type
Neil MacIntosh68064d62015-11-03 19:17:11 -08001148 {};
1149
1150 template <typename ValueType, std::ptrdiff_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001151 struct is_span_oracle<strided_span<ValueType, Rank>> : std::true_type
Neil MacIntosh68064d62015-11-03 19:17:11 -08001152 {};
1153
1154 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001155 struct is_span : is_span_oracle<std::remove_cv_t<T>>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001156 {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001157
1158}
1159
1160
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001161template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001162class span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001163{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001164 template <typename ValueType2, std::ptrdiff_t FirstDimension2, std::ptrdiff_t... RestDimensions2>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001165 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001166
Anna Gringauze8aa42482015-11-11 12:41:11 -08001167public:
Anna Gringauzef5100252015-11-12 12:48:49 -08001168 using bounds_type = static_bounds<FirstDimension, RestDimensions...>;
1169 static const size_t rank = bounds_type::rank;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001170 using size_type = typename bounds_type::size_type;
1171 using index_type = typename bounds_type::index_type;
1172 using value_type = ValueType;
1173 using const_value_type = std::add_const_t<value_type>;
Anna Gringauzef5100252015-11-12 12:48:49 -08001174 using pointer = std::add_pointer_t<value_type>;
1175 using reference = std::add_lvalue_reference_t<value_type>;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001176 using iterator = contiguous_span_iterator<span>;
1177 using const_span = span<const_value_type, FirstDimension, RestDimensions...>;
1178 using const_iterator = contiguous_span_iterator<const_span>;
1179 using reverse_iterator = std::reverse_iterator<iterator>;
1180 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1181 using sliced_type = std::conditional_t<rank == 1, value_type, span<value_type, RestDimensions...>>;
1182
1183private:
1184 pointer m_pdata;
1185 bounds_type m_bounds;
1186
1187 friend iterator;
1188 friend const_iterator;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001189
1190public:
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001191
Anna Gringauzef5100252015-11-12 12:48:49 -08001192 constexpr span(pointer data, bounds_type bounds) noexcept
1193 : m_pdata(data), m_bounds(std::move(bounds))
Anna Gringauze8aa42482015-11-11 12:41:11 -08001194 {
1195 fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
1196 }
1197
Anna Gringauzef5100252015-11-12 12:48:49 -08001198 constexpr span(pointer ptr, size_type size) noexcept
1199 : span(ptr, bounds_type{ size })
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001200 {}
1201
Anna Gringauzef5100252015-11-12 12:48:49 -08001202 constexpr span(std::nullptr_t) noexcept
1203 : span(nullptr, bounds_type{})
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001204 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001205
Anna Gringauzef5100252015-11-12 12:48:49 -08001206 constexpr span(std::nullptr_t, size_type size) noexcept
1207 : span(nullptr, bounds_type{})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001208 {
1209 fail_fast_assert(size == 0);
1210 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001211
Neil MacIntosh68064d62015-11-03 19:17:11 -08001212 // default
1213 template <std::ptrdiff_t DynamicRank = bounds_type::dynamic_rank, typename = std::enable_if_t<DynamicRank != 0>>
Anna Gringauzef5100252015-11-12 12:48:49 -08001214 constexpr span() noexcept
1215 : span(nullptr, bounds_type())
Neil MacIntosh68064d62015-11-03 19:17:11 -08001216 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001217
Neil MacIntosh68064d62015-11-03 19:17:11 -08001218 // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
Anna Gringauzef5100252015-11-12 12:48:49 -08001219 template <typename T, typename Helper = details::SpanArrayTraits<T, dynamic_range>,
1220 typename Dummy = std::enable_if_t<std::is_same<value_type, std::remove_all_extents_t<T>>::value>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001221 /*typename Dummy = std::enable_if_t<std::is_convertible<Helper::value_type (*)[], value_type (*)[]>::value>*/
1222 >
Anna Gringauzef5100252015-11-12 12:48:49 -08001223 constexpr span(T* const& data, size_type size) : span(reinterpret_cast<pointer>(data), typename Helper::bounds_type{size})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001224 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001225
Neil MacIntosh68064d62015-11-03 19:17:11 -08001226 // from n-dimensions static array
Anna Gringauze8aa42482015-11-11 12:41:11 -08001227 template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>,
1228 typename = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value>
1229 >
Anna Gringauzef5100252015-11-12 12:48:49 -08001230 constexpr span (T (&arr)[N]) : span(reinterpret_cast<pointer>(arr), typename Helper::bounds_type())
Neil MacIntosh68064d62015-11-03 19:17:11 -08001231 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001232
Neil MacIntosh68064d62015-11-03 19:17:11 -08001233 // from n-dimensions static array with size
Anna Gringauze8aa42482015-11-11 12:41:11 -08001234 template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>,
1235 typename = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001236 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001237 constexpr span(T(&arr)[N], size_type size) : span(arr, typename Helper::bounds_type{size})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001238 {
1239 fail_fast_assert(size <= N);
1240 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001241
Neil MacIntosh68064d62015-11-03 19:17:11 -08001242 // from std array
1243 template <size_t N,
Anna Gringauze8aa42482015-11-11 12:41:11 -08001244 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, bounds_type>::value>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001245 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001246 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 -08001247 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001248
Neil MacIntosh68064d62015-11-03 19:17:11 -08001249 template <size_t N,
Anna Gringauze8aa42482015-11-11 12:41:11 -08001250 typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, bounds_type>::value
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001251 && std::is_const<value_type>::value>
1252 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001253 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 -08001254 {}
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001255
Neil MacIntosh68064d62015-11-03 19:17:11 -08001256 // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
1257 template <typename Ptr,
1258 typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
Anna Gringauze8aa42482015-11-11 12:41:11 -08001259 && details::LessThan<bounds_type::dynamic_rank, 2>::value>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001260 > // remove literal 0 case
Anna Gringauze8aa42482015-11-11 12:41:11 -08001261 constexpr span (pointer begin, Ptr end) : span(begin, details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001262 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001263
Neil MacIntosh68064d62015-11-03 19:17:11 -08001264 // from containers. It must has .size() and .data() two function signatures
1265 template <typename Cont, typename DataType = typename Cont::value_type,
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001266 typename Dummy = std::enable_if_t<!details::is_span<Cont>::value
Anna Gringauze8aa42482015-11-11 12:41:11 -08001267 && std::is_convertible<DataType (*)[], value_type (*)[]>::value
Neil MacIntosh68064d62015-11-03 19:17:11 -08001268 && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
1269 >
Anna Gringauze8aa42482015-11-11 12:41:11 -08001270 constexpr span (Cont& cont) : span(static_cast<pointer>(cont.data()), details::newBoundsHelper<bounds_type>(cont.size()))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001271 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001272
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001273 constexpr span(const span &) = default;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001274
Neil MacIntosh68064d62015-11-03 19:17:11 -08001275 // convertible
1276 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
Anna Gringauze8aa42482015-11-11 12:41:11 -08001277 typename OtherBounds = static_bounds<OtherDimensions...>,
1278 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 -08001279 >
Anna Gringauzef5100252015-11-12 12:48:49 -08001280 constexpr span(const span<OtherValueType, OtherDimensions...>& other) noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001281 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001282 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001283
Neil MacIntosh68064d62015-11-03 19:17:11 -08001284 // reshape
Neil MacIntosh14d50a62015-11-03 12:44:09 -08001285 // DimCount here is a workaround for a bug in MSVC 2015
Anna Gringauzef5100252015-11-12 12:48:49 -08001286 template <typename... Dimensions2, size_t DimCount = sizeof...(Dimensions2), bool Enabled = (DimCount > 0), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001287 constexpr span<ValueType, Dimensions2::value...> as_span(Dimensions2... dims)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001288 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001289 using BoundsType = typename span<ValueType, (Dimensions2::value)...>::bounds_type;
1290 auto tobounds = details::static_as_span_helper<BoundsType>(dims..., details::Sep{});
Neil MacIntosh68064d62015-11-03 19:17:11 -08001291 details::verifyBoundsReshape(this->bounds(), tobounds);
1292 return {this->data(), tobounds};
1293 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001294
Neil MacIntosh68064d62015-11-03 19:17:11 -08001295 // to bytes array
1296 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001297 auto as_bytes() const noexcept -> span<const byte>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001298 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001299 static_assert(Enabled, "The value_type of span must be standarded layout");
Neil MacIntosh68064d62015-11-03 19:17:11 -08001300 return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
1301 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001302
Neil MacIntosh68064d62015-11-03 19:17:11 -08001303 template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001304 auto as_writeable_bytes() const noexcept -> span<byte>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001305 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001306 static_assert(Enabled, "The value_type of span must be standarded layout");
Neil MacIntosh68064d62015-11-03 19:17:11 -08001307 return { reinterpret_cast<byte*>(this->data()), this->bytes() };
1308 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001309
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001310 // from bytes array
Neil MacIntosh68064d62015-11-03 19:17:11 -08001311 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 -08001312 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 -08001313 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001314 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 -08001315 "Target type must be standard layout and its size must match the byte array size");
1316 fail_fast_assert((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX);
1317 return { reinterpret_cast<const U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
1318 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001319
Neil MacIntosh68064d62015-11-03 19:17:11 -08001320 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 -08001321 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 -08001322 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001323 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 -08001324 "Target type must be standard layout and its size must match the byte array size");
1325 fail_fast_assert((this->bytes() % sizeof(U)) == 0);
1326 return { reinterpret_cast<U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
1327 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001328
Neil MacIntosh68064d62015-11-03 19:17:11 -08001329 // section on linear space
1330 template<std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001331 constexpr span<ValueType, Count> first() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001332 {
1333 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1334 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size()); // ensures we only check condition when needed
1335 return { this->data(), Count };
1336 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001337
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001338 constexpr span<ValueType, dynamic_range> first(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001339 {
1340 fail_fast_assert(count <= this->size());
1341 return { this->data(), count };
1342 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001343
Neil MacIntosh68064d62015-11-03 19:17:11 -08001344 template<std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001345 constexpr span<ValueType, Count> last() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001346 {
1347 static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
1348 fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
1349 return { this->data() + this->size() - Count, Count };
1350 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001351
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001352 constexpr span<ValueType, dynamic_range> last(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001353 {
1354 fail_fast_assert(count <= this->size());
1355 return { this->data() + this->size() - count, count };
1356 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001357
Neil MacIntosh68064d62015-11-03 19:17:11 -08001358 template<std::ptrdiff_t Offset, std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001359 constexpr span<ValueType, Count> sub() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001360 {
1361 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");
1362 fail_fast_assert(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
1363 return { this->data() + Offset, Count };
1364 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001365
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001366 constexpr span<ValueType, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001367 {
1368 fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
1369 return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
1370 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001371
Neil MacIntosh68064d62015-11-03 19:17:11 -08001372 // size
1373 constexpr size_type length() const noexcept
1374 {
1375 return this->size();
1376 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001377
Neil MacIntosh68064d62015-11-03 19:17:11 -08001378 constexpr size_type used_length() const noexcept
1379 {
1380 return length();
1381 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001382
Neil MacIntosh68064d62015-11-03 19:17:11 -08001383 constexpr size_type bytes() const noexcept
1384 {
1385 return sizeof(value_type) * this->size();
1386 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001387
Neil MacIntosh68064d62015-11-03 19:17:11 -08001388 constexpr size_type used_bytes() const noexcept
1389 {
1390 return bytes();
1391 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001392
Neil MacIntosh68064d62015-11-03 19:17:11 -08001393 // section
Anna Gringauzef5100252015-11-12 12:48:49 -08001394 constexpr strided_span<ValueType, rank> section(index_type origin, index_type extents) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001395 {
1396 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauze8aa42482015-11-11 12:41:11 -08001397 return{ &this->operator[](origin), size, strided_bounds<rank> {extents, details::make_stride(bounds())} };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001398 }
1399
Anna Gringauzef5100252015-11-12 12:48:49 -08001400 constexpr reference operator[](const index_type& idx) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001401 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001402 return m_pdata[m_bounds.linearize(idx)];
Neil MacIntosh68064d62015-11-03 19:17:11 -08001403 }
1404
Anna Gringauze8aa42482015-11-11 12:41:11 -08001405 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Anna Gringauzef5100252015-11-12 12:48:49 -08001406 constexpr Ret operator[](size_type idx) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001407 {
Anna Gringauze8aa42482015-11-11 12:41:11 -08001408 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
1409 const size_type ridx = idx * m_bounds.stride();
1410
1411 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
1412 return Ret{ m_pdata + ridx, m_bounds.slice() };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001413 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001414
Anna Gringauze8aa42482015-11-11 12:41:11 -08001415 constexpr bounds_type bounds() const noexcept
1416 {
1417 return m_bounds;
1418 }
1419
1420 template <size_t Dim = 0>
1421 constexpr size_type extent() const noexcept
1422 {
1423 static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
1424 return m_bounds.template extent<Dim>();
1425 }
1426
1427 constexpr size_type size() const noexcept
1428 {
1429 return m_bounds.size();
1430 }
1431
1432 constexpr pointer data() const noexcept
1433 {
1434 return m_pdata;
1435 }
1436
1437 constexpr operator bool() const noexcept
1438 {
1439 return m_pdata != nullptr;
1440 }
1441
Anna Gringauzef5100252015-11-12 12:48:49 -08001442 constexpr iterator begin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001443 {
1444 return iterator{ this, true };
1445 }
1446
Anna Gringauzef5100252015-11-12 12:48:49 -08001447 constexpr iterator end() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001448 {
1449 return iterator{ this, false };
1450 }
1451
Anna Gringauzef5100252015-11-12 12:48:49 -08001452 constexpr const_iterator cbegin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001453 {
1454 return const_iterator{ reinterpret_cast<const const_span*>(this), true };
1455 }
1456
Anna Gringauzef5100252015-11-12 12:48:49 -08001457 constexpr const_iterator cend() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001458 {
1459 return const_iterator{ reinterpret_cast<const const_span*>(this), false };
1460 }
1461
Anna Gringauzef5100252015-11-12 12:48:49 -08001462 constexpr reverse_iterator rbegin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001463 {
1464 return reverse_iterator{ end() };
1465 }
1466
Anna Gringauzef5100252015-11-12 12:48:49 -08001467 constexpr reverse_iterator rend() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001468 {
1469 return reverse_iterator{ begin() };
1470 }
1471
Anna Gringauzef5100252015-11-12 12:48:49 -08001472 constexpr const_reverse_iterator crbegin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001473 {
1474 return const_reverse_iterator{ cend() };
1475 }
1476
Anna Gringauzef5100252015-11-12 12:48:49 -08001477 constexpr const_reverse_iterator crend() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001478 {
1479 return const_reverse_iterator{ cbegin() };
1480 }
1481
1482 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>>
1483 constexpr bool operator== (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1484 {
1485 return m_bounds.size() == other.m_bounds.size() &&
1486 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
1487 }
1488
1489 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>>
1490 constexpr bool operator!= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1491 {
1492 return !(*this == other);
1493 }
1494
1495 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>>
1496 constexpr bool operator< (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1497 {
1498 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1499 }
1500
1501 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>>
1502 constexpr bool operator<= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1503 {
1504 return !(other < *this);
1505 }
1506
1507 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>>
1508 constexpr bool operator> (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1509 {
1510 return (other < *this);
1511 }
1512
1513 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>>
1514 constexpr bool operator>= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
1515 {
1516 return !(*this < other);
1517 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001518};
1519
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001520template <typename T, std::ptrdiff_t... Dimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001521constexpr auto as_span(T* const& ptr, dim<Dimensions>... args) -> span<std::remove_all_extents_t<T>, Dimensions...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001522{
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001523 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 -07001524}
1525
1526template <typename T>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001527constexpr auto as_span (T* arr, std::ptrdiff_t len) -> typename details::SpanArrayTraits<T, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001528{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001529 return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001530}
1531
1532template <typename T, size_t N>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001533constexpr auto as_span (T (&arr)[N]) -> typename details::SpanArrayTraits<T, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001534{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001535 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001536}
1537
1538template <typename T, size_t N>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001539constexpr span<const T, N> as_span(const std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001540{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001541 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001542}
1543
1544template <typename T, size_t N>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001545constexpr span<const T, N> as_span(const std::array<T, N> &&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001546
1547template <typename T, size_t N>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001548constexpr span<T, N> as_span(std::array<T, N> &arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001549{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001550 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001551}
1552
1553template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001554constexpr span<T, dynamic_range> as_span(T *begin, T *end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001555{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001556 return {begin, end};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001557}
1558
1559template <typename Cont>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001560constexpr auto as_span(Cont &arr) -> std::enable_if_t<!details::is_span<std::decay_t<Cont>>::value,
1561 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001562{
Neil MacIntoshace9ab92015-10-23 19:49:17 -07001563 fail_fast_assert(arr.size() < PTRDIFF_MAX);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001564 return {arr.data(), static_cast<std::ptrdiff_t>(arr.size())};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001565}
1566
1567template <typename Cont>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001568constexpr auto as_span(Cont &&arr) -> std::enable_if_t<!details::is_span<std::decay_t<Cont>>::value,
1569 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001570
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001571template <typename ValueType, size_t Rank>
Anna Gringauzef5100252015-11-12 12:48:49 -08001572class strided_span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001573{
Anna Gringauzef5100252015-11-12 12:48:49 -08001574public:
1575 using bounds_type = strided_bounds<Rank>;
1576 using size_type = typename bounds_type::size_type;
1577 using index_type = typename bounds_type::index_type;
1578 using value_type = ValueType;
1579 using const_value_type = std::add_const_t<value_type>;
1580 using pointer = std::add_pointer_t<value_type>;
1581 using reference = std::add_lvalue_reference_t<value_type>;
1582 using iterator = general_span_iterator<strided_span>;
1583 using const_strided_span = strided_span<const_value_type, Rank>;
1584 using const_iterator = general_span_iterator<const_strided_span>;
1585 using reverse_iterator = std::reverse_iterator<iterator>;
1586 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
1587 using sliced_type = std::conditional_t<Rank == 1, value_type, strided_span<value_type, Rank-1>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001588
Anna Gringauzef5100252015-11-12 12:48:49 -08001589private:
1590 pointer m_pdata;
1591 bounds_type m_bounds;
1592
1593 friend iterator;
1594 friend const_iterator;
1595 template <typename OtherValueType, size_t OtherRank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001596 friend class strided_span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001597
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001598public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001599 // from raw data
Anna Gringauzef5100252015-11-12 12:48:49 -08001600 constexpr strided_span(pointer ptr, size_type size, bounds_type bounds)
1601 : m_pdata(ptr), m_bounds(std::move(bounds))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001602 {
Anna Gringauzef5100252015-11-12 12:48:49 -08001603 fail_fast_assert((m_bounds.size() > 0 && ptr != nullptr) || m_bounds.size() == 0);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001604 fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
1605 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001606
Anna Gringauzef5100252015-11-12 12:48:49 -08001607 // from static array of size N
1608 template<size_type N>
1609 constexpr strided_span(value_type(&values)[N], bounds_type bounds) : strided_span(values, N, std::move(bounds))
1610 {}
1611
Neil MacIntosh68064d62015-11-03 19:17:11 -08001612 // from array view
1613 template <std::ptrdiff_t... Dimensions, typename Dummy = std::enable_if<sizeof...(Dimensions) == Rank>>
Anna Gringauzef5100252015-11-12 12:48:49 -08001614 constexpr strided_span(span<ValueType, Dimensions...> av, bounds_type bounds) : strided_span(av.data(), av.bounds().total_size(), std::move(bounds))
1615 {}
Neil MacIntosh68064d62015-11-03 19:17:11 -08001616
1617 // convertible
1618 template <typename OtherValueType,
Anna Gringauzef5100252015-11-12 12:48:49 -08001619 typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001620 >
Anna Gringauzef5100252015-11-12 12:48:49 -08001621 constexpr strided_span(const strided_span<OtherValueType, Rank>& other)
1622 : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001623 {}
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001624
Neil MacIntosh68064d62015-11-03 19:17:11 -08001625 // convert from bytes
Anna Gringauzef5100252015-11-12 12:48:49 -08001626 template <typename OtherValueType>
1627 constexpr 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 -08001628 {
1629 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
1630 auto d = static_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001631
Neil MacIntosh68064d62015-11-03 19:17:11 -08001632 size_type size = this->bounds().total_size() / d;
1633 return{ (OtherValueType*)this->data(), size, bounds_type{ resize_extent(this->bounds().index_bounds(), d), resize_stride(this->bounds().strides(), d)} };
1634 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001635
Anna Gringauzef5100252015-11-12 12:48:49 -08001636 constexpr strided_span section(index_type origin, index_type extents) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001637 {
1638 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Anna Gringauzef5100252015-11-12 12:48:49 -08001639 return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(bounds())}};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001640 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001641
Neil MacIntosh68064d62015-11-03 19:17:11 -08001642 constexpr reference operator[](const index_type& idx) const
1643 {
Anna Gringauzef5100252015-11-12 12:48:49 -08001644 return m_pdata[m_bounds.linearize(idx)];
Neil MacIntosh68064d62015-11-03 19:17:11 -08001645 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001646
Anna Gringauzef5100252015-11-12 12:48:49 -08001647 template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
1648 constexpr Ret operator[](size_type idx) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001649 {
Anna Gringauzef5100252015-11-12 12:48:49 -08001650 fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
1651 const size_type ridx = idx * m_bounds.stride();
1652
1653 fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
1654 return{ m_pdata + ridx, m_bounds.slice().total_size(), m_bounds.slice() };
1655 }
1656
1657 constexpr bounds_type bounds() const noexcept
1658 {
1659 return m_bounds;
1660 }
1661
1662 template <size_t Dim = 0>
1663 constexpr size_type extent() const noexcept
1664 {
1665 static_assert(Dim < Rank, "dimension should be less than Rank (dimension count starts from 0)");
1666 return m_bounds.template extent<Dim>();
1667 }
1668
1669 constexpr size_type size() const noexcept
1670 {
1671 return m_bounds.size();
1672 }
1673
1674 constexpr pointer data() const noexcept
1675 {
1676 return m_pdata;
1677 }
1678
1679 constexpr operator bool() const noexcept
1680 {
1681 return m_pdata != nullptr;
1682 }
1683
1684 constexpr iterator begin() const
1685 {
1686 return iterator{ this, true };
1687 }
1688
1689 constexpr iterator end() const
1690 {
1691 return iterator{ this, false };
1692 }
1693
1694 constexpr const_iterator cbegin() const
1695 {
1696 return const_iterator{ reinterpret_cast<const const_strided_span*>(this), true };
1697 }
1698
1699 constexpr const_iterator cend() const
1700 {
1701 return const_iterator{ reinterpret_cast<const const_strided_span*>(this), false };
1702 }
1703
1704 constexpr reverse_iterator rbegin() const
1705 {
1706 return reverse_iterator{ end() };
1707 }
1708
1709 constexpr reverse_iterator rend() const
1710 {
1711 return reverse_iterator{ begin() };
1712 }
1713
1714 constexpr const_reverse_iterator crbegin() const
1715 {
1716 return const_reverse_iterator{ cend() };
1717 }
1718
1719 constexpr const_reverse_iterator crend() const
1720 {
1721 return const_reverse_iterator{ cbegin() };
1722 }
1723
1724 template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1725 constexpr bool operator== (const strided_span<OtherValueType, OtherRank>& other) const noexcept
1726 {
1727 return m_bounds.size() == other.m_bounds.size() &&
1728 (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
1729 }
1730
1731 template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1732 constexpr bool operator!= (const strided_span<OtherValueType, OtherRank>& other) const noexcept
1733 {
1734 return !(*this == other);
1735 }
1736
1737 template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1738 constexpr bool operator< (const strided_span<OtherValueType, OtherRank>& other) const noexcept
1739 {
1740 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1741 }
1742
1743 template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1744 constexpr bool operator<= (const strided_span<OtherValueType, OtherRank>& other) const noexcept
1745 {
1746 return !(other < *this);
1747 }
1748
1749 template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1750 constexpr bool operator> (const strided_span<OtherValueType, OtherRank>& other) const noexcept
1751 {
1752 return (other < *this);
1753 }
1754
1755 template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1756 constexpr bool operator>= (const strided_span<OtherValueType, OtherRank>& other) const noexcept
1757 {
1758 return !(*this < other);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001759 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001760
1761private:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001762 static index_type resize_extent(const index_type& extent, std::ptrdiff_t d)
1763 {
Anna Gringauzef5100252015-11-12 12:48:49 -08001764 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 -07001765
Neil MacIntosh68064d62015-11-03 19:17:11 -08001766 index_type ret = extent;
Anna Gringauzef5100252015-11-12 12:48:49 -08001767 ret[Rank - 1] /= d;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001768
Neil MacIntosh68064d62015-11-03 19:17:11 -08001769 return ret;
1770 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001771
Anna Gringauzef5100252015-11-12 12:48:49 -08001772 template <bool Enabled = (Rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001773 static index_type resize_stride(const index_type& strides, std::ptrdiff_t , void * = 0)
1774 {
Anna Gringauzef5100252015-11-12 12:48:49 -08001775 fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized");
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001776
Neil MacIntosh68064d62015-11-03 19:17:11 -08001777 return strides;
1778 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001779
Anna Gringauzef5100252015-11-12 12:48:49 -08001780 template <bool Enabled = (Rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001781 static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
1782 {
Anna Gringauzef5100252015-11-12 12:48:49 -08001783 fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized");
1784 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 -07001785
Anna Gringauzef5100252015-11-12 12:48:49 -08001786 for (size_t i = Rank - 1; i > 0; --i)
1787 {
1788 fail_fast_assert((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0), "Only strided arrays with regular strides can be resized");
1789 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001790
Neil MacIntosh68064d62015-11-03 19:17:11 -08001791 index_type ret = strides / d;
Anna Gringauzef5100252015-11-12 12:48:49 -08001792 ret[Rank - 1] = 1;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001793
Neil MacIntosh68064d62015-11-03 19:17:11 -08001794 return ret;
1795 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001796};
1797
Anna Gringauze8aa42482015-11-11 12:41:11 -08001798template <class Span>
1799class contiguous_span_iterator : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001800{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001801 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001802public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001803 using typename Base::reference;
1804 using typename Base::pointer;
1805 using typename Base::difference_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001806
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001807private:
Anna Gringauze8aa42482015-11-11 12:41:11 -08001808 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
1809 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001810
1811 pointer m_pdata;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001812 const Span* m_validator;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001813 void validateThis() const
1814 {
1815 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");
1816 }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001817 contiguous_span_iterator (const Span* container, bool isbegin) :
Neil MacIntosh68064d62015-11-03 19:17:11 -08001818 m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001819public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001820 reference operator*() const noexcept
1821 {
1822 validateThis();
1823 return *m_pdata;
1824 }
1825 pointer operator->() const noexcept
1826 {
1827 validateThis();
1828 return m_pdata;
1829 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001830 contiguous_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001831 {
1832 ++m_pdata;
1833 return *this;
1834 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001835 contiguous_span_iterator operator++(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001836 {
1837 auto ret = *this;
1838 ++(*this);
1839 return ret;
1840 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001841 contiguous_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001842 {
1843 --m_pdata;
1844 return *this;
1845 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001846 contiguous_span_iterator operator--(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001847 {
1848 auto ret = *this;
1849 --(*this);
1850 return ret;
1851 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001852 contiguous_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001853 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001854 contiguous_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001855 return ret += n;
1856 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001857 contiguous_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001858 {
1859 m_pdata += n;
1860 return *this;
1861 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001862 contiguous_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001863 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001864 contiguous_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001865 return ret -= n;
1866 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001867 contiguous_span_iterator& operator-=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001868 {
1869 return *this += -n;
1870 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001871 difference_type operator-(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001872 {
1873 fail_fast_assert(m_validator == rhs.m_validator);
1874 return m_pdata - rhs.m_pdata;
1875 }
1876 reference operator[](difference_type n) const noexcept
1877 {
1878 return *(*this + n);
1879 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001880 bool operator==(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001881 {
1882 fail_fast_assert(m_validator == rhs.m_validator);
1883 return m_pdata == rhs.m_pdata;
1884 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001885 bool operator!=(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001886 {
1887 return !(*this == rhs);
1888 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001889 bool operator<(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001890 {
1891 fail_fast_assert(m_validator == rhs.m_validator);
1892 return m_pdata < rhs.m_pdata;
1893 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001894 bool operator<=(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001895 {
1896 return !(rhs < *this);
1897 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001898 bool operator>(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001899 {
1900 return rhs < *this;
1901 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001902 bool operator>=(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001903 {
1904 return !(rhs > *this);
1905 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001906 void swap(contiguous_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001907 {
1908 std::swap(m_pdata, rhs.m_pdata);
1909 std::swap(m_validator, rhs.m_validator);
1910 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001911};
1912
Anna Gringauze8aa42482015-11-11 12:41:11 -08001913template <typename Span>
1914contiguous_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 -07001915{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001916 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001917}
1918
Anna Gringauze8aa42482015-11-11 12:41:11 -08001919template <typename Span>
1920class general_span_iterator : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001921{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001922 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001923public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001924 using typename Base::reference;
1925 using typename Base::pointer;
1926 using typename Base::difference_type;
1927 using typename Base::value_type;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001928private:
Anna Gringauzef5100252015-11-12 12:48:49 -08001929 template <typename ValueType, size_t Rank>
1930 friend class strided_span;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001931
Anna Gringauzef5100252015-11-12 12:48:49 -08001932 const Span* m_container;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001933 typename Span::bounds_type::iterator m_itr;
Anna Gringauzef5100252015-11-12 12:48:49 -08001934 general_span_iterator(const Span* container, bool isbegin) :
Neil MacIntosh68064d62015-11-03 19:17:11 -08001935 m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
1936 {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001937public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001938 reference operator*() noexcept
1939 {
1940 return (*m_container)[*m_itr];
1941 }
1942 pointer operator->() noexcept
1943 {
1944 return &(*m_container)[*m_itr];
1945 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001946 general_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001947 {
1948 ++m_itr;
1949 return *this;
1950 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001951 general_span_iterator operator++(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001952 {
1953 auto ret = *this;
1954 ++(*this);
1955 return ret;
1956 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001957 general_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001958 {
1959 --m_itr;
1960 return *this;
1961 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001962 general_span_iterator operator--(int)noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001963 {
1964 auto ret = *this;
1965 --(*this);
1966 return ret;
1967 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001968 general_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001969 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001970 general_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001971 return ret += n;
1972 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001973 general_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001974 {
1975 m_itr += n;
1976 return *this;
1977 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001978 general_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001979 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001980 general_span_iterator ret{ *this };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001981 return ret -= n;
1982 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001983 general_span_iterator& operator-=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001984 {
1985 return *this += -n;
1986 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001987 difference_type operator-(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001988 {
1989 fail_fast_assert(m_container == rhs.m_container);
1990 return m_itr - rhs.m_itr;
1991 }
1992 value_type operator[](difference_type n) const noexcept
1993 {
1994 return (*m_container)[m_itr[n]];;
1995 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001996 bool operator==(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001997 {
1998 fail_fast_assert(m_container == rhs.m_container);
1999 return m_itr == rhs.m_itr;
2000 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002001 bool operator !=(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002002 {
2003 return !(*this == rhs);
2004 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002005 bool operator<(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002006 {
2007 fail_fast_assert(m_container == rhs.m_container);
2008 return m_itr < rhs.m_itr;
2009 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002010 bool operator<=(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002011 {
2012 return !(rhs < *this);
2013 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002014 bool operator>(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002015 {
2016 return rhs < *this;
2017 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002018 bool operator>=(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002019 {
2020 return !(rhs > *this);
2021 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002022 void swap(general_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002023 {
2024 std::swap(m_itr, rhs.m_itr);
2025 std::swap(m_container, rhs.m_container);
2026 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002027};
2028
Anna Gringauze8aa42482015-11-11 12:41:11 -08002029template <typename Span>
2030general_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 -07002031{
Neil MacIntosh68064d62015-11-03 19:17:11 -08002032 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002033}
2034
Neil MacIntoshef626fd2015-09-29 16:41:37 -07002035} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002036
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002037
Neil MacIntoshd5316802015-09-30 21:54:08 -07002038#ifdef _MSC_VER
2039
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002040#undef constexpr
2041#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002042
Neil MacIntoshd5316802015-09-30 21:54:08 -07002043#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002044#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07002045
2046#ifndef GSL_THROWS_FOR_TESTING
Lukas Haselsteinere51eb222015-11-15 23:08:35 +01002047#undef noexcept
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002048#pragma pop_macro("noexcept")
Neil MacIntoshd5316802015-09-30 21:54:08 -07002049#endif // GSL_THROWS_FOR_TESTING
2050
Neil MacIntoshe9a96022015-11-03 18:56:55 -08002051#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
Neil MacIntoshe9a96022015-11-03 18:56:55 -08002052
Neil MacIntosh9a297122015-09-14 15:11:07 -07002053#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002054
Neil MacIntoshd5316802015-09-30 21:54:08 -07002055#endif // _MSC_VER
2056
2057#if defined(GSL_THROWS_FOR_TESTING)
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002058
Anna Gringauzef5100252015-11-12 12:48:49 -08002059#undef noexcept
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002060
2061#ifdef _MSC_VER
2062#pragma pop_macro("noexcept")
2063#endif
2064
Neil MacIntoshd5316802015-09-30 21:54:08 -07002065#endif // GSL_THROWS_FOR_TESTING
2066
Treb Connell51da1362015-09-24 18:08:34 -07002067
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002068#endif // GSL_SPAN_H