blob: a612983b28dd3fc1bfa53e3af863ac9169f41e9c [file] [log] [blame]
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001///////////////////////////////////////////////////////////////////////////////
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//
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070015///////////////////////////////////////////////////////////////////////////////
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
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080022#include "gsl_assert.h"
23#include "gsl_util.h"
Olaf van der Spek550361c2015-11-12 10:23:56 +010024#include <algorithm>
25#include <array>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080026#include <cassert>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070027#include <cstddef>
28#include <cstdint>
Olaf van der Spek550361c2015-11-12 10:23:56 +010029#include <functional>
30#include <iterator>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070031#include <limits>
Olaf van der Spek550361c2015-11-12 10:23:56 +010032#include <new>
Anna Gringauze2cdedda2015-10-15 13:19:24 -070033#include <numeric>
Olaf van der Spek550361c2015-11-12 10:23:56 +010034#include <stdexcept>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070035#include <type_traits>
36#include <utility>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070037
Neil MacIntoshd5316802015-09-30 21:54:08 -070038#ifdef _MSC_VER
39
Neil MacIntoshd13f6da2015-11-20 16:03:00 -080040#pragma warning(push)
Neil MacIntosha9f0ce22016-03-31 12:01:07 -070041
42// turn off some warnings that are noisy about our Expects statements
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080043#pragma warning(disable : 4127) // conditional expression is constant
Neil MacIntoshd13f6da2015-11-20 16:03:00 -080044
Neil MacIntosha9f0ce22016-03-31 12:01:07 -070045// blanket turn off warnings from CppCoreCheck for now
46// so people aren't annoyed by them when running the tool.
47// more targeted suppressions will be added in a future update to the GSL
48#pragma warning(disable: 26481 26482 26483 26485 26490 26491 26492 26493 26495)
49
Neil MacIntoshd5316802015-09-30 21:54:08 -070050// No MSVC does constexpr fully yet
Gabriel Dos Reis6554e832015-09-28 05:10:44 -070051#pragma push_macro("constexpr")
Neil MacIntoshd13f6da2015-11-20 16:03:00 -080052#define constexpr
Neil MacIntoshd5316802015-09-30 21:54:08 -070053
54// VS 2013 workarounds
55#if _MSC_VER <= 1800
56
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080057#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
58#define GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
Neil MacIntoshe9a96022015-11-03 18:56:55 -080059
Anna Gringauzee3878a62015-11-30 12:24:00 -080060// noexcept is not understood
61#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntosh292f81e2015-11-17 15:07:51 -080062#pragma push_macro("noexcept")
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080063#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070064#endif
65
Neil MacIntoshd5316802015-09-30 21:54:08 -070066// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070067#pragma warning(push)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080068#pragma warning(disable : 4351) // warns about newly introduced aggregate initializer behavior
69#pragma warning(disable : 4512) // warns that assignment op could not be generated
Neil MacIntoshd5316802015-09-30 21:54:08 -070070
Neil MacIntosh9a297122015-09-14 15:11:07 -070071#endif // _MSC_VER <= 1800
72
Neil MacIntoshd5316802015-09-30 21:54:08 -070073#endif // _MSC_VER
74
Neil MacIntoshd13f6da2015-11-20 16:03:00 -080075#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntosh292f81e2015-11-17 15:07:51 -080076
77#ifdef _MSC_VER
78#pragma push_macro("noexcept")
79#endif
80
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080081#define noexcept /* nothing */
Neil MacIntosh292f81e2015-11-17 15:07:51 -080082
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080083#endif // GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntoshd5316802015-09-30 21:54:08 -070084
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080085namespace gsl
86{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070087
88/*
89** begin definitions of index and bounds
90*/
91namespace details
92{
Neil MacIntosh68064d62015-11-03 19:17:11 -080093 template <typename SizeType>
94 struct SizeTypeTraits
95 {
96 static const SizeType max_value = std::numeric_limits<SizeType>::max();
97 };
Anna Gringauze1c208b32015-10-16 17:40:57 -070098
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080099 template <typename... Ts>
100 class are_integral : public std::integral_constant<bool, true>
101 {
102 };
Anna Gringauze1c208b32015-10-16 17:40:57 -0700103
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800104 template <typename T, typename... Ts>
105 class are_integral<T, Ts...>
106 : public std::integral_constant<bool,
107 std::is_integral<T>::value && are_integral<Ts...>::value>
108 {
109 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700110}
111
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700112template <size_t Rank>
Anna Gringauzedb384972015-10-05 12:34:23 -0700113class index final
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700114{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800115 static_assert(Rank > 0, "Rank must be greater than 0!");
Anna Gringauzedb384972015-10-05 12:34:23 -0700116
Neil MacIntosh68064d62015-11-03 19:17:11 -0800117 template <size_t OtherRank>
118 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -0700119
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700120public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800121 static const size_t rank = Rank;
122 using value_type = std::ptrdiff_t;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700123 using size_type = value_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800124 using reference = std::add_lvalue_reference_t<value_type>;
125 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700126
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800127 constexpr index() noexcept {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700128
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800129 constexpr index(const value_type (&values)[Rank]) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800130 {
131 std::copy(values, values + Rank, elems);
132 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700133
Anna Gringauze8aa42482015-11-11 12:41:11 -0800134#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800135 template <
136 typename T, typename... Ts,
137 typename = std::enable_if_t<((sizeof...(Ts) + 1) == Rank) && std::is_integral<T>::value &&
138 details::are_integral<Ts...>::value>>
139 constexpr index(T t, Ts... ds)
140 : index({narrow_cast<value_type>(t), narrow_cast<value_type>(ds)...})
141 {
142 }
Anna Gringauze8aa42482015-11-11 12:41:11 -0800143#else
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800144 template <typename... Ts, typename = std::enable_if_t<(sizeof...(Ts) == Rank) &&
145 details::are_integral<Ts...>::value>>
146 constexpr index(Ts... ds) noexcept : elems{narrow_cast<value_type>(ds)...}
147 {
148 }
Anna Gringauze8aa42482015-11-11 12:41:11 -0800149#endif
Anna Gringauzedb384972015-10-05 12:34:23 -0700150
Neil MacIntosh68064d62015-11-03 19:17:11 -0800151 constexpr index(const index& other) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700152
Neil MacIntosh68064d62015-11-03 19:17:11 -0800153 constexpr index& operator=(const index& rhs) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700154
Neil MacIntosh68064d62015-11-03 19:17:11 -0800155 // Preconditions: component_idx < rank
156 constexpr reference operator[](size_t component_idx)
157 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800158 Expects(component_idx < Rank); // Component index must be less than rank
Neil MacIntosh68064d62015-11-03 19:17:11 -0800159 return elems[component_idx];
160 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700161
Neil MacIntosh68064d62015-11-03 19:17:11 -0800162 // Preconditions: component_idx < rank
163 constexpr const_reference operator[](size_t component_idx) const noexcept
164 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800165 Expects(component_idx < Rank); // Component index must be less than rank
Neil MacIntosh68064d62015-11-03 19:17:11 -0800166 return elems[component_idx];
167 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700168
Neil MacIntosh68064d62015-11-03 19:17:11 -0800169 constexpr bool operator==(const index& rhs) const noexcept
170 {
171 return std::equal(elems, elems + rank, rhs.elems);
172 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700173
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800174 constexpr bool operator!=(const index& rhs) const noexcept { return !(this == rhs); }
Anna Gringauzedb384972015-10-05 12:34:23 -0700175
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800176 constexpr index operator+() const noexcept { return *this; }
Anna Gringauzedb384972015-10-05 12:34:23 -0700177
Neil MacIntosh68064d62015-11-03 19:17:11 -0800178 constexpr index operator-() const noexcept
179 {
180 index ret = *this;
181 std::transform(ret, ret + rank, ret, std::negate<value_type>{});
182 return ret;
183 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700184
Neil MacIntosh68064d62015-11-03 19:17:11 -0800185 constexpr index operator+(const index& rhs) const noexcept
186 {
187 index ret = *this;
188 ret += rhs;
189 return ret;
190 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700191
Neil MacIntosh68064d62015-11-03 19:17:11 -0800192 constexpr index operator-(const index& rhs) const noexcept
193 {
194 index ret = *this;
195 ret -= rhs;
196 return ret;
197 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700198
Neil MacIntosh68064d62015-11-03 19:17:11 -0800199 constexpr index& operator+=(const index& rhs) noexcept
200 {
201 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<value_type>{});
202 return *this;
203 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700204
Neil MacIntosh68064d62015-11-03 19:17:11 -0800205 constexpr index& operator-=(const index& rhs) noexcept
206 {
207 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<value_type>{});
208 return *this;
209 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700210
Neil MacIntosh68064d62015-11-03 19:17:11 -0800211 constexpr index operator*(value_type v) const noexcept
212 {
213 index ret = *this;
214 ret *= v;
215 return ret;
216 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700217
Neil MacIntosh68064d62015-11-03 19:17:11 -0800218 constexpr index operator/(value_type v) const noexcept
219 {
220 index ret = *this;
221 ret /= v;
222 return ret;
223 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700224
Neil MacIntosh68064d62015-11-03 19:17:11 -0800225 friend constexpr index operator*(value_type v, const index& rhs) noexcept
226 {
227 return rhs * v;
228 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700229
Neil MacIntosh68064d62015-11-03 19:17:11 -0800230 constexpr index& operator*=(value_type v) noexcept
231 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800232 std::transform(elems, elems + rank, elems,
233 [v](value_type x) { return std::multiplies<value_type>{}(x, v); });
Neil MacIntosh68064d62015-11-03 19:17:11 -0800234 return *this;
235 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700236
Neil MacIntosh68064d62015-11-03 19:17:11 -0800237 constexpr index& operator/=(value_type v) noexcept
238 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800239 std::transform(elems, elems + rank, elems,
240 [v](value_type x) { return std::divides<value_type>{}(x, v); });
Neil MacIntosh68064d62015-11-03 19:17:11 -0800241 return *this;
242 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700243
Anna Gringauzedb384972015-10-05 12:34:23 -0700244private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800245 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700246};
247
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700248#ifndef _MSC_VER
249
250struct static_bounds_dynamic_range_t
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700251{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800252 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
253 constexpr operator T() const noexcept
254 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800255 return narrow_cast<T>(-1);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800256 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700257
Neil MacIntosh68064d62015-11-03 19:17:11 -0800258 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800259 constexpr bool operator==(T other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800260 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800261 return narrow_cast<T>(-1) == other;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800262 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700263
Neil MacIntosh68064d62015-11-03 19:17:11 -0800264 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800265 constexpr bool operator!=(T other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800266 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800267 return narrow_cast<T>(-1) != other;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800268 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700269};
270
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700271template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800272constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700273{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800274 return right == left;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700275}
276
277template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800278constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700279{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800280 return right != left;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700281}
282
283constexpr static_bounds_dynamic_range_t dynamic_range{};
284#else
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700285const std::ptrdiff_t dynamic_range = -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700286#endif
287
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800288struct generalized_mapping_tag
289{
290};
291struct contiguous_mapping_tag : generalized_mapping_tag
292{
293};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700294
295namespace details
296{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700297
Neil MacIntosh68064d62015-11-03 19:17:11 -0800298 template <std::ptrdiff_t Left, std::ptrdiff_t Right>
299 struct LessThan
300 {
301 static const bool value = Left < Right;
302 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700303
Neil MacIntosh68064d62015-11-03 19:17:11 -0800304 template <std::ptrdiff_t... Ranges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800305 struct BoundsRanges
306 {
307 using size_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800308 static const size_type Depth = 0;
309 static const size_type DynamicNum = 0;
310 static const size_type CurrentRange = 1;
311 static const size_type TotalSize = 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700312
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700313 // TODO : following signature is for work around VS bug
314 template <typename OtherRange>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800315 BoundsRanges(const OtherRange&, bool /* firstLevel */)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800316 {
317 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700318
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800319 BoundsRanges(const BoundsRanges&) = default;
320 BoundsRanges& operator=(const BoundsRanges&) = default;
321 BoundsRanges(const std::ptrdiff_t* const) {}
322 BoundsRanges() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700323
Neil MacIntosh68064d62015-11-03 19:17:11 -0800324 template <typename T, size_t Dim>
325 void serialize(T&) const
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800326 {
327 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700328
Neil MacIntosh68064d62015-11-03 19:17:11 -0800329 template <typename T, size_t Dim>
330 size_type linearize(const T&) const
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800331 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800332 return 0;
333 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700334
Neil MacIntosh68064d62015-11-03 19:17:11 -0800335 template <typename T, size_t Dim>
Neil MacIntoshf76f7392015-11-30 18:20:14 -0800336 size_type contains(const T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700337 {
Neil MacIntoshf76f7392015-11-30 18:20:14 -0800338 return -1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800339 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700340
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800341 size_type elementNum(size_t) const noexcept { return 0; }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700342
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800343 size_type totalSize() const noexcept { return TotalSize; }
344
345 bool operator==(const BoundsRanges&) const noexcept { return true; }
Neil MacIntosh68064d62015-11-03 19:17:11 -0800346 };
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700347
Neil MacIntosh68064d62015-11-03 19:17:11 -0800348 template <std::ptrdiff_t... RestRanges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800349 struct BoundsRanges<dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>
350 {
351 using Base = BoundsRanges<RestRanges...>;
352 using size_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800353 static const size_t Depth = Base::Depth + 1;
354 static const size_t DynamicNum = Base::DynamicNum + 1;
355 static const size_type CurrentRange = dynamic_range;
356 static const size_type TotalSize = dynamic_range;
357 const size_type m_bound;
358
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800359 BoundsRanges(const BoundsRanges&) = default;
360
361 BoundsRanges(const std::ptrdiff_t* const arr)
362 : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
Neil MacIntosh68064d62015-11-03 19:17:11 -0800363 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800364 Expects(0 <= *arr);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800365 }
366
367 BoundsRanges() : m_bound(0) {}
368
369 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800370 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other,
371 bool /* firstLevel */ = true)
372 : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
373 , m_bound(other.totalSize())
374 {
375 }
Neil MacIntosh68064d62015-11-03 19:17:11 -0800376
377 template <typename T, size_t Dim = 0>
378 void serialize(T& arr) const
379 {
380 arr[Dim] = elementNum();
381 this->Base::template serialize<T, Dim + 1>(arr);
382 }
383
384 template <typename T, size_t Dim = 0>
385 size_type linearize(const T& arr) const
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800386 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800387 const size_type index = this->Base::totalSize() * arr[Dim];
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800388 Expects(index < m_bound);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800389 return index + this->Base::template linearize<T, Dim + 1>(arr);
390 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700391
Neil MacIntosh68064d62015-11-03 19:17:11 -0800392 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700393 size_type contains(const T& arr) const
394 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800395 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
396 if (last == -1) return -1;
397 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
398 return cur < m_bound ? cur + last : -1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800399 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700400
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800401 size_type totalSize() const noexcept { return m_bound; }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700402
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800403 size_type elementNum() const noexcept { return totalSize() / this->Base::totalSize(); }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700404
Neil MacIntosh68064d62015-11-03 19:17:11 -0800405 size_type elementNum(size_t dim) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700406 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800407 if (dim > 0)
408 return this->Base::elementNum(dim - 1);
409 else
410 return elementNum();
411 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700412
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800413 bool operator==(const BoundsRanges& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800414 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800415 return m_bound == rhs.m_bound &&
416 static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800417 }
418 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700419
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800420 template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
421 struct BoundsRanges<CurRange, RestRanges...> : BoundsRanges<RestRanges...>
422 {
423 using Base = BoundsRanges<RestRanges...>;
424 using size_type = std::ptrdiff_t;
425 static const size_t Depth = Base::Depth + 1;
426 static const size_t DynamicNum = Base::DynamicNum;
427 static const size_type CurrentRange = CurRange;
428 static const size_type TotalSize =
429 Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700430
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800431 BoundsRanges(const BoundsRanges&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700432
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800433 BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {}
434 BoundsRanges() = default;
435
436 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
437 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other,
438 bool firstLevel = true)
439 : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
440 {
441 (void) firstLevel;
442 }
443
444 template <typename T, size_t Dim = 0>
445 void serialize(T& arr) const
446 {
447 arr[Dim] = elementNum();
448 this->Base::template serialize<T, Dim + 1>(arr);
449 }
450
451 template <typename T, size_t Dim = 0>
452 size_type linearize(const T& arr) const
453 {
454 Expects(arr[Dim] < CurrentRange); // Index is out of range
455 return this->Base::totalSize() * arr[Dim] +
456 this->Base::template linearize<T, Dim + 1>(arr);
457 }
458
459 template <typename T, size_t Dim = 0>
460 size_type contains(const T& arr) const
461 {
462 if (arr[Dim] >= CurrentRange) return -1;
463 const size_type last = this->Base::template contains<T, Dim + 1>(arr);
464 if (last == -1) return -1;
465 return this->Base::totalSize() * arr[Dim] + last;
466 }
467
468 size_type totalSize() const noexcept { return CurrentRange * this->Base::totalSize(); }
469
470 size_type elementNum() const noexcept { return CurrentRange; }
471
472 size_type elementNum(size_t dim) const noexcept
473 {
474 if (dim > 0)
475 return this->Base::elementNum(dim - 1);
476 else
477 return elementNum();
478 }
479
480 bool operator==(const BoundsRanges& rhs) const noexcept
481 {
482 return static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
483 }
484 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700485
Neil MacIntosh68064d62015-11-03 19:17:11 -0800486 template <typename SourceType, typename TargetType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800487 struct BoundsRangeConvertible
488 : public std::integral_constant<bool, (SourceType::TotalSize >= TargetType::TotalSize ||
489 TargetType::TotalSize == dynamic_range ||
490 SourceType::TotalSize == dynamic_range ||
491 TargetType::TotalSize == 0)>
492 {
493 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700494
Neil MacIntosh68064d62015-11-03 19:17:11 -0800495 template <typename TypeChain>
496 struct TypeListIndexer
497 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800498 const TypeChain& obj_;
499 TypeListIndexer(const TypeChain& obj) : obj_(obj) {}
500
Neil MacIntosh68064d62015-11-03 19:17:11 -0800501 template <size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800502 const TypeChain& getObj(std::true_type)
503 {
504 return obj_;
505 }
506
507 template <size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
508 auto getObj(std::false_type)
509 -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>())
510 {
511 return TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>();
512 }
513
514 template <size_t N>
515 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, N == 0>()))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800516 {
517 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
518 }
519 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700520
Neil MacIntosh68064d62015-11-03 19:17:11 -0800521 template <typename TypeChain>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800522 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain& obj)
Neil MacIntosh68064d62015-11-03 19:17:11 -0800523 {
524 return TypeListIndexer<TypeChain>(obj);
525 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700526
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800527 template <size_t Rank, bool Enabled = (Rank > 1),
528 typename Ret = std::enable_if_t<Enabled, index<Rank - 1>>>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800529 constexpr Ret shift_left(const index<Rank>& other) noexcept
530 {
531 Ret ret{};
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800532 for (size_t i = 0; i < Rank - 1; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800533 ret[i] = other[i + 1];
534 }
535 return ret;
536 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700537}
538
539template <typename IndexType>
540class bounds_iterator;
541
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700542template <std::ptrdiff_t... Ranges>
543class static_bounds
544{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700545public:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800546 static_bounds(const details::BoundsRanges<Ranges...>&) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700547};
548
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700549template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
550class static_bounds<FirstRange, RestRanges...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700551{
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800552 using MyRanges = details::BoundsRanges<FirstRange, RestRanges...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700553
Neil MacIntosh68064d62015-11-03 19:17:11 -0800554 MyRanges m_ranges;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800555 constexpr static_bounds(const MyRanges& range) : m_ranges(range) {}
556
Neil MacIntosh68064d62015-11-03 19:17:11 -0800557 template <std::ptrdiff_t... OtherRanges>
558 friend class static_bounds;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700559
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700560public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800561 static const size_t rank = MyRanges::Depth;
562 static const size_t dynamic_rank = MyRanges::DynamicNum;
563 static const std::ptrdiff_t static_size = MyRanges::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700564
Neil MacIntosh68064d62015-11-03 19:17:11 -0800565 using size_type = std::ptrdiff_t;
566 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700567 using const_index_type = std::add_const_t<index_type>;
568 using iterator = bounds_iterator<const_index_type>;
569 using const_iterator = bounds_iterator<const_index_type>;
570 using difference_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800571 using sliced_type = static_bounds<RestRanges...>;
572 using mapping_type = contiguous_mapping_tag;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700573
Neil MacIntosh68064d62015-11-03 19:17:11 -0800574 constexpr static_bounds(const static_bounds&) = default;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800575
576 template <typename SourceType, typename TargetType, size_t Rank>
577 struct BoundsRangeConvertible2;
578
579 template <size_t Rank, typename SourceType, typename TargetType,
580 typename Ret = BoundsRangeConvertible2<typename SourceType::Base,
581 typename TargetType::Base, Rank>>
582 static auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
583
584 template <size_t Rank, typename SourceType, typename TargetType>
585 static auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
586
587 template <typename SourceType, typename TargetType, size_t Rank>
588 struct BoundsRangeConvertible2
589 : decltype(helpBoundsRangeConvertible<Rank - 1>(
590 SourceType(), TargetType(),
591 std::integral_constant<bool,
592 SourceType::Depth == TargetType::Depth &&
593 (SourceType::CurrentRange == TargetType::CurrentRange ||
594 TargetType::CurrentRange == dynamic_range ||
595 SourceType::CurrentRange == dynamic_range)>()))
596 {
597 };
598
599 template <typename SourceType, typename TargetType>
600 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type
601 {
602 };
603
604 template <typename SourceType, typename TargetType, std::ptrdiff_t Rank = TargetType::Depth>
605 struct BoundsRangeConvertible
606 : decltype(helpBoundsRangeConvertible<Rank - 1>(
607 SourceType(), TargetType(),
608 std::integral_constant<bool,
609 SourceType::Depth == TargetType::Depth &&
610 (!details::LessThan<SourceType::CurrentRange,
611 TargetType::CurrentRange>::value ||
612 TargetType::CurrentRange == dynamic_range ||
613 SourceType::CurrentRange == dynamic_range)>()))
614 {
615 };
616
617 template <typename SourceType, typename TargetType>
618 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type
619 {
620 };
621
622 template <std::ptrdiff_t... Ranges,
623 typename = std::enable_if_t<details::BoundsRangeConvertible<
624 details::BoundsRanges<Ranges...>,
625 details::BoundsRanges<FirstRange, RestRanges...>>::value>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700626 constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800627 {
628 Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges<Ranges...>::DynamicNum == 0) ||
629 MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize());
630 }
631
632 constexpr static_bounds(std::initializer_list<size_type> il)
633 : m_ranges(static_cast<const std::ptrdiff_t*>(il.begin()))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800634 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800635 // Size of the initializer list must match the rank of the array
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800636 Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) ||
637 MyRanges::DynamicNum == il.size());
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800638 // Size of the range must be less than the max element of the size type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800639 Expects(m_ranges.totalSize() <= PTRDIFF_MAX);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800640 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800641
Neil MacIntosh68064d62015-11-03 19:17:11 -0800642 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700643
Neil MacIntosh68064d62015-11-03 19:17:11 -0800644 constexpr static_bounds& operator=(const static_bounds& otherBounds)
645 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800646 new (&m_ranges) MyRanges(otherBounds.m_ranges);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800647 return *this;
648 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700649
Neil MacIntosh68064d62015-11-03 19:17:11 -0800650 constexpr sliced_type slice() const noexcept
651 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800652 return sliced_type{static_cast<const details::BoundsRanges<RestRanges...>&>(m_ranges)};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800653 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700654
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800655 constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700656
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800657 constexpr size_type size() const noexcept { return m_ranges.totalSize(); }
658
659 constexpr size_type total_size() const noexcept { return m_ranges.totalSize(); }
660
661 constexpr size_type linearize(const index_type& idx) const { return m_ranges.linearize(idx); }
662
Neil MacIntosh68064d62015-11-03 19:17:11 -0800663 constexpr bool contains(const index_type& idx) const noexcept
664 {
665 return m_ranges.contains(idx) != -1;
666 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800667
Neil MacIntosh68064d62015-11-03 19:17:11 -0800668 constexpr size_type operator[](size_t index) const noexcept
669 {
670 return m_ranges.elementNum(index);
671 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800672
Neil MacIntosh68064d62015-11-03 19:17:11 -0800673 template <size_t Dim = 0>
674 constexpr size_type extent() const noexcept
675 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800676 static_assert(Dim < rank,
677 "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosh68064d62015-11-03 19:17:11 -0800678 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
679 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800680
681 template <typename IntType>
682 constexpr size_type extent(IntType dim) const noexcept
683 {
684 static_assert(std::is_integral<IntType>::value,
685 "Dimension parameter must be supplied as an integral type.");
686 auto real_dim = narrow_cast<size_t>(dim);
687 Expects(real_dim < rank);
688
689 return m_ranges.elementNum(real_dim);
690 }
691
Neil MacIntosh68064d62015-11-03 19:17:11 -0800692 constexpr index_type index_bounds() const noexcept
693 {
694 size_type extents[rank] = {};
695 m_ranges.serialize(extents);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800696 return {extents};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800697 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800698
Neil MacIntosh68064d62015-11-03 19:17:11 -0800699 template <std::ptrdiff_t... Ranges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800700 constexpr bool operator==(const static_bounds<Ranges...>& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800701 {
702 return this->size() == rhs.size();
703 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800704
Neil MacIntosh68064d62015-11-03 19:17:11 -0800705 template <std::ptrdiff_t... Ranges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800706 constexpr bool operator!=(const static_bounds<Ranges...>& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800707 {
708 return !(*this == rhs);
709 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800710
711 constexpr const_iterator begin() const noexcept { return const_iterator(*this, index_type{}); }
712
Neil MacIntosh68064d62015-11-03 19:17:11 -0800713 constexpr const_iterator end() const noexcept
714 {
715 return const_iterator(*this, this->index_bounds());
716 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700717};
718
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700719template <size_t Rank>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800720class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700721{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800722 template <size_t OtherRank>
723 friend class strided_bounds;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700724
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700725public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800726 static const size_t rank = Rank;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800727 using value_type = std::ptrdiff_t;
728 using reference = std::add_lvalue_reference_t<value_type>;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800729 using const_reference = std::add_const_t<reference>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800730 using size_type = value_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800731 using difference_type = value_type;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800732 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700733 using const_index_type = std::add_const_t<index_type>;
734 using iterator = bounds_iterator<const_index_type>;
735 using const_iterator = bounds_iterator<const_index_type>;
736 static const value_type dynamic_rank = rank;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800737 static const value_type static_size = dynamic_range;
738 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
739 using mapping_type = generalized_mapping_tag;
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700740
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800741 constexpr strided_bounds(const strided_bounds&) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700742
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800743 constexpr strided_bounds& operator=(const strided_bounds&) noexcept = default;
Vladislav Yaroslavlev557e6692015-11-12 10:44:41 +0300744
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800745 constexpr strided_bounds(const value_type (&values)[rank], index_type strides)
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700746 : m_extents(values), m_strides(std::move(strides))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800747 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800748 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700749
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800750 constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept
751 : m_extents(extents),
752 m_strides(strides)
753 {
754 }
755
756 constexpr index_type strides() const noexcept { return m_strides; }
757
Neil MacIntosh68064d62015-11-03 19:17:11 -0800758 constexpr size_type total_size() const noexcept
759 {
760 size_type ret = 0;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800761 for (size_t i = 0; i < rank; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800762 ret += (m_extents[i] - 1) * m_strides[i];
763 }
764 return ret + 1;
765 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800766
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700767 constexpr size_type size() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800768 {
769 size_type ret = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800770 for (size_t i = 0; i < rank; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800771 ret *= m_extents[i];
772 }
773 return ret;
774 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800775
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700776 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800777 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800778 for (size_t i = 0; i < rank; ++i) {
779 if (idx[i] < 0 || idx[i] >= m_extents[i]) return false;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800780 }
781 return true;
782 }
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700783
Neil MacIntosh68064d62015-11-03 19:17:11 -0800784 constexpr size_type linearize(const index_type& idx) const noexcept
785 {
786 size_type ret = 0;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800787 for (size_t i = 0; i < rank; i++) {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800788 Expects(idx[i] < m_extents[i]); // index is out of bounds of the array
Neil MacIntosh68064d62015-11-03 19:17:11 -0800789 ret += idx[i] * m_strides[i];
790 }
791 return ret;
792 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800793
794 constexpr size_type stride() const noexcept { return m_strides[0]; }
795
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700796 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800797 constexpr sliced_type slice() const
798 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800799 return {details::shift_left(m_extents), details::shift_left(m_strides)};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800800 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800801
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700802 template <size_t Dim = 0>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800803 constexpr size_type extent() const noexcept
804 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800805 static_assert(Dim < Rank,
806 "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosh68064d62015-11-03 19:17:11 -0800807 return m_extents[Dim];
808 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800809
810 constexpr index_type index_bounds() const noexcept { return m_extents; }
811 constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; }
812
813 constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700814
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700815private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800816 index_type m_extents;
817 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700818};
819
820template <typename T>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800821struct is_bounds : std::integral_constant<bool, false>
822{
823};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700824template <std::ptrdiff_t... Ranges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800825struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true>
826{
827};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700828template <size_t Rank>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800829struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true>
830{
831};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700832
833template <typename IndexType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800834class bounds_iterator : public std::iterator<std::random_access_iterator_tag, IndexType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700835{
836private:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800837 using Base = std::iterator<std::random_access_iterator_tag, IndexType>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700838
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700839public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800840 static const size_t rank = IndexType::rank;
841 using typename Base::reference;
842 using typename Base::pointer;
843 using typename Base::difference_type;
844 using typename Base::value_type;
845 using index_type = value_type;
846 using index_size_type = typename IndexType::value_type;
847 template <typename Bounds>
848 explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000849 : boundary_(bnd.index_bounds()),
850 curr_(std::move(curr))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800851 {
852 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
853 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700854
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000855 constexpr reference operator*() const noexcept { return curr_; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700856
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000857 constexpr pointer operator->() const noexcept { return &curr_; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700858
Neil MacIntosh68064d62015-11-03 19:17:11 -0800859 constexpr bounds_iterator& operator++() noexcept
860 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800861 for (size_t i = rank; i-- > 0;) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000862 if (curr_[i] < boundary_[i] - 1) {
863 curr_[i]++;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800864 return *this;
865 }
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000866 curr_[i] = 0;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800867 }
868 // If we're here we've wrapped over - set to past-the-end.
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000869 curr_ = boundary_;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800870 return *this;
871 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700872
Neil MacIntosh68064d62015-11-03 19:17:11 -0800873 constexpr bounds_iterator operator++(int) noexcept
874 {
875 auto ret = *this;
876 ++(*this);
877 return ret;
878 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700879
Neil MacIntosh68064d62015-11-03 19:17:11 -0800880 constexpr bounds_iterator& operator--() noexcept
881 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000882 if (!less(curr_, boundary_)) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800883 // if at the past-the-end, set to last element
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800884 for (size_t i = 0; i < rank; ++i) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000885 curr_[i] = boundary_[i] - 1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800886 }
887 return *this;
888 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800889 for (size_t i = rank; i-- > 0;) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000890 if (curr_[i] >= 1) {
891 curr_[i]--;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800892 return *this;
893 }
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000894 curr_[i] = boundary_[i] - 1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800895 }
896 // If we're here the preconditions were violated
897 // "pre: there exists s such that r == ++s"
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800898 Expects(false);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800899 return *this;
900 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700901
Neil MacIntosh68064d62015-11-03 19:17:11 -0800902 constexpr bounds_iterator operator--(int) noexcept
903 {
904 auto ret = *this;
905 --(*this);
906 return ret;
907 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700908
Neil MacIntosh68064d62015-11-03 19:17:11 -0800909 constexpr bounds_iterator operator+(difference_type n) const noexcept
910 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800911 bounds_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800912 return ret += n;
913 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700914
Neil MacIntosh68064d62015-11-03 19:17:11 -0800915 constexpr bounds_iterator& operator+=(difference_type n) noexcept
916 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000917 auto linear_idx = linearize(curr_) + n;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800918 std::remove_const_t<value_type> stride = 0;
919 stride[rank - 1] = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800920 for (size_t i = rank - 1; i-- > 0;) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000921 stride[i] = stride[i + 1] * boundary_[i + 1];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800922 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800923 for (size_t i = 0; i < rank; ++i) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000924 curr_[i] = linear_idx / stride[i];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800925 linear_idx = linear_idx % stride[i];
926 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800927 // index is out of bounds of the array
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000928 Expects(!less(curr_, index_type{}) && !less(boundary_, curr_));
Neil MacIntosh68064d62015-11-03 19:17:11 -0800929 return *this;
930 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700931
Neil MacIntosh68064d62015-11-03 19:17:11 -0800932 constexpr bounds_iterator operator-(difference_type n) const noexcept
933 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800934 bounds_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800935 return ret -= n;
936 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700937
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800938 constexpr bounds_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700939
Neil MacIntosh68064d62015-11-03 19:17:11 -0800940 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
941 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000942 return linearize(curr_) - linearize(rhs.curr_);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800943 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700944
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800945 constexpr value_type operator[](difference_type n) const noexcept { return *(*this + n); }
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 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000949 return curr_ == rhs.curr_;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800950 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700951
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800952 constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700953
Neil MacIntosh68064d62015-11-03 19:17:11 -0800954 constexpr bool operator<(const bounds_iterator& rhs) const noexcept
955 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000956 return less(curr_, rhs.curr_);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800957 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700958
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800959 constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700960
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800961 constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700962
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800963 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700964
Neil MacIntosh68064d62015-11-03 19:17:11 -0800965 void swap(bounds_iterator& rhs) noexcept
966 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000967 std::swap(boundary_, rhs.boundary_);
968 std::swap(curr_, rhs.curr_);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800969 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800970
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700971private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800972 constexpr bool less(index_type& one, index_type& other) const noexcept
973 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800974 for (size_t i = 0; i < rank; ++i) {
975 if (one[i] < other[i]) return true;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800976 }
977 return false;
978 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700979
Neil MacIntosh68064d62015-11-03 19:17:11 -0800980 constexpr index_size_type linearize(const value_type& idx) const noexcept
981 {
982 // TODO: Smarter impl.
983 // Check if past-the-end
984 index_size_type multiplier = 1;
985 index_size_type res = 0;
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000986 if (!less(idx, boundary_)) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800987 res = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800988 for (size_t i = rank; i-- > 0;) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800989 res += (idx[i] - 1) * multiplier;
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000990 multiplier *= boundary_[i];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800991 }
992 }
993 else
994 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800995 for (size_t i = rank; i-- > 0;) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800996 res += idx[i] * multiplier;
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000997 multiplier *= boundary_[i];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800998 }
999 }
1000 return res;
1001 }
Anna Gringauzea4654a42015-10-16 12:15:22 -07001002
Neil MacIntoshc9959b12015-11-30 05:34:38 +00001003 value_type boundary_;
1004 std::remove_const_t<value_type> curr_;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001005};
1006
1007template <typename IndexType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001008bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n,
1009 const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001010{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001011 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001012}
1013
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001014namespace details
1015{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001016 template <typename Bounds>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001017 constexpr std::enable_if_t<
1018 std::is_same<typename Bounds::mapping_type, generalized_mapping_tag>::value,
1019 typename Bounds::index_type>
1020 make_stride(const Bounds& bnd) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001021 {
1022 return bnd.strides();
1023 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001024
Neil MacIntosh68064d62015-11-03 19:17:11 -08001025 // Make a stride vector from bounds, assuming contiguous memory.
1026 template <typename Bounds>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001027 constexpr std::enable_if_t<
1028 std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value,
1029 typename Bounds::index_type>
1030 make_stride(const Bounds& bnd) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001031 {
1032 auto extents = bnd.index_bounds();
1033 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001034
Neil MacIntosh68064d62015-11-03 19:17:11 -08001035 stride[Bounds::rank - 1] = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001036 for (size_t i = 1; i < Bounds::rank; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -08001037 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
1038 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001039 return {stride};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001040 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001041
Neil MacIntosh68064d62015-11-03 19:17:11 -08001042 template <typename BoundsSrc, typename BoundsDest>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001043 void verifyBoundsReshape(const BoundsSrc& src, const BoundsDest& dest)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001044 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001045 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value,
1046 "The src type and dest type must be bounds");
1047 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value,
1048 "The source type must be a contiguous bounds");
1049 static_assert(BoundsDest::static_size == dynamic_range ||
1050 BoundsSrc::static_size == dynamic_range ||
1051 BoundsDest::static_size == BoundsSrc::static_size,
1052 "The source bounds must have same size as dest bounds");
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001053 Expects(src.size() == dest.size());
Neil MacIntosh68064d62015-11-03 19:17:11 -08001054 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001055
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001056} // namespace details
1057
Anna Gringauze8aa42482015-11-11 12:41:11 -08001058template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001059class contiguous_span_iterator;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001060template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001061class general_span_iterator;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001062enum class byte : std::uint8_t
1063{
1064};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001065
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001066template <std::ptrdiff_t DimSize = dynamic_range>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001067struct dim
1068{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001069 static const std::ptrdiff_t value = DimSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001070};
1071template <>
1072struct dim<dynamic_range>
1073{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001074 static const std::ptrdiff_t value = dynamic_range;
1075 const std::ptrdiff_t dvalue;
1076 dim(std::ptrdiff_t size) : dvalue(size) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001077};
1078
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001079template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range,
1080 std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001081class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001082
1083template <typename ValueType, size_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001084class strided_span;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001085
1086namespace details
1087{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001088 template <typename T, typename = std::true_type>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001089 struct SpanTypeTraits
Neil MacIntosh68064d62015-11-03 19:17:11 -08001090 {
1091 using value_type = T;
1092 using size_type = size_t;
1093 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001094
Neil MacIntosh68064d62015-11-03 19:17:11 -08001095 template <typename Traits>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001096 struct SpanTypeTraits<Traits, typename std::is_reference<typename Traits::span_traits&>::type>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001097 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001098 using value_type = typename Traits::span_traits::value_type;
1099 using size_type = typename Traits::span_traits::size_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001100 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001101
Neil MacIntosh68064d62015-11-03 19:17:11 -08001102 template <typename T, std::ptrdiff_t... Ranks>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001103 struct SpanArrayTraits
1104 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001105 using type = span<T, Ranks...>;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001106 using value_type = T;
1107 using bounds_type = static_bounds<Ranks...>;
1108 using pointer = T*;
1109 using reference = T&;
1110 };
1111 template <typename T, std::ptrdiff_t N, std::ptrdiff_t... Ranks>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001112 struct SpanArrayTraits<T[N], Ranks...> : SpanArrayTraits<T, Ranks..., N>
1113 {
1114 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001115
Neil MacIntosh68064d62015-11-03 19:17:11 -08001116 template <typename BoundsType>
1117 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
1118 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001119 Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001120 return BoundsType{totalSize};
1121 }
1122 template <typename BoundsType>
1123 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
1124 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001125 Expects(BoundsType::static_size <= totalSize);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001126 return {};
1127 }
1128 template <typename BoundsType>
1129 BoundsType newBoundsHelper(std::ptrdiff_t totalSize)
1130 {
1131 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001132 return newBoundsHelperImpl<BoundsType>(
1133 totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
Neil MacIntosh68064d62015-11-03 19:17:11 -08001134 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001135
1136 struct Sep
1137 {
1138 };
1139
Neil MacIntosh68064d62015-11-03 19:17:11 -08001140 template <typename T, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001141 T static_as_span_helper(Sep, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001142 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001143 return T{narrow_cast<typename T::size_type>(args)...};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001144 }
1145 template <typename T, typename Arg, typename... Args>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001146 std::enable_if_t<
1147 !std::is_same<Arg, dim<dynamic_range>>::value && !std::is_same<Arg, Sep>::value, T>
1148 static_as_span_helper(Arg, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001149 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001150 return static_as_span_helper<T>(args...);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001151 }
1152 template <typename T, typename... Args>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001153 T static_as_span_helper(dim<dynamic_range> val, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001154 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001155 return static_as_span_helper<T>(args..., val.dvalue);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001156 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001157
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001158 template <typename... Dimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001159 struct static_as_span_static_bounds_helper
Neil MacIntosh68064d62015-11-03 19:17:11 -08001160 {
1161 using type = static_bounds<(Dimensions::value)...>;
1162 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001163
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001164 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001165 struct is_span_oracle : std::false_type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001166 {
1167 };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001168
1169 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001170 struct is_span_oracle<span<ValueType, FirstDimension, RestDimensions...>> : std::true_type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001171 {
1172 };
1173
Neil MacIntosh68064d62015-11-03 19:17:11 -08001174 template <typename ValueType, std::ptrdiff_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001175 struct is_span_oracle<strided_span<ValueType, Rank>> : std::true_type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001176 {
1177 };
1178
Neil MacIntosh68064d62015-11-03 19:17:11 -08001179 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001180 struct is_span : is_span_oracle<std::remove_cv_t<T>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001181 {
1182 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001183}
1184
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001185template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001186class span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001187{
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001188 // TODO do we still need this?
1189 template <typename ValueType2, std::ptrdiff_t FirstDimension2,
1190 std::ptrdiff_t... RestDimensions2>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001191 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001192
Anna Gringauze8aa42482015-11-11 12:41:11 -08001193public:
Anna Gringauzef5100252015-11-12 12:48:49 -08001194 using bounds_type = static_bounds<FirstDimension, RestDimensions...>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001195 static const size_t Rank = bounds_type::rank;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001196 using size_type = typename bounds_type::size_type;
1197 using index_type = typename bounds_type::index_type;
1198 using value_type = ValueType;
1199 using const_value_type = std::add_const_t<value_type>;
Anna Gringauzef5100252015-11-12 12:48:49 -08001200 using pointer = std::add_pointer_t<value_type>;
1201 using reference = std::add_lvalue_reference_t<value_type>;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001202 using iterator = contiguous_span_iterator<span>;
1203 using const_span = span<const_value_type, FirstDimension, RestDimensions...>;
1204 using const_iterator = contiguous_span_iterator<const_span>;
1205 using reverse_iterator = std::reverse_iterator<iterator>;
1206 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001207 using sliced_type =
1208 std::conditional_t<Rank == 1, value_type, span<value_type, RestDimensions...>>;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001209
1210private:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001211 pointer data_;
1212 bounds_type bounds_;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001213
1214 friend iterator;
1215 friend const_iterator;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001216
1217public:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001218 // default constructor - same as constructing from nullptr_t
1219 constexpr span() noexcept : span(nullptr, bounds_type{})
Anna Gringauze8aa42482015-11-11 12:41:11 -08001220 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001221 static_assert(bounds_type::dynamic_rank != 0 ||
1222 (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
1223 "Default construction of span<T> only possible "
1224 "for dynamic or fixed, zero-length spans.");
Anna Gringauze8aa42482015-11-11 12:41:11 -08001225 }
1226
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001227 // construct from nullptr - get an empty span
1228 constexpr span(std::nullptr_t) noexcept : span(nullptr, bounds_type{})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001229 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001230 static_assert(bounds_type::dynamic_rank != 0 ||
1231 (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
1232 "nullptr_t construction of span<T> only possible "
1233 "for dynamic or fixed, zero-length spans.");
1234 }
1235
1236 // construct from nullptr with size of 0 (helps with template function calls)
1237 template <class IntType, typename = std::enable_if_t<std::is_integral<IntType>::value>>
1238 constexpr span(std::nullptr_t, IntType size) noexcept : span(nullptr, bounds_type{})
1239 {
1240 static_assert(bounds_type::dynamic_rank != 0 ||
1241 (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
1242 "nullptr_t construction of span<T> only possible "
1243 "for dynamic or fixed, zero-length spans.");
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001244 Expects(size == 0);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001245 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001246
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001247 // construct from a single element
1248 constexpr span(reference data) noexcept : span(&data, bounds_type{1})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001249 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001250 static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 ||
1251 bounds_type::static_size == 1,
1252 "Construction from a single element only possible "
1253 "for dynamic or fixed spans of length 0 or 1.");
Neil MacIntosh68064d62015-11-03 19:17:11 -08001254 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001255
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001256 // prevent constructing from temporaries for single-elements
1257 constexpr span(value_type&&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001258
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001259 // construct from pointer + length
1260 constexpr span(pointer ptr, size_type size) noexcept : span(ptr, bounds_type{size}) {}
1261
1262 // construct from pointer + length - multidimensional
1263 constexpr span(pointer data, bounds_type bounds) noexcept : data_(data),
1264 bounds_(std::move(bounds))
1265 {
1266 Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0);
1267 }
1268
1269 // construct from begin,end pointer pair
Neil MacIntosh68064d62015-11-03 19:17:11 -08001270 template <typename Ptr,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001271 typename = std::enable_if_t<std::is_convertible<Ptr, pointer>::value &&
1272 details::LessThan<bounds_type::dynamic_rank, 2>::value>>
1273 constexpr span(pointer begin, Ptr end)
1274 : span(begin, details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin))
1275 {
1276 Expects(begin != nullptr && end != nullptr && begin <= static_cast<pointer>(end));
1277 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001278
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001279 // construct from n-dimensions static array
1280 template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>>
1281 constexpr span(T (&arr)[N])
1282 : span(reinterpret_cast<pointer>(arr), bounds_type{typename Helper::bounds_type{}})
1283 {
1284 static_assert(
1285 std::is_convertible<typename Helper::value_type(*) [], value_type(*) []>::value,
1286 "Cannot convert from source type to target span type.");
1287 static_assert(std::is_convertible<typename Helper::bounds_type, bounds_type>::value,
1288 "Cannot construct a span from an array with fewer elements.");
1289 }
1290
1291 // construct from n-dimensions dynamic array (e.g. new int[m][4])
1292 // (precedence will be lower than the 1-dimension pointer)
1293 template <typename T, typename Helper = details::SpanArrayTraits<T, dynamic_range>>
1294 constexpr span(T* const& data, size_type size)
1295 : span(reinterpret_cast<pointer>(data), typename Helper::bounds_type{size})
1296 {
1297 static_assert(
1298 std::is_convertible<typename Helper::value_type(*) [], value_type(*) []>::value,
1299 "Cannot convert from source type to target span type.");
1300 }
1301
1302 // construct from std::array
1303 template <typename T, size_t N>
1304 constexpr span(std::array<T, N>& arr) : span(arr.data(), bounds_type{static_bounds<N>{}})
1305 {
1306 static_assert(
1307 std::is_convertible<T(*) [], typename std::remove_const_t<value_type>(*) []>::value,
1308 "Cannot convert from source type to target span type.");
1309 static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value,
1310 "You cannot construct a span from a std::array of smaller size.");
1311 }
1312
1313 // construct from const std::array
1314 template <typename T, size_t N>
1315 constexpr span(const std::array<std::remove_const_t<value_type>, N>& arr)
1316 : span(arr.data(), static_bounds<N>())
1317 {
1318 static_assert(std::is_convertible<T(*) [], std::remove_const_t<value_type>>::value,
1319 "Cannot convert from source type to target span type.");
1320 static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value,
1321 "You cannot construct a span from a std::array of smaller size.");
1322 }
1323
1324 // prevent constructing from temporary std::array
1325 template <typename T, size_t N>
1326 constexpr span(std::array<T, N>&& arr) = delete;
1327
1328 // construct from containers
1329 // future: could use contiguous_iterator_traits to identify only contiguous containers
1330 // type-requirements: container must have .size(), operator[] which are value_type compatible
Neil MacIntosh68064d62015-11-03 19:17:11 -08001331 template <typename Cont, typename DataType = typename Cont::value_type,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001332 typename = std::enable_if_t<
1333 !details::is_span<Cont>::value &&
1334 std::is_convertible<DataType (*)[], value_type (*)[]>::value &&
1335 std::is_same<std::decay_t<decltype(std::declval<Cont>().size(),
1336 *std::declval<Cont>().data())>,
1337 DataType>::value>>
1338 constexpr span(Cont& cont)
1339 : span(static_cast<pointer>(cont.data()),
1340 details::newBoundsHelper<bounds_type>(narrow_cast<size_type>(cont.size())))
1341 {
1342 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001343
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001344 // prevent constructing from temporary containers
1345 template <typename Cont, typename DataType = typename Cont::value_type,
1346 typename = std::enable_if_t<
1347 !details::is_span<Cont>::value &&
1348 std::is_convertible<DataType (*)[], value_type (*)[]>::value &&
1349 std::is_same<std::decay_t<decltype(std::declval<Cont>().size(),
1350 *std::declval<Cont>().data())>,
1351 DataType>::value>>
1352 explicit constexpr span(Cont&& cont) = delete;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001353
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001354 // construct from a convertible span
Neil MacIntosh68064d62015-11-03 19:17:11 -08001355 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001356 typename OtherBounds = static_bounds<OtherDimensions...>,
1357 typename = std::enable_if_t<std::is_convertible<OtherValueType, ValueType>::value &&
1358 std::is_convertible<OtherBounds, bounds_type>::value>>
1359 constexpr span(span<OtherValueType, OtherDimensions...> other) noexcept : data_(other.data_),
1360 bounds_(other.bounds_)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001361 {
Neil MacIntosh68064d62015-11-03 19:17:11 -08001362 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001363
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001364// trivial copy and move
1365#ifndef GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
1366 constexpr span(span&&) = default;
1367#endif
1368 constexpr span(const span&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001369
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001370// trivial assignment
1371#ifndef GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
1372 constexpr span& operator=(span&&) = default;
1373#endif
1374 constexpr span& operator=(const span&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001375
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001376 // first() - extract the first Count elements into a new span
1377 template <std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001378 constexpr span<ValueType, Count> first() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001379 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001380 static_assert(Count >= 0, "Count must be >= 0.");
1381 static_assert(bounds_type::static_size == dynamic_range ||
1382 Count <= bounds_type::static_size,
1383 "Count is out of bounds.");
1384
1385 Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
1386 return {this->data(), Count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001387 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001388
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001389 // first() - extract the first count elements into a new span
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001390 constexpr span<ValueType, dynamic_range> first(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001391 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001392 Expects(count >= 0 && count <= this->size());
1393 return {this->data(), count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001394 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001395
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001396 // last() - extract the last Count elements into a new span
1397 template <std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001398 constexpr span<ValueType, Count> last() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001399 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001400 static_assert(Count >= 0, "Count must be >= 0.");
1401 static_assert(bounds_type::static_size == dynamic_range ||
1402 Count <= bounds_type::static_size,
1403 "Count is out of bounds.");
1404
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001405 Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001406 return {this->data() + this->size() - Count, Count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001407 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001408
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001409 // last() - extract the last count elements into a new span
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001410 constexpr span<ValueType, dynamic_range> last(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001411 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001412 Expects(count >= 0 && count <= this->size());
1413 return {this->data() + this->size() - count, count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001414 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001415
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001416 // subspan() - create a subview of Count elements starting at Offset
1417 template <std::ptrdiff_t Offset, std::ptrdiff_t Count>
1418 constexpr span<ValueType, Count> subspan() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001419 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001420 static_assert(Count >= 0, "Count must be >= 0.");
1421 static_assert(Offset >= 0, "Offset must be >= 0.");
1422 static_assert(bounds_type::static_size == dynamic_range ||
1423 ((Offset <= bounds_type::static_size) &&
1424 Count <= bounds_type::static_size - Offset),
1425 "You must describe a sub-range within bounds of the span.");
1426
1427 Expects(bounds_type::static_size != dynamic_range ||
1428 (Offset <= this->size() && Count <= this->size() - Offset));
1429 return {this->data() + Offset, Count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001430 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001431
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001432 // subspan() - create a subview of count elements starting at offset
1433 // supplying dynamic_range for count will consume all available elements from offset
1434 constexpr span<ValueType, dynamic_range> subspan(size_type offset,
1435 size_type count = dynamic_range) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001436 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001437 Expects((offset >= 0 && offset <= this->size()) &&
1438 (count == dynamic_range || (count <= this->size() - offset)));
1439 return {this->data() + offset, count == dynamic_range ? this->length() - offset : count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001440 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001441
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001442 // section - creates a non-contiguous, strided span from a contiguous one
1443 constexpr strided_span<ValueType, Rank> section(index_type origin, index_type extents) const
1444 noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001445 {
1446 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001447 return {&this->operator[](origin), size,
1448 strided_bounds<Rank>{extents, details::make_stride(bounds())}};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001449 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001450
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001451 // length of the span in elements
1452 constexpr size_type size() const noexcept { return bounds_.size(); }
1453
1454 // length of the span in elements
1455 constexpr size_type length() const noexcept { return this->size(); }
1456
1457 // length of the span in bytes
1458 constexpr size_type size_bytes() const noexcept { return sizeof(value_type) * this->size(); }
1459
1460 // length of the span in bytes
1461 constexpr size_type length_bytes() const noexcept { return this->size_bytes(); }
1462
1463 constexpr bool empty() const noexcept { return this->size() == 0; }
1464
1465 static constexpr std::size_t rank() { return Rank; }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001466
1467 template <size_t Dim = 0>
1468 constexpr size_type extent() const noexcept
1469 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001470 static_assert(Dim < Rank,
1471 "Dimension should be less than rank (dimension count starts from 0).");
1472 return bounds_.template extent<Dim>();
Anna Gringauze8aa42482015-11-11 12:41:11 -08001473 }
1474
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001475 template <typename IntType>
1476 constexpr size_type extent(IntType dim) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001477 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001478 return bounds_.extent(dim);
Anna Gringauze8aa42482015-11-11 12:41:11 -08001479 }
1480
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001481 constexpr bounds_type bounds() const noexcept { return bounds_; }
1482
1483 constexpr pointer data() const noexcept { return data_; }
1484
1485 template <typename FirstIndex>
1486 constexpr reference operator()(FirstIndex index)
Anna Gringauze8aa42482015-11-11 12:41:11 -08001487 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001488 return this->operator[](narrow_cast<std::ptrdiff_t>(index));
Anna Gringauze8aa42482015-11-11 12:41:11 -08001489 }
1490
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001491 template <typename FirstIndex, typename... OtherIndices>
1492 constexpr reference operator()(FirstIndex index, OtherIndices... indices)
Anna Gringauze8aa42482015-11-11 12:41:11 -08001493 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001494 index_type idx = {narrow_cast<std::ptrdiff_t>(index),
1495 narrow_cast<std::ptrdiff_t>(indices...)};
1496 return this->operator[](idx);
Anna Gringauze8aa42482015-11-11 12:41:11 -08001497 }
1498
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001499 constexpr reference operator[](const index_type& idx) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001500 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001501 return data_[bounds_.linearize(idx)];
Anna Gringauze8aa42482015-11-11 12:41:11 -08001502 }
1503
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001504 template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
1505 constexpr Ret operator[](size_type idx) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001506 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001507 Expects(idx < bounds_.size()); // index is out of bounds of the array
1508 const size_type ridx = idx * bounds_.stride();
1509
1510 // index is out of bounds of the underlying data
1511 Expects(ridx < bounds_.total_size());
1512 return Ret{data_ + ridx, bounds_.slice()};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001513 }
1514
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001515 constexpr iterator begin() const noexcept { return iterator{this, true}; }
1516
1517 constexpr iterator end() const noexcept { return iterator{this, false}; }
1518
Anna Gringauzef5100252015-11-12 12:48:49 -08001519 constexpr const_iterator cbegin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001520 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001521 return const_iterator{reinterpret_cast<const const_span*>(this), true};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001522 }
1523
Anna Gringauzef5100252015-11-12 12:48:49 -08001524 constexpr const_iterator cend() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001525 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001526 return const_iterator{reinterpret_cast<const const_span*>(this), false};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001527 }
1528
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001529 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001530
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001531 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001532
Anna Gringauzef5100252015-11-12 12:48:49 -08001533 constexpr const_reverse_iterator crbegin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001534 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001535 return const_reverse_iterator{cend()};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001536 }
1537
Anna Gringauzef5100252015-11-12 12:48:49 -08001538 constexpr const_reverse_iterator crend() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001539 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001540 return const_reverse_iterator{cbegin()};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001541 }
1542
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001543 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1544 typename Dummy = std::enable_if_t<std::is_same<
1545 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1546 constexpr bool operator==(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001547 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001548 return bounds_.size() == other.bounds_.size() &&
1549 (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin()));
Anna Gringauze8aa42482015-11-11 12:41:11 -08001550 }
1551
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001552 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1553 typename Dummy = std::enable_if_t<std::is_same<
1554 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1555 constexpr bool operator!=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001556 {
1557 return !(*this == other);
1558 }
1559
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001560 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1561 typename Dummy = std::enable_if_t<std::is_same<
1562 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1563 constexpr bool operator<(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001564 {
1565 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1566 }
1567
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001568 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1569 typename Dummy = std::enable_if_t<std::is_same<
1570 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1571 constexpr bool operator<=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001572 {
1573 return !(other < *this);
1574 }
1575
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001576 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1577 typename Dummy = std::enable_if_t<std::is_same<
1578 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1579 constexpr bool operator>(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001580 {
1581 return (other < *this);
1582 }
1583
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001584 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1585 typename Dummy = std::enable_if_t<std::is_same<
1586 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1587 constexpr bool operator>=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001588 {
1589 return !(*this < other);
1590 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001591};
1592
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001593//
1594// Free functions for manipulating spans
1595//
1596
1597// reshape a span into a different dimensionality
1598// DimCount and Enabled here are workarounds for a bug in MSVC 2015
1599template <typename SpanType, typename... Dimensions2, size_t DimCount = sizeof...(Dimensions2),
1600 bool Enabled = (DimCount > 0), typename = std::enable_if_t<Enabled>>
1601constexpr span<typename SpanType::value_type, Dimensions2::value...> as_span(SpanType s,
1602 Dimensions2... dims)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001603{
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001604 static_assert(details::is_span<SpanType>::value,
1605 "Variadic as_span() is for reshaping existing spans.");
1606 using BoundsType =
1607 typename span<typename SpanType::value_type, (Dimensions2::value)...>::bounds_type;
1608 auto tobounds = details::static_as_span_helper<BoundsType>(dims..., details::Sep{});
1609 details::verifyBoundsReshape(s.bounds(), tobounds);
1610 return {s.data(), tobounds};
1611}
1612
1613// convert a span<T> to a span<const byte>
1614template <typename U, std::ptrdiff_t... Dimensions>
1615span<const byte, dynamic_range> as_bytes(span<U, Dimensions...> s) noexcept
1616{
1617 static_assert(std::is_trivial<std::decay_t<U>>::value,
1618 "The value_type of span must be a trivial type.");
1619 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
1620}
1621
1622// convert a span<T> to a span<byte> (a writeable byte span)
1623// this is not currently a portable function that can be relied upon to work
1624// on all implementations. It should be considered an experimental extension
1625// to the standard GSL interface.
1626template <typename U, std::ptrdiff_t... Dimensions>
1627span<byte> as_writeable_bytes(span<U, Dimensions...> s) noexcept
1628{
1629 static_assert(std::is_trivial<std::decay_t<U>>::value,
1630 "The value_type of span must be a trivial type.");
1631 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
1632}
1633
1634// convert a span<const byte> to a span<const T>
1635// this is not currently a portable function that can be relied upon to work
1636// on all implementations. It should be considered an experimental extension
1637// to the standard GSL interface.
1638template <typename U, std::ptrdiff_t... Dimensions>
1639constexpr auto as_span(span<const byte, Dimensions...> s) noexcept
1640 -> span<const U, static_cast<std::ptrdiff_t>(
1641 span<const byte, Dimensions...>::bounds_type::static_size != dynamic_range
1642 ? (static_cast<size_t>(
1643 span<const byte, Dimensions...>::bounds_type::static_size) /
1644 sizeof(U))
1645 : dynamic_range)>
1646{
1647 using ConstByteSpan = span<const byte, Dimensions...>;
1648 static_assert(
1649 std::is_trivial<std::decay_t<U>>::value &&
1650 (ConstByteSpan::bounds_type::static_size == dynamic_range ||
1651 ConstByteSpan::bounds_type::static_size % narrow_cast<std::ptrdiff_t>(sizeof(U)) == 0),
1652 "Target type must be a trivial type and its size must match the byte array size");
1653
1654 Expects((s.size_bytes() % sizeof(U)) == 0 && (s.size_bytes() / sizeof(U)) < PTRDIFF_MAX);
1655 return {reinterpret_cast<const U*>(s.data()),
1656 s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
1657}
1658
1659// convert a span<byte> to a span<T>
1660// this is not currently a portable function that can be relied upon to work
1661// on all implementations. It should be considered an experimental extension
1662// to the standard GSL interface.
1663template <typename U, std::ptrdiff_t... Dimensions>
1664constexpr auto as_span(span<byte, Dimensions...> s) noexcept -> span<
1665 U, narrow_cast<std::ptrdiff_t>(
1666 span<byte, Dimensions...>::bounds_type::static_size != dynamic_range
1667 ? static_cast<std::size_t>(span<byte, Dimensions...>::bounds_type::static_size) /
1668 sizeof(U)
1669 : dynamic_range)>
1670{
1671 using ByteSpan = span<byte, Dimensions...>;
1672 static_assert(
1673 std::is_trivial<std::decay_t<U>>::value &&
1674 (ByteSpan::bounds_type::static_size == dynamic_range ||
1675 ByteSpan::bounds_type::static_size % static_cast<std::size_t>(sizeof(U)) == 0),
1676 "Target type must be a trivial type and its size must match the byte array size");
1677
mcheeseeedd18d2015-12-06 13:43:03 +01001678 Expects((s.size_bytes() % sizeof(U)) == 0);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001679 return {reinterpret_cast<U*>(s.data()),
1680 s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
1681}
1682
1683template <typename T, std::ptrdiff_t... Dimensions>
1684constexpr auto as_span(T* const& ptr, dim<Dimensions>... args)
1685 -> span<std::remove_all_extents_t<T>, Dimensions...>
1686{
1687 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr),
1688 details::static_as_span_helper<static_bounds<Dimensions...>>(args..., details::Sep{})};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001689}
1690
1691template <typename T>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001692constexpr auto as_span(T* arr, std::ptrdiff_t len) ->
1693 typename details::SpanArrayTraits<T, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001694{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001695 return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001696}
1697
1698template <typename T, size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001699constexpr auto as_span(T (&arr)[N]) -> typename details::SpanArrayTraits<T, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001700{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001701 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001702}
1703
1704template <typename T, size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001705constexpr span<const T, N> as_span(const std::array<T, N>& arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001706{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001707 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001708}
1709
1710template <typename T, size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001711constexpr span<const T, N> as_span(const std::array<T, N>&&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001712
1713template <typename T, size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001714constexpr span<T, N> as_span(std::array<T, N>& arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001715{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001716 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001717}
1718
1719template <typename T>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001720constexpr span<T, dynamic_range> as_span(T* begin, T* end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001721{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001722 return {begin, end};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001723}
1724
1725template <typename Cont>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001726constexpr auto as_span(Cont& arr) -> std::enable_if_t<
1727 !details::is_span<std::decay_t<Cont>>::value,
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001728 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001729{
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001730 Expects(arr.size() < PTRDIFF_MAX);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001731 return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001732}
1733
1734template <typename Cont>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001735constexpr auto as_span(Cont&& arr) -> std::enable_if_t<
1736 !details::is_span<std::decay_t<Cont>>::value,
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001737 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001738
Elron A. Yelline4d8d352015-11-20 17:50:02 -05001739// from basic_string which doesn't have nonconst .data() member like other contiguous containers
1740template <typename CharT, typename Traits, typename Allocator>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001741constexpr auto as_span(std::basic_string<CharT, Traits, Allocator>& str)
1742 -> span<CharT, dynamic_range>
Elron A. Yelline4d8d352015-11-20 17:50:02 -05001743{
Neil MacIntoshd5057372015-11-20 17:14:21 -08001744 Expects(str.size() < PTRDIFF_MAX);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001745 return {&str[0], narrow_cast<std::ptrdiff_t>(str.size())};
Elron A. Yelline4d8d352015-11-20 17:50:02 -05001746}
1747
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001748// strided_span is an extension that is not strictly part of the GSL at this time.
1749// It is kept here while the multidimensional interface is still being defined.
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001750template <typename ValueType, size_t Rank>
Anna Gringauzef5100252015-11-12 12:48:49 -08001751class strided_span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001752{
Anna Gringauzef5100252015-11-12 12:48:49 -08001753public:
1754 using bounds_type = strided_bounds<Rank>;
1755 using size_type = typename bounds_type::size_type;
1756 using index_type = typename bounds_type::index_type;
1757 using value_type = ValueType;
1758 using const_value_type = std::add_const_t<value_type>;
1759 using pointer = std::add_pointer_t<value_type>;
1760 using reference = std::add_lvalue_reference_t<value_type>;
1761 using iterator = general_span_iterator<strided_span>;
1762 using const_strided_span = strided_span<const_value_type, Rank>;
1763 using const_iterator = general_span_iterator<const_strided_span>;
1764 using reverse_iterator = std::reverse_iterator<iterator>;
1765 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001766 using sliced_type =
1767 std::conditional_t<Rank == 1, value_type, strided_span<value_type, Rank - 1>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001768
Anna Gringauzef5100252015-11-12 12:48:49 -08001769private:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001770 pointer data_;
1771 bounds_type bounds_;
Anna Gringauzef5100252015-11-12 12:48:49 -08001772
1773 friend iterator;
1774 friend const_iterator;
1775 template <typename OtherValueType, size_t OtherRank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001776 friend class strided_span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001777
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001778public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001779 // from raw data
Anna Gringauzef5100252015-11-12 12:48:49 -08001780 constexpr strided_span(pointer ptr, size_type size, bounds_type bounds)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001781 : data_(ptr), bounds_(std::move(bounds))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001782 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001783 Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0);
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001784 // Bounds cross data boundaries
1785 Expects(this->bounds().total_size() <= size);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001786 (void) size;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001787 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001788
Anna Gringauzef5100252015-11-12 12:48:49 -08001789 // from static array of size N
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001790 template <size_type N>
1791 constexpr strided_span(value_type (&values)[N], bounds_type bounds)
1792 : strided_span(values, N, std::move(bounds))
1793 {
1794 }
Anna Gringauzef5100252015-11-12 12:48:49 -08001795
Neil MacIntosh68064d62015-11-03 19:17:11 -08001796 // from array view
Anna Gringauzec95eb572015-11-19 12:02:06 -08001797 template <typename OtherValueType, std::ptrdiff_t... Dimensions,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001798 bool Enabled1 = (sizeof...(Dimensions) == Rank),
1799 bool Enabled2 = std::is_convertible<OtherValueType*, ValueType*>::value,
1800 typename Dummy = std::enable_if_t<Enabled1 && Enabled2>>
1801 constexpr strided_span(span<OtherValueType, Dimensions...> av, bounds_type bounds)
1802 : strided_span(av.data(), av.bounds().total_size(), std::move(bounds))
1803 {
1804 }
1805
Neil MacIntosh68064d62015-11-03 19:17:11 -08001806 // convertible
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001807 template <typename OtherValueType, typename Dummy = std::enable_if_t<std::is_convertible<
1808 OtherValueType (*)[], value_type (*)[]>::value>>
Anna Gringauzef5100252015-11-12 12:48:49 -08001809 constexpr strided_span(const strided_span<OtherValueType, Rank>& other)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001810 : data_(other.data_), bounds_(other.bounds_)
1811 {
1812 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001813
Neil MacIntosh68064d62015-11-03 19:17:11 -08001814 // convert from bytes
Anna Gringauzef5100252015-11-12 12:48:49 -08001815 template <typename OtherValueType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001816 constexpr strided_span<
1817 typename std::enable_if<std::is_same<value_type, const byte>::value, OtherValueType>::type,
1818 Rank>
1819 as_strided_span() const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001820 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001821 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) &&
1822 (sizeof(OtherValueType) % sizeof(value_type) == 0),
1823 "OtherValueType should have a size to contain a multiple of ValueTypes");
1824 auto d = narrow_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001825
Neil MacIntosh68064d62015-11-03 19:17:11 -08001826 size_type size = this->bounds().total_size() / d;
Gary Furnish62b063a2016-01-13 16:12:17 +00001827 return {const_cast<OtherValueType*>(reinterpret_cast<const OtherValueType*>(this->data())), size,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001828 bounds_type{resize_extent(this->bounds().index_bounds(), d),
1829 resize_stride(this->bounds().strides(), d)}};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001830 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001831
Anna Gringauzef5100252015-11-12 12:48:49 -08001832 constexpr strided_span section(index_type origin, index_type extents) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001833 {
1834 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001835 return {&this->operator[](origin), size,
1836 bounds_type{extents, details::make_stride(bounds())}};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001837 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001838
Neil MacIntosh68064d62015-11-03 19:17:11 -08001839 constexpr reference operator[](const index_type& idx) const
1840 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001841 return data_[bounds_.linearize(idx)];
Neil MacIntosh68064d62015-11-03 19:17:11 -08001842 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001843
Anna Gringauzef5100252015-11-12 12:48:49 -08001844 template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
1845 constexpr Ret operator[](size_type idx) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001846 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001847 Expects(idx < bounds_.size()); // index is out of bounds of the array
1848 const size_type ridx = idx * bounds_.stride();
Anna Gringauzef5100252015-11-12 12:48:49 -08001849
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001850 // index is out of bounds of the underlying data
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001851 Expects(ridx < bounds_.total_size());
1852 return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()};
Anna Gringauzef5100252015-11-12 12:48:49 -08001853 }
1854
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001855 constexpr bounds_type bounds() const noexcept { return bounds_; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001856
1857 template <size_t Dim = 0>
1858 constexpr size_type extent() const noexcept
1859 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001860 static_assert(Dim < Rank,
1861 "dimension should be less than Rank (dimension count starts from 0)");
1862 return bounds_.template extent<Dim>();
Anna Gringauzef5100252015-11-12 12:48:49 -08001863 }
1864
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001865 constexpr size_type size() const noexcept { return bounds_.size(); }
Anna Gringauzef5100252015-11-12 12:48:49 -08001866
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001867 constexpr pointer data() const noexcept { return data_; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001868
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001869 constexpr explicit operator bool() const noexcept { return data_ != nullptr; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001870
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001871 constexpr iterator begin() const { return iterator{this, true}; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001872
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001873 constexpr iterator end() const { return iterator{this, false}; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001874
1875 constexpr const_iterator cbegin() const
1876 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001877 return const_iterator{reinterpret_cast<const const_strided_span*>(this), true};
Anna Gringauzef5100252015-11-12 12:48:49 -08001878 }
1879
1880 constexpr const_iterator cend() const
1881 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001882 return const_iterator{reinterpret_cast<const const_strided_span*>(this), false};
Anna Gringauzef5100252015-11-12 12:48:49 -08001883 }
1884
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001885 constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; }
1886
1887 constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; }
1888
1889 constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{cend()}; }
1890
1891 constexpr const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; }
1892
1893 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1894 typename Dummy = std::enable_if_t<std::is_same<
1895 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1896 constexpr bool operator==(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001897 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001898 return bounds_.size() == other.bounds_.size() &&
1899 (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin()));
Anna Gringauzef5100252015-11-12 12:48:49 -08001900 }
1901
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001902 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1903 typename Dummy = std::enable_if_t<std::is_same<
1904 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1905 constexpr bool operator!=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001906 {
1907 return !(*this == other);
1908 }
1909
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001910 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1911 typename Dummy = std::enable_if_t<std::is_same<
1912 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1913 constexpr bool operator<(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001914 {
1915 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1916 }
1917
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001918 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1919 typename Dummy = std::enable_if_t<std::is_same<
1920 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1921 constexpr bool operator<=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001922 {
1923 return !(other < *this);
1924 }
1925
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001926 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1927 typename Dummy = std::enable_if_t<std::is_same<
1928 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1929 constexpr bool operator>(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001930 {
1931 return (other < *this);
1932 }
1933
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001934 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1935 typename Dummy = std::enable_if_t<std::is_same<
1936 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1937 constexpr bool operator>=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001938 {
1939 return !(*this < other);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001940 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001941
1942private:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001943 static index_type resize_extent(const index_type& extent, std::ptrdiff_t d)
1944 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001945 // The last dimension of the array needs to contain a multiple of new type elements
1946 Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001947
Neil MacIntosh68064d62015-11-03 19:17:11 -08001948 index_type ret = extent;
Anna Gringauzef5100252015-11-12 12:48:49 -08001949 ret[Rank - 1] /= d;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001950
Neil MacIntosh68064d62015-11-03 19:17:11 -08001951 return ret;
1952 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001953
Anna Gringauzef5100252015-11-12 12:48:49 -08001954 template <bool Enabled = (Rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001955 static index_type resize_stride(const index_type& strides, std::ptrdiff_t, void* = 0)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001956 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001957 // Only strided arrays with regular strides can be resized
1958 Expects(strides[Rank - 1] == 1);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001959
Neil MacIntosh68064d62015-11-03 19:17:11 -08001960 return strides;
1961 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001962
Anna Gringauzef5100252015-11-12 12:48:49 -08001963 template <bool Enabled = (Rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001964 static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
1965 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001966 // Only strided arrays with regular strides can be resized
1967 Expects(strides[Rank - 1] == 1);
1968 // The strides must have contiguous chunks of
1969 // memory that can contain a multiple of new type elements
1970 Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001971
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001972 for (size_t i = Rank - 1; i > 0; --i) {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001973 // Only strided arrays with regular strides can be resized
1974 Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0));
Anna Gringauzef5100252015-11-12 12:48:49 -08001975 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001976
Neil MacIntosh68064d62015-11-03 19:17:11 -08001977 index_type ret = strides / d;
Anna Gringauzef5100252015-11-12 12:48:49 -08001978 ret[Rank - 1] = 1;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001979
Neil MacIntosh68064d62015-11-03 19:17:11 -08001980 return ret;
1981 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001982};
1983
Anna Gringauze8aa42482015-11-11 12:41:11 -08001984template <class Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001985class contiguous_span_iterator
1986 : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001987{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001988 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001989
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001990public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001991 using typename Base::reference;
1992 using typename Base::pointer;
1993 using typename Base::difference_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001994
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001995private:
Anna Gringauze8aa42482015-11-11 12:41:11 -08001996 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
1997 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001998
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001999 pointer data_;
Anna Gringauze8aa42482015-11-11 12:41:11 -08002000 const Span* m_validator;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002001 void validateThis() const
2002 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002003 // iterator is out of range of the array
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002004 Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size());
Neil MacIntosh68064d62015-11-03 19:17:11 -08002005 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002006 contiguous_span_iterator(const Span* container, bool isbegin)
2007 : data_(isbegin ? container->data_ : container->data_ + container->size())
2008 , m_validator(container)
2009 {
2010 }
2011
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002012public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08002013 reference operator*() const noexcept
2014 {
2015 validateThis();
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002016 return *data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002017 }
2018 pointer operator->() const noexcept
2019 {
2020 validateThis();
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002021 return data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002022 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002023 contiguous_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002024 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002025 ++data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002026 return *this;
2027 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002028 contiguous_span_iterator operator++(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002029 {
2030 auto ret = *this;
2031 ++(*this);
2032 return ret;
2033 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002034 contiguous_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002035 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002036 --data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002037 return *this;
2038 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002039 contiguous_span_iterator operator--(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002040 {
2041 auto ret = *this;
2042 --(*this);
2043 return ret;
2044 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002045 contiguous_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002046 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002047 contiguous_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002048 return ret += n;
2049 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002050 contiguous_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002051 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002052 data_ += n;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002053 return *this;
2054 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002055 contiguous_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002056 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002057 contiguous_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002058 return ret -= n;
2059 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002060 contiguous_span_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002061 difference_type operator-(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002062 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002063 Expects(m_validator == rhs.m_validator);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002064 return data_ - rhs.data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002065 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002066 reference operator[](difference_type n) const noexcept { return *(*this + n); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002067 bool operator==(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002068 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002069 Expects(m_validator == rhs.m_validator);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002070 return data_ == rhs.data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002071 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002072 bool operator!=(const contiguous_span_iterator& rhs) const noexcept { return !(*this == rhs); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002073 bool operator<(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002074 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002075 Expects(m_validator == rhs.m_validator);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002076 return data_ < rhs.data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002077 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002078 bool operator<=(const contiguous_span_iterator& rhs) const noexcept { return !(rhs < *this); }
2079 bool operator>(const contiguous_span_iterator& rhs) const noexcept { return rhs < *this; }
2080 bool operator>=(const contiguous_span_iterator& rhs) const noexcept { return !(rhs > *this); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002081 void swap(contiguous_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002082 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002083 std::swap(data_, rhs.data_);
Neil MacIntosh68064d62015-11-03 19:17:11 -08002084 std::swap(m_validator, rhs.m_validator);
2085 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002086};
2087
Anna Gringauze8aa42482015-11-11 12:41:11 -08002088template <typename Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002089contiguous_span_iterator<Span> operator+(typename contiguous_span_iterator<Span>::difference_type n,
2090 const contiguous_span_iterator<Span>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002091{
Neil MacIntosh68064d62015-11-03 19:17:11 -08002092 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002093}
2094
Anna Gringauze8aa42482015-11-11 12:41:11 -08002095template <typename Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002096class general_span_iterator
2097 : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002098{
Anna Gringauze8aa42482015-11-11 12:41:11 -08002099 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002100
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002101public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08002102 using typename Base::reference;
2103 using typename Base::pointer;
2104 using typename Base::difference_type;
2105 using typename Base::value_type;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002106
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002107private:
Anna Gringauzef5100252015-11-12 12:48:49 -08002108 template <typename ValueType, size_t Rank>
2109 friend class strided_span;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002110
Anna Gringauzef5100252015-11-12 12:48:49 -08002111 const Span* m_container;
Anna Gringauze8aa42482015-11-11 12:41:11 -08002112 typename Span::bounds_type::iterator m_itr;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002113 general_span_iterator(const Span* container, bool isbegin)
2114 : m_container(container)
2115 , m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
2116 {
2117 }
2118
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002119public:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002120 reference operator*() noexcept { return (*m_container)[*m_itr]; }
2121 pointer operator->() noexcept { return &(*m_container)[*m_itr]; }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002122 general_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002123 {
2124 ++m_itr;
2125 return *this;
2126 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002127 general_span_iterator operator++(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002128 {
2129 auto ret = *this;
2130 ++(*this);
2131 return ret;
2132 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002133 general_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002134 {
2135 --m_itr;
2136 return *this;
2137 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002138 general_span_iterator operator--(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002139 {
2140 auto ret = *this;
2141 --(*this);
2142 return ret;
2143 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002144 general_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002145 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002146 general_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002147 return ret += n;
2148 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002149 general_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002150 {
2151 m_itr += n;
2152 return *this;
2153 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002154 general_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002155 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002156 general_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002157 return ret -= n;
2158 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002159 general_span_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002160 difference_type operator-(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002161 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002162 Expects(m_container == rhs.m_container);
Neil MacIntosh68064d62015-11-03 19:17:11 -08002163 return m_itr - rhs.m_itr;
2164 }
2165 value_type operator[](difference_type n) const noexcept
2166 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002167 return (*m_container)[m_itr[n]];
2168 ;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002169 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002170 bool operator==(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002171 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002172 Expects(m_container == rhs.m_container);
Neil MacIntosh68064d62015-11-03 19:17:11 -08002173 return m_itr == rhs.m_itr;
2174 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002175 bool operator!=(const general_span_iterator& rhs) const noexcept { return !(*this == rhs); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002176 bool operator<(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002177 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002178 Expects(m_container == rhs.m_container);
Neil MacIntosh68064d62015-11-03 19:17:11 -08002179 return m_itr < rhs.m_itr;
2180 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002181 bool operator<=(const general_span_iterator& rhs) const noexcept { return !(rhs < *this); }
2182 bool operator>(const general_span_iterator& rhs) const noexcept { return rhs < *this; }
2183 bool operator>=(const general_span_iterator& rhs) const noexcept { return !(rhs > *this); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002184 void swap(general_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002185 {
2186 std::swap(m_itr, rhs.m_itr);
2187 std::swap(m_container, rhs.m_container);
2188 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002189};
2190
Anna Gringauze8aa42482015-11-11 12:41:11 -08002191template <typename Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002192general_span_iterator<Span> operator+(typename general_span_iterator<Span>::difference_type n,
2193 const general_span_iterator<Span>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002194{
Neil MacIntosh68064d62015-11-03 19:17:11 -08002195 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002196}
2197
Neil MacIntoshef626fd2015-09-29 16:41:37 -07002198} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002199
Neil MacIntoshd5316802015-09-30 21:54:08 -07002200#ifdef _MSC_VER
2201
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002202#undef constexpr
2203#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002204
Neil MacIntoshd5316802015-09-30 21:54:08 -07002205#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002206#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07002207
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002208#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
Lukas Haselsteinere51eb222015-11-15 23:08:35 +01002209#undef noexcept
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002210#pragma pop_macro("noexcept")
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002211#endif // GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntoshd5316802015-09-30 21:54:08 -07002212
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002213#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
Neil MacIntoshe9a96022015-11-03 18:56:55 -08002214
Neil MacIntosh9a297122015-09-14 15:11:07 -07002215#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002216
Neil MacIntoshd5316802015-09-30 21:54:08 -07002217#endif // _MSC_VER
2218
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002219#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002220
Anna Gringauzef5100252015-11-12 12:48:49 -08002221#undef noexcept
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002222
2223#ifdef _MSC_VER
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002224#pragma warning(pop)
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002225#pragma pop_macro("noexcept")
2226#endif
2227
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002228#endif // GSL_THROW_ON_CONTRACT_VIOLATION
Treb Connell51da1362015-09-24 18:08:34 -07002229
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002230#endif // GSL_SPAN_H