blob: 8151737761da4c7b722825995264543295b931e1 [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// turn off some warnings that are noisy about our Expects statements
41#pragma warning(push)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080042#pragma warning(disable : 4127) // conditional expression is constant
Neil MacIntoshd13f6da2015-11-20 16:03:00 -080043
Neil MacIntoshd5316802015-09-30 21:54:08 -070044// No MSVC does constexpr fully yet
Gabriel Dos Reis6554e832015-09-28 05:10:44 -070045#pragma push_macro("constexpr")
Neil MacIntoshd13f6da2015-11-20 16:03:00 -080046#define constexpr
Neil MacIntoshd5316802015-09-30 21:54:08 -070047
48// VS 2013 workarounds
49#if _MSC_VER <= 1800
50
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080051#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
52#define GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
Neil MacIntoshe9a96022015-11-03 18:56:55 -080053
Anna Gringauzee3878a62015-11-30 12:24:00 -080054// noexcept is not understood
55#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntosh292f81e2015-11-17 15:07:51 -080056#pragma push_macro("noexcept")
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080057#define noexcept /* nothing */
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070058#endif
59
Neil MacIntoshd5316802015-09-30 21:54:08 -070060// turn off some misguided warnings
Neil MacIntosh9a297122015-09-14 15:11:07 -070061#pragma warning(push)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080062#pragma warning(disable : 4351) // warns about newly introduced aggregate initializer behavior
63#pragma warning(disable : 4512) // warns that assignment op could not be generated
Neil MacIntoshd5316802015-09-30 21:54:08 -070064
Neil MacIntosh9a297122015-09-14 15:11:07 -070065#endif // _MSC_VER <= 1800
66
Neil MacIntoshd5316802015-09-30 21:54:08 -070067#endif // _MSC_VER
68
Neil MacIntoshd13f6da2015-11-20 16:03:00 -080069#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntosh292f81e2015-11-17 15:07:51 -080070
71#ifdef _MSC_VER
72#pragma push_macro("noexcept")
73#endif
74
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080075#define noexcept /* nothing */
Neil MacIntosh292f81e2015-11-17 15:07:51 -080076
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080077#endif // GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntoshd5316802015-09-30 21:54:08 -070078
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080079namespace gsl
80{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070081
82/*
83** begin definitions of index and bounds
84*/
85namespace details
86{
Neil MacIntosh68064d62015-11-03 19:17:11 -080087 template <typename SizeType>
88 struct SizeTypeTraits
89 {
90 static const SizeType max_value = std::numeric_limits<SizeType>::max();
91 };
Anna Gringauze1c208b32015-10-16 17:40:57 -070092
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080093 template <typename... Ts>
94 class are_integral : public std::integral_constant<bool, true>
95 {
96 };
Anna Gringauze1c208b32015-10-16 17:40:57 -070097
Neil MacIntosh0cf947d2015-11-24 12:49:03 -080098 template <typename T, typename... Ts>
99 class are_integral<T, Ts...>
100 : public std::integral_constant<bool,
101 std::is_integral<T>::value && are_integral<Ts...>::value>
102 {
103 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700104}
105
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700106template <size_t Rank>
Anna Gringauzedb384972015-10-05 12:34:23 -0700107class index final
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700108{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800109 static_assert(Rank > 0, "Rank must be greater than 0!");
Anna Gringauzedb384972015-10-05 12:34:23 -0700110
Neil MacIntosh68064d62015-11-03 19:17:11 -0800111 template <size_t OtherRank>
112 friend class index;
Anna Gringauzedb384972015-10-05 12:34:23 -0700113
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700114public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800115 static const size_t rank = Rank;
116 using value_type = std::ptrdiff_t;
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700117 using size_type = value_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800118 using reference = std::add_lvalue_reference_t<value_type>;
119 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700120
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800121 constexpr index() noexcept {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700122
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800123 constexpr index(const value_type (&values)[Rank]) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800124 {
125 std::copy(values, values + Rank, elems);
126 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700127
Anna Gringauze8aa42482015-11-11 12:41:11 -0800128#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800129 template <
130 typename T, typename... Ts,
131 typename = std::enable_if_t<((sizeof...(Ts) + 1) == Rank) && std::is_integral<T>::value &&
132 details::are_integral<Ts...>::value>>
133 constexpr index(T t, Ts... ds)
134 : index({narrow_cast<value_type>(t), narrow_cast<value_type>(ds)...})
135 {
136 }
Anna Gringauze8aa42482015-11-11 12:41:11 -0800137#else
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800138 template <typename... Ts, typename = std::enable_if_t<(sizeof...(Ts) == Rank) &&
139 details::are_integral<Ts...>::value>>
140 constexpr index(Ts... ds) noexcept : elems{narrow_cast<value_type>(ds)...}
141 {
142 }
Anna Gringauze8aa42482015-11-11 12:41:11 -0800143#endif
Anna Gringauzedb384972015-10-05 12:34:23 -0700144
Neil MacIntosh68064d62015-11-03 19:17:11 -0800145 constexpr index(const index& other) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700146
Neil MacIntosh68064d62015-11-03 19:17:11 -0800147 constexpr index& operator=(const index& rhs) noexcept = default;
Anna Gringauzedb384972015-10-05 12:34:23 -0700148
Neil MacIntosh68064d62015-11-03 19:17:11 -0800149 // Preconditions: component_idx < rank
150 constexpr reference operator[](size_t component_idx)
151 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800152 Expects(component_idx < Rank); // Component index must be less than rank
Neil MacIntosh68064d62015-11-03 19:17:11 -0800153 return elems[component_idx];
154 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700155
Neil MacIntosh68064d62015-11-03 19:17:11 -0800156 // Preconditions: component_idx < rank
157 constexpr const_reference operator[](size_t component_idx) const noexcept
158 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800159 Expects(component_idx < Rank); // Component index must be less than rank
Neil MacIntosh68064d62015-11-03 19:17:11 -0800160 return elems[component_idx];
161 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700162
Neil MacIntosh68064d62015-11-03 19:17:11 -0800163 constexpr bool operator==(const index& rhs) const noexcept
164 {
165 return std::equal(elems, elems + rank, rhs.elems);
166 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700167
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800168 constexpr bool operator!=(const index& rhs) const noexcept { return !(this == rhs); }
Anna Gringauzedb384972015-10-05 12:34:23 -0700169
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800170 constexpr index operator+() const noexcept { return *this; }
Anna Gringauzedb384972015-10-05 12:34:23 -0700171
Neil MacIntosh68064d62015-11-03 19:17:11 -0800172 constexpr index operator-() const noexcept
173 {
174 index ret = *this;
175 std::transform(ret, ret + rank, ret, std::negate<value_type>{});
176 return ret;
177 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700178
Neil MacIntosh68064d62015-11-03 19:17:11 -0800179 constexpr index operator+(const index& rhs) const noexcept
180 {
181 index ret = *this;
182 ret += rhs;
183 return ret;
184 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700185
Neil MacIntosh68064d62015-11-03 19:17:11 -0800186 constexpr index operator-(const index& rhs) const noexcept
187 {
188 index ret = *this;
189 ret -= rhs;
190 return ret;
191 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700192
Neil MacIntosh68064d62015-11-03 19:17:11 -0800193 constexpr index& operator+=(const index& rhs) noexcept
194 {
195 std::transform(elems, elems + rank, rhs.elems, elems, std::plus<value_type>{});
196 return *this;
197 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700198
Neil MacIntosh68064d62015-11-03 19:17:11 -0800199 constexpr index& operator-=(const index& rhs) noexcept
200 {
201 std::transform(elems, elems + rank, rhs.elems, elems, std::minus<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*(value_type v) const noexcept
206 {
207 index ret = *this;
208 ret *= v;
209 return ret;
210 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700211
Neil MacIntosh68064d62015-11-03 19:17:11 -0800212 constexpr index operator/(value_type v) const noexcept
213 {
214 index ret = *this;
215 ret /= v;
216 return ret;
217 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700218
Neil MacIntosh68064d62015-11-03 19:17:11 -0800219 friend constexpr index operator*(value_type v, const index& rhs) noexcept
220 {
221 return rhs * v;
222 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700223
Neil MacIntosh68064d62015-11-03 19:17:11 -0800224 constexpr index& operator*=(value_type v) noexcept
225 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800226 std::transform(elems, elems + rank, elems,
227 [v](value_type x) { return std::multiplies<value_type>{}(x, v); });
Neil MacIntosh68064d62015-11-03 19:17:11 -0800228 return *this;
229 }
Anna Gringauzedb384972015-10-05 12:34:23 -0700230
Neil MacIntosh68064d62015-11-03 19:17:11 -0800231 constexpr index& operator/=(value_type v) noexcept
232 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800233 std::transform(elems, elems + rank, elems,
234 [v](value_type x) { return std::divides<value_type>{}(x, v); });
Neil MacIntosh68064d62015-11-03 19:17:11 -0800235 return *this;
236 }
Anna Gringauze546f8cc2015-10-05 21:04:56 -0700237
Anna Gringauzedb384972015-10-05 12:34:23 -0700238private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800239 value_type elems[Rank] = {};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700240};
241
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700242#ifndef _MSC_VER
243
244struct static_bounds_dynamic_range_t
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700245{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800246 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
247 constexpr operator T() const noexcept
248 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800249 return narrow_cast<T>(-1);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800250 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700251
Neil MacIntosh68064d62015-11-03 19:17:11 -0800252 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800253 constexpr bool operator==(T other) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800254 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800255 return narrow_cast<T>(-1) == other;
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 MacIntosha9dcbe02015-08-20 18:09:14 -0700263};
264
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700265template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800266constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700267{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800268 return right == left;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700269}
270
271template <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
277constexpr static_bounds_dynamic_range_t dynamic_range{};
278#else
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700279const std::ptrdiff_t dynamic_range = -1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700280#endif
281
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800282struct generalized_mapping_tag
283{
284};
285struct contiguous_mapping_tag : generalized_mapping_tag
286{
287};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700288
289namespace details
290{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700291
Neil MacIntosh68064d62015-11-03 19:17:11 -0800292 template <std::ptrdiff_t Left, std::ptrdiff_t Right>
293 struct LessThan
294 {
295 static const bool value = Left < Right;
296 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700297
Neil MacIntosh68064d62015-11-03 19:17:11 -0800298 template <std::ptrdiff_t... Ranges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800299 struct BoundsRanges
300 {
301 using size_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800302 static const size_type Depth = 0;
303 static const size_type DynamicNum = 0;
304 static const size_type CurrentRange = 1;
305 static const size_type TotalSize = 1;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700306
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700307 // TODO : following signature is for work around VS bug
308 template <typename OtherRange>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800309 BoundsRanges(const OtherRange&, bool /* firstLevel */)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800310 {
311 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700312
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800313 BoundsRanges(const BoundsRanges&) = default;
314 BoundsRanges& operator=(const BoundsRanges&) = default;
315 BoundsRanges(const std::ptrdiff_t* const) {}
316 BoundsRanges() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700317
Neil MacIntosh68064d62015-11-03 19:17:11 -0800318 template <typename T, size_t Dim>
319 void serialize(T&) const
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800320 {
321 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700322
Neil MacIntosh68064d62015-11-03 19:17:11 -0800323 template <typename T, size_t Dim>
324 size_type linearize(const T&) const
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800325 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800326 return 0;
327 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700328
Neil MacIntosh68064d62015-11-03 19:17:11 -0800329 template <typename T, size_t Dim>
Neil MacIntoshf76f7392015-11-30 18:20:14 -0800330 size_type contains(const T&) const
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700331 {
Neil MacIntoshf76f7392015-11-30 18:20:14 -0800332 return -1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800333 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700334
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800335 size_type elementNum(size_t) const noexcept { return 0; }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700336
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800337 size_type totalSize() const noexcept { return TotalSize; }
338
339 bool operator==(const BoundsRanges&) const noexcept { return true; }
Neil MacIntosh68064d62015-11-03 19:17:11 -0800340 };
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700341
Neil MacIntosh68064d62015-11-03 19:17:11 -0800342 template <std::ptrdiff_t... RestRanges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800343 struct BoundsRanges<dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>
344 {
345 using Base = BoundsRanges<RestRanges...>;
346 using size_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800347 static const size_t Depth = Base::Depth + 1;
348 static const size_t DynamicNum = Base::DynamicNum + 1;
349 static const size_type CurrentRange = dynamic_range;
350 static const size_type TotalSize = dynamic_range;
351 const size_type m_bound;
352
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800353 BoundsRanges(const BoundsRanges&) = default;
354
355 BoundsRanges(const std::ptrdiff_t* const arr)
356 : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
Neil MacIntosh68064d62015-11-03 19:17:11 -0800357 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800358 Expects(0 <= *arr);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800359 }
360
361 BoundsRanges() : m_bound(0) {}
362
363 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800364 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other,
365 bool /* firstLevel */ = true)
366 : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
367 , m_bound(other.totalSize())
368 {
369 }
Neil MacIntosh68064d62015-11-03 19:17:11 -0800370
371 template <typename T, size_t Dim = 0>
372 void serialize(T& arr) const
373 {
374 arr[Dim] = elementNum();
375 this->Base::template serialize<T, Dim + 1>(arr);
376 }
377
378 template <typename T, size_t Dim = 0>
379 size_type linearize(const T& arr) const
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800380 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800381 const size_type index = this->Base::totalSize() * arr[Dim];
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800382 Expects(index < m_bound);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800383 return index + this->Base::template linearize<T, Dim + 1>(arr);
384 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700385
Neil MacIntosh68064d62015-11-03 19:17:11 -0800386 template <typename T, size_t Dim = 0>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700387 size_type contains(const T& arr) const
388 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800389 const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
390 if (last == -1) return -1;
391 const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
392 return cur < m_bound ? cur + last : -1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800393 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700394
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800395 size_type totalSize() const noexcept { return m_bound; }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700396
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800397 size_type elementNum() const noexcept { return totalSize() / this->Base::totalSize(); }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700398
Neil MacIntosh68064d62015-11-03 19:17:11 -0800399 size_type elementNum(size_t dim) const noexcept
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700400 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800401 if (dim > 0)
402 return this->Base::elementNum(dim - 1);
403 else
404 return elementNum();
405 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700406
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800407 bool operator==(const BoundsRanges& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800408 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800409 return m_bound == rhs.m_bound &&
410 static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800411 }
412 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700413
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800414 template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
415 struct BoundsRanges<CurRange, RestRanges...> : BoundsRanges<RestRanges...>
416 {
417 using Base = BoundsRanges<RestRanges...>;
418 using size_type = std::ptrdiff_t;
419 static const size_t Depth = Base::Depth + 1;
420 static const size_t DynamicNum = Base::DynamicNum;
421 static const size_type CurrentRange = CurRange;
422 static const size_type TotalSize =
423 Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700424
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800425 BoundsRanges(const BoundsRanges&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700426
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800427 BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {}
428 BoundsRanges() = default;
429
430 template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
431 BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other,
432 bool firstLevel = true)
433 : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
434 {
435 (void) firstLevel;
436 }
437
438 template <typename T, size_t Dim = 0>
439 void serialize(T& arr) const
440 {
441 arr[Dim] = elementNum();
442 this->Base::template serialize<T, Dim + 1>(arr);
443 }
444
445 template <typename T, size_t Dim = 0>
446 size_type linearize(const T& arr) const
447 {
448 Expects(arr[Dim] < CurrentRange); // Index is out of range
449 return this->Base::totalSize() * arr[Dim] +
450 this->Base::template linearize<T, Dim + 1>(arr);
451 }
452
453 template <typename T, size_t Dim = 0>
454 size_type contains(const T& arr) const
455 {
456 if (arr[Dim] >= CurrentRange) return -1;
457 const size_type last = this->Base::template contains<T, Dim + 1>(arr);
458 if (last == -1) return -1;
459 return this->Base::totalSize() * arr[Dim] + last;
460 }
461
462 size_type totalSize() const noexcept { return CurrentRange * this->Base::totalSize(); }
463
464 size_type elementNum() const noexcept { return CurrentRange; }
465
466 size_type elementNum(size_t dim) const noexcept
467 {
468 if (dim > 0)
469 return this->Base::elementNum(dim - 1);
470 else
471 return elementNum();
472 }
473
474 bool operator==(const BoundsRanges& rhs) const noexcept
475 {
476 return static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
477 }
478 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700479
Neil MacIntosh68064d62015-11-03 19:17:11 -0800480 template <typename SourceType, typename TargetType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800481 struct BoundsRangeConvertible
482 : public std::integral_constant<bool, (SourceType::TotalSize >= TargetType::TotalSize ||
483 TargetType::TotalSize == dynamic_range ||
484 SourceType::TotalSize == dynamic_range ||
485 TargetType::TotalSize == 0)>
486 {
487 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700488
Neil MacIntosh68064d62015-11-03 19:17:11 -0800489 template <typename TypeChain>
490 struct TypeListIndexer
491 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800492 const TypeChain& obj_;
493 TypeListIndexer(const TypeChain& obj) : obj_(obj) {}
494
Neil MacIntosh68064d62015-11-03 19:17:11 -0800495 template <size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800496 const TypeChain& getObj(std::true_type)
497 {
498 return obj_;
499 }
500
501 template <size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
502 auto getObj(std::false_type)
503 -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>())
504 {
505 return TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>();
506 }
507
508 template <size_t N>
509 auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, N == 0>()))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800510 {
511 return getObj<N - 1>(std::integral_constant<bool, N == 0>());
512 }
513 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700514
Neil MacIntosh68064d62015-11-03 19:17:11 -0800515 template <typename TypeChain>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800516 TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain& obj)
Neil MacIntosh68064d62015-11-03 19:17:11 -0800517 {
518 return TypeListIndexer<TypeChain>(obj);
519 }
Anna Gringauzefdf86432015-10-14 10:46:22 -0700520
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800521 template <size_t Rank, bool Enabled = (Rank > 1),
522 typename Ret = std::enable_if_t<Enabled, index<Rank - 1>>>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800523 constexpr Ret shift_left(const index<Rank>& other) noexcept
524 {
525 Ret ret{};
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800526 for (size_t i = 0; i < Rank - 1; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800527 ret[i] = other[i + 1];
528 }
529 return ret;
530 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700531}
532
533template <typename IndexType>
534class bounds_iterator;
535
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700536template <std::ptrdiff_t... Ranges>
537class static_bounds
538{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700539public:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800540 static_bounds(const details::BoundsRanges<Ranges...>&) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700541};
542
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700543template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
544class static_bounds<FirstRange, RestRanges...>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700545{
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800546 using MyRanges = details::BoundsRanges<FirstRange, RestRanges...>;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700547
Neil MacIntosh68064d62015-11-03 19:17:11 -0800548 MyRanges m_ranges;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800549 constexpr static_bounds(const MyRanges& range) : m_ranges(range) {}
550
Neil MacIntosh68064d62015-11-03 19:17:11 -0800551 template <std::ptrdiff_t... OtherRanges>
552 friend class static_bounds;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700553
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700554public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800555 static const size_t rank = MyRanges::Depth;
556 static const size_t dynamic_rank = MyRanges::DynamicNum;
557 static const std::ptrdiff_t static_size = MyRanges::TotalSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700558
Neil MacIntosh68064d62015-11-03 19:17:11 -0800559 using size_type = std::ptrdiff_t;
560 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700561 using const_index_type = std::add_const_t<index_type>;
562 using iterator = bounds_iterator<const_index_type>;
563 using const_iterator = bounds_iterator<const_index_type>;
564 using difference_type = std::ptrdiff_t;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800565 using sliced_type = static_bounds<RestRanges...>;
566 using mapping_type = contiguous_mapping_tag;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700567
Neil MacIntosh68064d62015-11-03 19:17:11 -0800568 constexpr static_bounds(const static_bounds&) = default;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800569
570 template <typename SourceType, typename TargetType, size_t Rank>
571 struct BoundsRangeConvertible2;
572
573 template <size_t Rank, typename SourceType, typename TargetType,
574 typename Ret = BoundsRangeConvertible2<typename SourceType::Base,
575 typename TargetType::Base, Rank>>
576 static auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
577
578 template <size_t Rank, typename SourceType, typename TargetType>
579 static auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
580
581 template <typename SourceType, typename TargetType, size_t Rank>
582 struct BoundsRangeConvertible2
583 : decltype(helpBoundsRangeConvertible<Rank - 1>(
584 SourceType(), TargetType(),
585 std::integral_constant<bool,
586 SourceType::Depth == TargetType::Depth &&
587 (SourceType::CurrentRange == TargetType::CurrentRange ||
588 TargetType::CurrentRange == dynamic_range ||
589 SourceType::CurrentRange == dynamic_range)>()))
590 {
591 };
592
593 template <typename SourceType, typename TargetType>
594 struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type
595 {
596 };
597
598 template <typename SourceType, typename TargetType, std::ptrdiff_t Rank = TargetType::Depth>
599 struct BoundsRangeConvertible
600 : decltype(helpBoundsRangeConvertible<Rank - 1>(
601 SourceType(), TargetType(),
602 std::integral_constant<bool,
603 SourceType::Depth == TargetType::Depth &&
604 (!details::LessThan<SourceType::CurrentRange,
605 TargetType::CurrentRange>::value ||
606 TargetType::CurrentRange == dynamic_range ||
607 SourceType::CurrentRange == dynamic_range)>()))
608 {
609 };
610
611 template <typename SourceType, typename TargetType>
612 struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type
613 {
614 };
615
616 template <std::ptrdiff_t... Ranges,
617 typename = std::enable_if_t<details::BoundsRangeConvertible<
618 details::BoundsRanges<Ranges...>,
619 details::BoundsRanges<FirstRange, RestRanges...>>::value>>
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700620 constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800621 {
622 Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges<Ranges...>::DynamicNum == 0) ||
623 MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize());
624 }
625
626 constexpr static_bounds(std::initializer_list<size_type> il)
627 : m_ranges(static_cast<const std::ptrdiff_t*>(il.begin()))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800628 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800629 // Size of the initializer list must match the rank of the array
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800630 Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) ||
631 MyRanges::DynamicNum == il.size());
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800632 // Size of the range must be less than the max element of the size type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800633 Expects(m_ranges.totalSize() <= PTRDIFF_MAX);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800634 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800635
Neil MacIntosh68064d62015-11-03 19:17:11 -0800636 constexpr static_bounds() = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700637
Neil MacIntosh68064d62015-11-03 19:17:11 -0800638 constexpr static_bounds& operator=(const static_bounds& otherBounds)
639 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800640 new (&m_ranges) MyRanges(otherBounds.m_ranges);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800641 return *this;
642 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700643
Neil MacIntosh68064d62015-11-03 19:17:11 -0800644 constexpr sliced_type slice() const noexcept
645 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800646 return sliced_type{static_cast<const details::BoundsRanges<RestRanges...>&>(m_ranges)};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800647 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700648
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800649 constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; }
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700650
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800651 constexpr size_type size() const noexcept { return m_ranges.totalSize(); }
652
653 constexpr size_type total_size() const noexcept { return m_ranges.totalSize(); }
654
655 constexpr size_type linearize(const index_type& idx) const { return m_ranges.linearize(idx); }
656
Neil MacIntosh68064d62015-11-03 19:17:11 -0800657 constexpr bool contains(const index_type& idx) const noexcept
658 {
659 return m_ranges.contains(idx) != -1;
660 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800661
Neil MacIntosh68064d62015-11-03 19:17:11 -0800662 constexpr size_type operator[](size_t index) const noexcept
663 {
664 return m_ranges.elementNum(index);
665 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800666
Neil MacIntosh68064d62015-11-03 19:17:11 -0800667 template <size_t Dim = 0>
668 constexpr size_type extent() const noexcept
669 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800670 static_assert(Dim < rank,
671 "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosh68064d62015-11-03 19:17:11 -0800672 return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
673 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800674
675 template <typename IntType>
676 constexpr size_type extent(IntType dim) const noexcept
677 {
678 static_assert(std::is_integral<IntType>::value,
679 "Dimension parameter must be supplied as an integral type.");
680 auto real_dim = narrow_cast<size_t>(dim);
681 Expects(real_dim < rank);
682
683 return m_ranges.elementNum(real_dim);
684 }
685
Neil MacIntosh68064d62015-11-03 19:17:11 -0800686 constexpr index_type index_bounds() const noexcept
687 {
688 size_type extents[rank] = {};
689 m_ranges.serialize(extents);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800690 return {extents};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800691 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800692
Neil MacIntosh68064d62015-11-03 19:17:11 -0800693 template <std::ptrdiff_t... Ranges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800694 constexpr bool operator==(const static_bounds<Ranges...>& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800695 {
696 return this->size() == rhs.size();
697 }
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 == rhs);
703 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800704
705 constexpr const_iterator begin() const noexcept { return const_iterator(*this, index_type{}); }
706
Neil MacIntosh68064d62015-11-03 19:17:11 -0800707 constexpr const_iterator end() const noexcept
708 {
709 return const_iterator(*this, this->index_bounds());
710 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700711};
712
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700713template <size_t Rank>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800714class strided_bounds
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700715{
Neil MacIntosh68064d62015-11-03 19:17:11 -0800716 template <size_t OtherRank>
717 friend class strided_bounds;
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700718
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700719public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800720 static const size_t rank = Rank;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800721 using value_type = std::ptrdiff_t;
722 using reference = std::add_lvalue_reference_t<value_type>;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800723 using const_reference = std::add_const_t<reference>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800724 using size_type = value_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800725 using difference_type = value_type;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800726 using index_type = index<rank>;
Neil MacIntosha4fa2b32015-10-28 16:53:53 -0700727 using const_index_type = std::add_const_t<index_type>;
728 using iterator = bounds_iterator<const_index_type>;
729 using const_iterator = bounds_iterator<const_index_type>;
730 static const value_type dynamic_rank = rank;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800731 static const value_type static_size = dynamic_range;
732 using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
733 using mapping_type = generalized_mapping_tag;
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700734
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800735 constexpr strided_bounds(const strided_bounds&) noexcept = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700736
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800737 constexpr strided_bounds& operator=(const strided_bounds&) noexcept = default;
Vladislav Yaroslavlev557e6692015-11-12 10:44:41 +0300738
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800739 constexpr strided_bounds(const value_type (&values)[rank], index_type strides)
Neil MacIntoshace9ab92015-10-23 19:49:17 -0700740 : m_extents(values), m_strides(std::move(strides))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800741 {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800742 }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700743
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800744 constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept
745 : m_extents(extents),
746 m_strides(strides)
747 {
748 }
749
750 constexpr index_type strides() const noexcept { return m_strides; }
751
Neil MacIntosh68064d62015-11-03 19:17:11 -0800752 constexpr size_type total_size() const noexcept
753 {
754 size_type ret = 0;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800755 for (size_t i = 0; i < rank; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800756 ret += (m_extents[i] - 1) * m_strides[i];
757 }
758 return ret + 1;
759 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800760
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700761 constexpr size_type size() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800762 {
763 size_type ret = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800764 for (size_t i = 0; i < rank; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800765 ret *= m_extents[i];
766 }
767 return ret;
768 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800769
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700770 constexpr bool contains(const index_type& idx) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -0800771 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800772 for (size_t i = 0; i < rank; ++i) {
773 if (idx[i] < 0 || idx[i] >= m_extents[i]) return false;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800774 }
775 return true;
776 }
Neil MacIntoshd0f09e72015-10-15 16:38:53 -0700777
Neil MacIntosh68064d62015-11-03 19:17:11 -0800778 constexpr size_type linearize(const index_type& idx) const noexcept
779 {
780 size_type ret = 0;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800781 for (size_t i = 0; i < rank; i++) {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -0800782 Expects(idx[i] < m_extents[i]); // index is out of bounds of the array
Neil MacIntosh68064d62015-11-03 19:17:11 -0800783 ret += idx[i] * m_strides[i];
784 }
785 return ret;
786 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800787
788 constexpr size_type stride() const noexcept { return m_strides[0]; }
789
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700790 template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800791 constexpr sliced_type slice() const
792 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800793 return {details::shift_left(m_extents), details::shift_left(m_strides)};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800794 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800795
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700796 template <size_t Dim = 0>
Neil MacIntosh68064d62015-11-03 19:17:11 -0800797 constexpr size_type extent() const noexcept
798 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800799 static_assert(Dim < Rank,
800 "dimension should be less than rank (dimension count starts from 0)");
Neil MacIntosh68064d62015-11-03 19:17:11 -0800801 return m_extents[Dim];
802 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800803
804 constexpr index_type index_bounds() const noexcept { return m_extents; }
805 constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; }
806
807 constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; }
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700808
Anna Gringauze17ed5c32015-08-30 23:30:15 -0700809private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800810 index_type m_extents;
811 index_type m_strides;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700812};
813
814template <typename T>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800815struct is_bounds : std::integral_constant<bool, false>
816{
817};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700818template <std::ptrdiff_t... Ranges>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800819struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true>
820{
821};
Neil MacIntoshf45fedb2015-10-15 14:29:35 -0700822template <size_t Rank>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800823struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true>
824{
825};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700826
827template <typename IndexType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800828class bounds_iterator : public std::iterator<std::random_access_iterator_tag, IndexType>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700829{
830private:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800831 using Base = std::iterator<std::random_access_iterator_tag, IndexType>;
Anna Gringauzea4654a42015-10-16 12:15:22 -0700832
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700833public:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800834 static const size_t rank = IndexType::rank;
835 using typename Base::reference;
836 using typename Base::pointer;
837 using typename Base::difference_type;
838 using typename Base::value_type;
839 using index_type = value_type;
840 using index_size_type = typename IndexType::value_type;
841 template <typename Bounds>
842 explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000843 : boundary_(bnd.index_bounds()),
844 curr_(std::move(curr))
Neil MacIntosh68064d62015-11-03 19:17:11 -0800845 {
846 static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
847 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700848
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000849 constexpr reference operator*() const noexcept { return curr_; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700850
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000851 constexpr pointer operator->() const noexcept { return &curr_; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700852
Neil MacIntosh68064d62015-11-03 19:17:11 -0800853 constexpr bounds_iterator& operator++() noexcept
854 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800855 for (size_t i = rank; i-- > 0;) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000856 if (curr_[i] < boundary_[i] - 1) {
857 curr_[i]++;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800858 return *this;
859 }
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000860 curr_[i] = 0;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800861 }
862 // If we're here we've wrapped over - set to past-the-end.
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000863 curr_ = boundary_;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800864 return *this;
865 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700866
Neil MacIntosh68064d62015-11-03 19:17:11 -0800867 constexpr bounds_iterator operator++(int) noexcept
868 {
869 auto ret = *this;
870 ++(*this);
871 return ret;
872 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700873
Neil MacIntosh68064d62015-11-03 19:17:11 -0800874 constexpr bounds_iterator& operator--() noexcept
875 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000876 if (!less(curr_, boundary_)) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800877 // if at the past-the-end, set to last element
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800878 for (size_t i = 0; i < rank; ++i) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000879 curr_[i] = boundary_[i] - 1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800880 }
881 return *this;
882 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800883 for (size_t i = rank; i-- > 0;) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000884 if (curr_[i] >= 1) {
885 curr_[i]--;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800886 return *this;
887 }
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000888 curr_[i] = boundary_[i] - 1;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800889 }
890 // If we're here the preconditions were violated
891 // "pre: there exists s such that r == ++s"
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800892 Expects(false);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800893 return *this;
894 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700895
Neil MacIntosh68064d62015-11-03 19:17:11 -0800896 constexpr bounds_iterator operator--(int) noexcept
897 {
898 auto ret = *this;
899 --(*this);
900 return ret;
901 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700902
Neil MacIntosh68064d62015-11-03 19:17:11 -0800903 constexpr bounds_iterator operator+(difference_type n) const noexcept
904 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800905 bounds_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800906 return ret += n;
907 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700908
Neil MacIntosh68064d62015-11-03 19:17:11 -0800909 constexpr bounds_iterator& operator+=(difference_type n) noexcept
910 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000911 auto linear_idx = linearize(curr_) + n;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800912 std::remove_const_t<value_type> stride = 0;
913 stride[rank - 1] = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800914 for (size_t i = rank - 1; i-- > 0;) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000915 stride[i] = stride[i + 1] * boundary_[i + 1];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800916 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800917 for (size_t i = 0; i < rank; ++i) {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000918 curr_[i] = linear_idx / stride[i];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800919 linear_idx = linear_idx % stride[i];
920 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800921 // index is out of bounds of the array
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000922 Expects(!less(curr_, index_type{}) && !less(boundary_, curr_));
Neil MacIntosh68064d62015-11-03 19:17:11 -0800923 return *this;
924 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700925
Neil MacIntosh68064d62015-11-03 19:17:11 -0800926 constexpr bounds_iterator operator-(difference_type n) const noexcept
927 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800928 bounds_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -0800929 return ret -= n;
930 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700931
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800932 constexpr bounds_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700933
Neil MacIntosh68064d62015-11-03 19:17:11 -0800934 constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
935 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000936 return linearize(curr_) - linearize(rhs.curr_);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800937 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700938
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800939 constexpr value_type operator[](difference_type n) const noexcept { return *(*this + n); }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700940
Neil MacIntosh68064d62015-11-03 19:17:11 -0800941 constexpr bool operator==(const bounds_iterator& rhs) const noexcept
942 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000943 return curr_ == rhs.curr_;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800944 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700945
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800946 constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700947
Neil MacIntosh68064d62015-11-03 19:17:11 -0800948 constexpr bool operator<(const bounds_iterator& rhs) const noexcept
949 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000950 return less(curr_, rhs.curr_);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800951 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700952
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800953 constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700954
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800955 constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700956
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800957 constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700958
Neil MacIntosh68064d62015-11-03 19:17:11 -0800959 void swap(bounds_iterator& rhs) noexcept
960 {
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000961 std::swap(boundary_, rhs.boundary_);
962 std::swap(curr_, rhs.curr_);
Neil MacIntosh68064d62015-11-03 19:17:11 -0800963 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800964
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700965private:
Neil MacIntosh68064d62015-11-03 19:17:11 -0800966 constexpr bool less(index_type& one, index_type& other) const noexcept
967 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800968 for (size_t i = 0; i < rank; ++i) {
969 if (one[i] < other[i]) return true;
Neil MacIntosh68064d62015-11-03 19:17:11 -0800970 }
971 return false;
972 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700973
Neil MacIntosh68064d62015-11-03 19:17:11 -0800974 constexpr index_size_type linearize(const value_type& idx) const noexcept
975 {
976 // TODO: Smarter impl.
977 // Check if past-the-end
978 index_size_type multiplier = 1;
979 index_size_type res = 0;
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000980 if (!less(idx, boundary_)) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800981 res = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800982 for (size_t i = rank; i-- > 0;) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800983 res += (idx[i] - 1) * multiplier;
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000984 multiplier *= boundary_[i];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800985 }
986 }
987 else
988 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -0800989 for (size_t i = rank; i-- > 0;) {
Neil MacIntosh68064d62015-11-03 19:17:11 -0800990 res += idx[i] * multiplier;
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000991 multiplier *= boundary_[i];
Neil MacIntosh68064d62015-11-03 19:17:11 -0800992 }
993 }
994 return res;
995 }
Anna Gringauzea4654a42015-10-16 12:15:22 -0700996
Neil MacIntoshc9959b12015-11-30 05:34:38 +0000997 value_type boundary_;
998 std::remove_const_t<value_type> curr_;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700999};
1000
1001template <typename IndexType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001002bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n,
1003 const bounds_iterator<IndexType>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001004{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001005 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001006}
1007
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001008namespace details
1009{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001010 template <typename Bounds>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001011 constexpr std::enable_if_t<
1012 std::is_same<typename Bounds::mapping_type, generalized_mapping_tag>::value,
1013 typename Bounds::index_type>
1014 make_stride(const Bounds& bnd) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001015 {
1016 return bnd.strides();
1017 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001018
Neil MacIntosh68064d62015-11-03 19:17:11 -08001019 // Make a stride vector from bounds, assuming contiguous memory.
1020 template <typename Bounds>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001021 constexpr std::enable_if_t<
1022 std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value,
1023 typename Bounds::index_type>
1024 make_stride(const Bounds& bnd) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001025 {
1026 auto extents = bnd.index_bounds();
1027 typename Bounds::size_type stride[Bounds::rank] = {};
Anna Gringauzedb384972015-10-05 12:34:23 -07001028
Neil MacIntosh68064d62015-11-03 19:17:11 -08001029 stride[Bounds::rank - 1] = 1;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001030 for (size_t i = 1; i < Bounds::rank; ++i) {
Neil MacIntosh68064d62015-11-03 19:17:11 -08001031 stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
1032 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001033 return {stride};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001034 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001035
Neil MacIntosh68064d62015-11-03 19:17:11 -08001036 template <typename BoundsSrc, typename BoundsDest>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001037 void verifyBoundsReshape(const BoundsSrc& src, const BoundsDest& dest)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001038 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001039 static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value,
1040 "The src type and dest type must be bounds");
1041 static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value,
1042 "The source type must be a contiguous bounds");
1043 static_assert(BoundsDest::static_size == dynamic_range ||
1044 BoundsSrc::static_size == dynamic_range ||
1045 BoundsDest::static_size == BoundsSrc::static_size,
1046 "The source bounds must have same size as dest bounds");
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001047 Expects(src.size() == dest.size());
Neil MacIntosh68064d62015-11-03 19:17:11 -08001048 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001049
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001050} // namespace details
1051
Anna Gringauze8aa42482015-11-11 12:41:11 -08001052template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001053class contiguous_span_iterator;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001054template <typename Span>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001055class general_span_iterator;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001056enum class byte : std::uint8_t
1057{
1058};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001059
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001060template <std::ptrdiff_t DimSize = dynamic_range>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001061struct dim
1062{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001063 static const std::ptrdiff_t value = DimSize;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001064};
1065template <>
1066struct dim<dynamic_range>
1067{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001068 static const std::ptrdiff_t value = dynamic_range;
1069 const std::ptrdiff_t dvalue;
1070 dim(std::ptrdiff_t size) : dvalue(size) {}
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001071};
1072
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001073template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range,
1074 std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001075class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001076
1077template <typename ValueType, size_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001078class strided_span;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001079
1080namespace details
1081{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001082 template <typename T, typename = std::true_type>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001083 struct SpanTypeTraits
Neil MacIntosh68064d62015-11-03 19:17:11 -08001084 {
1085 using value_type = T;
1086 using size_type = size_t;
1087 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001088
Neil MacIntosh68064d62015-11-03 19:17:11 -08001089 template <typename Traits>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001090 struct SpanTypeTraits<Traits, typename std::is_reference<typename Traits::span_traits&>::type>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001091 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001092 using value_type = typename Traits::span_traits::value_type;
1093 using size_type = typename Traits::span_traits::size_type;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001094 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001095
Neil MacIntosh68064d62015-11-03 19:17:11 -08001096 template <typename T, std::ptrdiff_t... Ranks>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001097 struct SpanArrayTraits
1098 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001099 using type = span<T, Ranks...>;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001100 using value_type = T;
1101 using bounds_type = static_bounds<Ranks...>;
1102 using pointer = T*;
1103 using reference = T&;
1104 };
1105 template <typename T, std::ptrdiff_t N, std::ptrdiff_t... Ranks>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001106 struct SpanArrayTraits<T[N], Ranks...> : SpanArrayTraits<T, Ranks..., N>
1107 {
1108 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001109
Neil MacIntosh68064d62015-11-03 19:17:11 -08001110 template <typename BoundsType>
1111 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
1112 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001113 Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001114 return BoundsType{totalSize};
1115 }
1116 template <typename BoundsType>
1117 BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
1118 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001119 Expects(BoundsType::static_size <= totalSize);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001120 return {};
1121 }
1122 template <typename BoundsType>
1123 BoundsType newBoundsHelper(std::ptrdiff_t totalSize)
1124 {
1125 static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001126 return newBoundsHelperImpl<BoundsType>(
1127 totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
Neil MacIntosh68064d62015-11-03 19:17:11 -08001128 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001129
1130 struct Sep
1131 {
1132 };
1133
Neil MacIntosh68064d62015-11-03 19:17:11 -08001134 template <typename T, typename... Args>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001135 T static_as_span_helper(Sep, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001136 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001137 return T{narrow_cast<typename T::size_type>(args)...};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001138 }
1139 template <typename T, typename Arg, typename... Args>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001140 std::enable_if_t<
1141 !std::is_same<Arg, dim<dynamic_range>>::value && !std::is_same<Arg, Sep>::value, T>
1142 static_as_span_helper(Arg, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001143 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001144 return static_as_span_helper<T>(args...);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001145 }
1146 template <typename T, typename... Args>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001147 T static_as_span_helper(dim<dynamic_range> val, Args... args)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001148 {
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001149 return static_as_span_helper<T>(args..., val.dvalue);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001150 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001151
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001152 template <typename... Dimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001153 struct static_as_span_static_bounds_helper
Neil MacIntosh68064d62015-11-03 19:17:11 -08001154 {
1155 using type = static_bounds<(Dimensions::value)...>;
1156 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001157
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001158 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001159 struct is_span_oracle : std::false_type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001160 {
1161 };
Neil MacIntosh68064d62015-11-03 19:17:11 -08001162
1163 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001164 struct is_span_oracle<span<ValueType, FirstDimension, RestDimensions...>> : std::true_type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001165 {
1166 };
1167
Neil MacIntosh68064d62015-11-03 19:17:11 -08001168 template <typename ValueType, std::ptrdiff_t Rank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001169 struct is_span_oracle<strided_span<ValueType, Rank>> : std::true_type
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001170 {
1171 };
1172
Neil MacIntosh68064d62015-11-03 19:17:11 -08001173 template <typename T>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001174 struct is_span : is_span_oracle<std::remove_cv_t<T>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001175 {
1176 };
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001177}
1178
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001179template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
Anna Gringauze8aa42482015-11-11 12:41:11 -08001180class span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001181{
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001182 // TODO do we still need this?
1183 template <typename ValueType2, std::ptrdiff_t FirstDimension2,
1184 std::ptrdiff_t... RestDimensions2>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001185 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001186
Anna Gringauze8aa42482015-11-11 12:41:11 -08001187public:
Anna Gringauzef5100252015-11-12 12:48:49 -08001188 using bounds_type = static_bounds<FirstDimension, RestDimensions...>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001189 static const size_t Rank = bounds_type::rank;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001190 using size_type = typename bounds_type::size_type;
1191 using index_type = typename bounds_type::index_type;
1192 using value_type = ValueType;
1193 using const_value_type = std::add_const_t<value_type>;
Anna Gringauzef5100252015-11-12 12:48:49 -08001194 using pointer = std::add_pointer_t<value_type>;
1195 using reference = std::add_lvalue_reference_t<value_type>;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001196 using iterator = contiguous_span_iterator<span>;
1197 using const_span = span<const_value_type, FirstDimension, RestDimensions...>;
1198 using const_iterator = contiguous_span_iterator<const_span>;
1199 using reverse_iterator = std::reverse_iterator<iterator>;
1200 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001201 using sliced_type =
1202 std::conditional_t<Rank == 1, value_type, span<value_type, RestDimensions...>>;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001203
1204private:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001205 pointer data_;
1206 bounds_type bounds_;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001207
1208 friend iterator;
1209 friend const_iterator;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001210
1211public:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001212 // default constructor - same as constructing from nullptr_t
1213 constexpr span() noexcept : span(nullptr, bounds_type{})
Anna Gringauze8aa42482015-11-11 12:41:11 -08001214 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001215 static_assert(bounds_type::dynamic_rank != 0 ||
1216 (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
1217 "Default construction of span<T> only possible "
1218 "for dynamic or fixed, zero-length spans.");
Anna Gringauze8aa42482015-11-11 12:41:11 -08001219 }
1220
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001221 // construct from nullptr - get an empty span
1222 constexpr span(std::nullptr_t) noexcept : span(nullptr, bounds_type{})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001223 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001224 static_assert(bounds_type::dynamic_rank != 0 ||
1225 (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
1226 "nullptr_t construction of span<T> only possible "
1227 "for dynamic or fixed, zero-length spans.");
1228 }
1229
1230 // construct from nullptr with size of 0 (helps with template function calls)
1231 template <class IntType, typename = std::enable_if_t<std::is_integral<IntType>::value>>
1232 constexpr span(std::nullptr_t, IntType size) noexcept : span(nullptr, bounds_type{})
1233 {
1234 static_assert(bounds_type::dynamic_rank != 0 ||
1235 (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
1236 "nullptr_t construction of span<T> only possible "
1237 "for dynamic or fixed, zero-length spans.");
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001238 Expects(size == 0);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001239 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001240
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001241 // construct from a single element
1242 constexpr span(reference data) noexcept : span(&data, bounds_type{1})
Neil MacIntosh68064d62015-11-03 19:17:11 -08001243 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001244 static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 ||
1245 bounds_type::static_size == 1,
1246 "Construction from a single element only possible "
1247 "for dynamic or fixed spans of length 0 or 1.");
Neil MacIntosh68064d62015-11-03 19:17:11 -08001248 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001249
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001250 // prevent constructing from temporaries for single-elements
1251 constexpr span(value_type&&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001252
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001253 // construct from pointer + length
1254 constexpr span(pointer ptr, size_type size) noexcept : span(ptr, bounds_type{size}) {}
1255
1256 // construct from pointer + length - multidimensional
1257 constexpr span(pointer data, bounds_type bounds) noexcept : data_(data),
1258 bounds_(std::move(bounds))
1259 {
1260 Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0);
1261 }
1262
1263 // construct from begin,end pointer pair
Neil MacIntosh68064d62015-11-03 19:17:11 -08001264 template <typename Ptr,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001265 typename = std::enable_if_t<std::is_convertible<Ptr, pointer>::value &&
1266 details::LessThan<bounds_type::dynamic_rank, 2>::value>>
1267 constexpr span(pointer begin, Ptr end)
1268 : span(begin, details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin))
1269 {
1270 Expects(begin != nullptr && end != nullptr && begin <= static_cast<pointer>(end));
1271 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001272
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001273 // construct from n-dimensions static array
1274 template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>>
1275 constexpr span(T (&arr)[N])
1276 : span(reinterpret_cast<pointer>(arr), bounds_type{typename Helper::bounds_type{}})
1277 {
1278 static_assert(
1279 std::is_convertible<typename Helper::value_type(*) [], value_type(*) []>::value,
1280 "Cannot convert from source type to target span type.");
1281 static_assert(std::is_convertible<typename Helper::bounds_type, bounds_type>::value,
1282 "Cannot construct a span from an array with fewer elements.");
1283 }
1284
1285 // construct from n-dimensions dynamic array (e.g. new int[m][4])
1286 // (precedence will be lower than the 1-dimension pointer)
1287 template <typename T, typename Helper = details::SpanArrayTraits<T, dynamic_range>>
1288 constexpr span(T* const& data, size_type size)
1289 : span(reinterpret_cast<pointer>(data), typename Helper::bounds_type{size})
1290 {
1291 static_assert(
1292 std::is_convertible<typename Helper::value_type(*) [], value_type(*) []>::value,
1293 "Cannot convert from source type to target span type.");
1294 }
1295
1296 // construct from std::array
1297 template <typename T, size_t N>
1298 constexpr span(std::array<T, N>& arr) : span(arr.data(), bounds_type{static_bounds<N>{}})
1299 {
1300 static_assert(
1301 std::is_convertible<T(*) [], typename std::remove_const_t<value_type>(*) []>::value,
1302 "Cannot convert from source type to target span type.");
1303 static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value,
1304 "You cannot construct a span from a std::array of smaller size.");
1305 }
1306
1307 // construct from const std::array
1308 template <typename T, size_t N>
1309 constexpr span(const std::array<std::remove_const_t<value_type>, N>& arr)
1310 : span(arr.data(), static_bounds<N>())
1311 {
1312 static_assert(std::is_convertible<T(*) [], std::remove_const_t<value_type>>::value,
1313 "Cannot convert from source type to target span type.");
1314 static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value,
1315 "You cannot construct a span from a std::array of smaller size.");
1316 }
1317
1318 // prevent constructing from temporary std::array
1319 template <typename T, size_t N>
1320 constexpr span(std::array<T, N>&& arr) = delete;
1321
1322 // construct from containers
1323 // future: could use contiguous_iterator_traits to identify only contiguous containers
1324 // type-requirements: container must have .size(), operator[] which are value_type compatible
Neil MacIntosh68064d62015-11-03 19:17:11 -08001325 template <typename Cont, typename DataType = typename Cont::value_type,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001326 typename = std::enable_if_t<
1327 !details::is_span<Cont>::value &&
1328 std::is_convertible<DataType (*)[], value_type (*)[]>::value &&
1329 std::is_same<std::decay_t<decltype(std::declval<Cont>().size(),
1330 *std::declval<Cont>().data())>,
1331 DataType>::value>>
1332 constexpr span(Cont& cont)
1333 : span(static_cast<pointer>(cont.data()),
1334 details::newBoundsHelper<bounds_type>(narrow_cast<size_type>(cont.size())))
1335 {
1336 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001337
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001338 // prevent constructing from temporary containers
1339 template <typename Cont, typename DataType = typename Cont::value_type,
1340 typename = std::enable_if_t<
1341 !details::is_span<Cont>::value &&
1342 std::is_convertible<DataType (*)[], value_type (*)[]>::value &&
1343 std::is_same<std::decay_t<decltype(std::declval<Cont>().size(),
1344 *std::declval<Cont>().data())>,
1345 DataType>::value>>
1346 explicit constexpr span(Cont&& cont) = delete;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001347
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001348 // construct from a convertible span
Neil MacIntosh68064d62015-11-03 19:17:11 -08001349 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001350 typename OtherBounds = static_bounds<OtherDimensions...>,
1351 typename = std::enable_if_t<std::is_convertible<OtherValueType, ValueType>::value &&
1352 std::is_convertible<OtherBounds, bounds_type>::value>>
1353 constexpr span(span<OtherValueType, OtherDimensions...> other) noexcept : data_(other.data_),
1354 bounds_(other.bounds_)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001355 {
Neil MacIntosh68064d62015-11-03 19:17:11 -08001356 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001357
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001358// trivial copy and move
1359#ifndef GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
1360 constexpr span(span&&) = default;
1361#endif
1362 constexpr span(const span&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001363
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001364// trivial assignment
1365#ifndef GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
1366 constexpr span& operator=(span&&) = default;
1367#endif
1368 constexpr span& operator=(const span&) = default;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001369
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001370 // first() - extract the first Count elements into a new span
1371 template <std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001372 constexpr span<ValueType, Count> first() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001373 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001374 static_assert(Count >= 0, "Count must be >= 0.");
1375 static_assert(bounds_type::static_size == dynamic_range ||
1376 Count <= bounds_type::static_size,
1377 "Count is out of bounds.");
1378
1379 Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
1380 return {this->data(), Count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001381 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001382
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001383 // first() - extract the first count elements into a new span
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001384 constexpr span<ValueType, dynamic_range> first(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001385 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001386 Expects(count >= 0 && count <= this->size());
1387 return {this->data(), count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001388 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001389
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001390 // last() - extract the last Count elements into a new span
1391 template <std::ptrdiff_t Count>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001392 constexpr span<ValueType, Count> last() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001393 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001394 static_assert(Count >= 0, "Count must be >= 0.");
1395 static_assert(bounds_type::static_size == dynamic_range ||
1396 Count <= bounds_type::static_size,
1397 "Count is out of bounds.");
1398
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001399 Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001400 return {this->data() + this->size() - Count, Count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001401 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001402
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001403 // last() - extract the last count elements into a new span
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001404 constexpr span<ValueType, dynamic_range> last(size_type count) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001405 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001406 Expects(count >= 0 && count <= this->size());
1407 return {this->data() + this->size() - count, count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001408 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001409
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001410 // subspan() - create a subview of Count elements starting at Offset
1411 template <std::ptrdiff_t Offset, std::ptrdiff_t Count>
1412 constexpr span<ValueType, Count> subspan() const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001413 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001414 static_assert(Count >= 0, "Count must be >= 0.");
1415 static_assert(Offset >= 0, "Offset must be >= 0.");
1416 static_assert(bounds_type::static_size == dynamic_range ||
1417 ((Offset <= bounds_type::static_size) &&
1418 Count <= bounds_type::static_size - Offset),
1419 "You must describe a sub-range within bounds of the span.");
1420
1421 Expects(bounds_type::static_size != dynamic_range ||
1422 (Offset <= this->size() && Count <= this->size() - Offset));
1423 return {this->data() + Offset, Count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001424 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001425
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001426 // subspan() - create a subview of count elements starting at offset
1427 // supplying dynamic_range for count will consume all available elements from offset
1428 constexpr span<ValueType, dynamic_range> subspan(size_type offset,
1429 size_type count = dynamic_range) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001430 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001431 Expects((offset >= 0 && offset <= this->size()) &&
1432 (count == dynamic_range || (count <= this->size() - offset)));
1433 return {this->data() + offset, count == dynamic_range ? this->length() - offset : count};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001434 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001435
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001436 // section - creates a non-contiguous, strided span from a contiguous one
1437 constexpr strided_span<ValueType, Rank> section(index_type origin, index_type extents) const
1438 noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08001439 {
1440 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001441 return {&this->operator[](origin), size,
1442 strided_bounds<Rank>{extents, details::make_stride(bounds())}};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001443 }
Neil MacIntosh9f9fad92015-08-27 18:13:49 -07001444
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001445 // length of the span in elements
1446 constexpr size_type size() const noexcept { return bounds_.size(); }
1447
1448 // length of the span in elements
1449 constexpr size_type length() const noexcept { return this->size(); }
1450
1451 // length of the span in bytes
1452 constexpr size_type size_bytes() const noexcept { return sizeof(value_type) * this->size(); }
1453
1454 // length of the span in bytes
1455 constexpr size_type length_bytes() const noexcept { return this->size_bytes(); }
1456
1457 constexpr bool empty() const noexcept { return this->size() == 0; }
1458
1459 static constexpr std::size_t rank() { return Rank; }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001460
1461 template <size_t Dim = 0>
1462 constexpr size_type extent() const noexcept
1463 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001464 static_assert(Dim < Rank,
1465 "Dimension should be less than rank (dimension count starts from 0).");
1466 return bounds_.template extent<Dim>();
Anna Gringauze8aa42482015-11-11 12:41:11 -08001467 }
1468
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001469 template <typename IntType>
1470 constexpr size_type extent(IntType dim) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001471 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001472 return bounds_.extent(dim);
Anna Gringauze8aa42482015-11-11 12:41:11 -08001473 }
1474
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001475 constexpr bounds_type bounds() const noexcept { return bounds_; }
1476
1477 constexpr pointer data() const noexcept { return data_; }
1478
1479 template <typename FirstIndex>
1480 constexpr reference operator()(FirstIndex index)
Anna Gringauze8aa42482015-11-11 12:41:11 -08001481 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001482 return this->operator[](narrow_cast<std::ptrdiff_t>(index));
Anna Gringauze8aa42482015-11-11 12:41:11 -08001483 }
1484
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001485 template <typename FirstIndex, typename... OtherIndices>
1486 constexpr reference operator()(FirstIndex index, OtherIndices... indices)
Anna Gringauze8aa42482015-11-11 12:41:11 -08001487 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001488 index_type idx = {narrow_cast<std::ptrdiff_t>(index),
1489 narrow_cast<std::ptrdiff_t>(indices...)};
1490 return this->operator[](idx);
Anna Gringauze8aa42482015-11-11 12:41:11 -08001491 }
1492
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001493 constexpr reference operator[](const index_type& idx) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001494 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001495 return data_[bounds_.linearize(idx)];
Anna Gringauze8aa42482015-11-11 12:41:11 -08001496 }
1497
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001498 template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
1499 constexpr Ret operator[](size_type idx) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001500 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001501 Expects(idx < bounds_.size()); // index is out of bounds of the array
1502 const size_type ridx = idx * bounds_.stride();
1503
1504 // index is out of bounds of the underlying data
1505 Expects(ridx < bounds_.total_size());
1506 return Ret{data_ + ridx, bounds_.slice()};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001507 }
1508
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001509 constexpr iterator begin() const noexcept { return iterator{this, true}; }
1510
1511 constexpr iterator end() const noexcept { return iterator{this, false}; }
1512
Anna Gringauzef5100252015-11-12 12:48:49 -08001513 constexpr const_iterator cbegin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001514 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001515 return const_iterator{reinterpret_cast<const const_span*>(this), true};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001516 }
1517
Anna Gringauzef5100252015-11-12 12:48:49 -08001518 constexpr const_iterator cend() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001519 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001520 return const_iterator{reinterpret_cast<const const_span*>(this), false};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001521 }
1522
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001523 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001524
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001525 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
Anna Gringauze8aa42482015-11-11 12:41:11 -08001526
Anna Gringauzef5100252015-11-12 12:48:49 -08001527 constexpr const_reverse_iterator crbegin() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001528 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001529 return const_reverse_iterator{cend()};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001530 }
1531
Anna Gringauzef5100252015-11-12 12:48:49 -08001532 constexpr const_reverse_iterator crend() const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001533 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001534 return const_reverse_iterator{cbegin()};
Anna Gringauze8aa42482015-11-11 12:41:11 -08001535 }
1536
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001537 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1538 typename Dummy = std::enable_if_t<std::is_same<
1539 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1540 constexpr bool operator==(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001541 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001542 return bounds_.size() == other.bounds_.size() &&
1543 (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin()));
Anna Gringauze8aa42482015-11-11 12:41:11 -08001544 }
1545
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001546 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1547 typename Dummy = std::enable_if_t<std::is_same<
1548 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1549 constexpr bool operator!=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001550 {
1551 return !(*this == other);
1552 }
1553
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001554 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1555 typename Dummy = std::enable_if_t<std::is_same<
1556 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1557 constexpr bool operator<(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001558 {
1559 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1560 }
1561
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001562 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1563 typename Dummy = std::enable_if_t<std::is_same<
1564 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1565 constexpr bool operator<=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001566 {
1567 return !(other < *this);
1568 }
1569
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001570 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1571 typename Dummy = std::enable_if_t<std::is_same<
1572 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1573 constexpr bool operator>(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001574 {
1575 return (other < *this);
1576 }
1577
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001578 template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
1579 typename Dummy = std::enable_if_t<std::is_same<
1580 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1581 constexpr bool operator>=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
Anna Gringauze8aa42482015-11-11 12:41:11 -08001582 {
1583 return !(*this < other);
1584 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001585};
1586
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001587//
1588// Free functions for manipulating spans
1589//
1590
1591// reshape a span into a different dimensionality
1592// DimCount and Enabled here are workarounds for a bug in MSVC 2015
1593template <typename SpanType, typename... Dimensions2, size_t DimCount = sizeof...(Dimensions2),
1594 bool Enabled = (DimCount > 0), typename = std::enable_if_t<Enabled>>
1595constexpr span<typename SpanType::value_type, Dimensions2::value...> as_span(SpanType s,
1596 Dimensions2... dims)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001597{
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001598 static_assert(details::is_span<SpanType>::value,
1599 "Variadic as_span() is for reshaping existing spans.");
1600 using BoundsType =
1601 typename span<typename SpanType::value_type, (Dimensions2::value)...>::bounds_type;
1602 auto tobounds = details::static_as_span_helper<BoundsType>(dims..., details::Sep{});
1603 details::verifyBoundsReshape(s.bounds(), tobounds);
1604 return {s.data(), tobounds};
1605}
1606
1607// convert a span<T> to a span<const byte>
1608template <typename U, std::ptrdiff_t... Dimensions>
1609span<const byte, dynamic_range> as_bytes(span<U, Dimensions...> s) noexcept
1610{
1611 static_assert(std::is_trivial<std::decay_t<U>>::value,
1612 "The value_type of span must be a trivial type.");
1613 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
1614}
1615
1616// convert a span<T> to a span<byte> (a writeable byte span)
1617// this is not currently a portable function that can be relied upon to work
1618// on all implementations. It should be considered an experimental extension
1619// to the standard GSL interface.
1620template <typename U, std::ptrdiff_t... Dimensions>
1621span<byte> as_writeable_bytes(span<U, Dimensions...> s) noexcept
1622{
1623 static_assert(std::is_trivial<std::decay_t<U>>::value,
1624 "The value_type of span must be a trivial type.");
1625 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
1626}
1627
1628// convert a span<const byte> to a span<const T>
1629// this is not currently a portable function that can be relied upon to work
1630// on all implementations. It should be considered an experimental extension
1631// to the standard GSL interface.
1632template <typename U, std::ptrdiff_t... Dimensions>
1633constexpr auto as_span(span<const byte, Dimensions...> s) noexcept
1634 -> span<const U, static_cast<std::ptrdiff_t>(
1635 span<const byte, Dimensions...>::bounds_type::static_size != dynamic_range
1636 ? (static_cast<size_t>(
1637 span<const byte, Dimensions...>::bounds_type::static_size) /
1638 sizeof(U))
1639 : dynamic_range)>
1640{
1641 using ConstByteSpan = span<const byte, Dimensions...>;
1642 static_assert(
1643 std::is_trivial<std::decay_t<U>>::value &&
1644 (ConstByteSpan::bounds_type::static_size == dynamic_range ||
1645 ConstByteSpan::bounds_type::static_size % narrow_cast<std::ptrdiff_t>(sizeof(U)) == 0),
1646 "Target type must be a trivial type and its size must match the byte array size");
1647
1648 Expects((s.size_bytes() % sizeof(U)) == 0 && (s.size_bytes() / sizeof(U)) < PTRDIFF_MAX);
1649 return {reinterpret_cast<const U*>(s.data()),
1650 s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
1651}
1652
1653// convert a span<byte> to a span<T>
1654// this is not currently a portable function that can be relied upon to work
1655// on all implementations. It should be considered an experimental extension
1656// to the standard GSL interface.
1657template <typename U, std::ptrdiff_t... Dimensions>
1658constexpr auto as_span(span<byte, Dimensions...> s) noexcept -> span<
1659 U, narrow_cast<std::ptrdiff_t>(
1660 span<byte, Dimensions...>::bounds_type::static_size != dynamic_range
1661 ? static_cast<std::size_t>(span<byte, Dimensions...>::bounds_type::static_size) /
1662 sizeof(U)
1663 : dynamic_range)>
1664{
1665 using ByteSpan = span<byte, Dimensions...>;
1666 static_assert(
1667 std::is_trivial<std::decay_t<U>>::value &&
1668 (ByteSpan::bounds_type::static_size == dynamic_range ||
1669 ByteSpan::bounds_type::static_size % static_cast<std::size_t>(sizeof(U)) == 0),
1670 "Target type must be a trivial type and its size must match the byte array size");
1671
1672 Expects((s.bytes() % sizeof(U)) == 0);
1673 return {reinterpret_cast<U*>(s.data()),
1674 s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
1675}
1676
1677template <typename T, std::ptrdiff_t... Dimensions>
1678constexpr auto as_span(T* const& ptr, dim<Dimensions>... args)
1679 -> span<std::remove_all_extents_t<T>, Dimensions...>
1680{
1681 return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr),
1682 details::static_as_span_helper<static_bounds<Dimensions...>>(args..., details::Sep{})};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001683}
1684
1685template <typename T>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001686constexpr auto as_span(T* arr, std::ptrdiff_t len) ->
1687 typename details::SpanArrayTraits<T, dynamic_range>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001688{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001689 return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001690}
1691
1692template <typename T, size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001693constexpr auto as_span(T (&arr)[N]) -> typename details::SpanArrayTraits<T, N>::type
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001694{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001695 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001696}
1697
1698template <typename T, size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001699constexpr span<const T, N> as_span(const std::array<T, N>& arr)
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>&&) = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001706
1707template <typename T, size_t N>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001708constexpr span<T, N> as_span(std::array<T, N>& arr)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001709{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001710 return {arr};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001711}
1712
1713template <typename T>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001714constexpr span<T, dynamic_range> as_span(T* begin, T* end)
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001715{
Neil MacIntosh68064d62015-11-03 19:17:11 -08001716 return {begin, end};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001717}
1718
1719template <typename Cont>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001720constexpr auto as_span(Cont& arr) -> std::enable_if_t<
1721 !details::is_span<std::decay_t<Cont>>::value,
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001722 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001723{
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001724 Expects(arr.size() < PTRDIFF_MAX);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001725 return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001726}
1727
1728template <typename Cont>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001729constexpr auto as_span(Cont&& arr) -> std::enable_if_t<
1730 !details::is_span<std::decay_t<Cont>>::value,
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001731 span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001732
Elron A. Yelline4d8d352015-11-20 17:50:02 -05001733// from basic_string which doesn't have nonconst .data() member like other contiguous containers
1734template <typename CharT, typename Traits, typename Allocator>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001735constexpr auto as_span(std::basic_string<CharT, Traits, Allocator>& str)
1736 -> span<CharT, dynamic_range>
Elron A. Yelline4d8d352015-11-20 17:50:02 -05001737{
Neil MacIntoshd5057372015-11-20 17:14:21 -08001738 Expects(str.size() < PTRDIFF_MAX);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001739 return {&str[0], narrow_cast<std::ptrdiff_t>(str.size())};
Elron A. Yelline4d8d352015-11-20 17:50:02 -05001740}
1741
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001742// strided_span is an extension that is not strictly part of the GSL at this time.
1743// It is kept here while the multidimensional interface is still being defined.
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001744template <typename ValueType, size_t Rank>
Anna Gringauzef5100252015-11-12 12:48:49 -08001745class strided_span
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001746{
Anna Gringauzef5100252015-11-12 12:48:49 -08001747public:
1748 using bounds_type = strided_bounds<Rank>;
1749 using size_type = typename bounds_type::size_type;
1750 using index_type = typename bounds_type::index_type;
1751 using value_type = ValueType;
1752 using const_value_type = std::add_const_t<value_type>;
1753 using pointer = std::add_pointer_t<value_type>;
1754 using reference = std::add_lvalue_reference_t<value_type>;
1755 using iterator = general_span_iterator<strided_span>;
1756 using const_strided_span = strided_span<const_value_type, Rank>;
1757 using const_iterator = general_span_iterator<const_strided_span>;
1758 using reverse_iterator = std::reverse_iterator<iterator>;
1759 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001760 using sliced_type =
1761 std::conditional_t<Rank == 1, value_type, strided_span<value_type, Rank - 1>>;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001762
Anna Gringauzef5100252015-11-12 12:48:49 -08001763private:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001764 pointer data_;
1765 bounds_type bounds_;
Anna Gringauzef5100252015-11-12 12:48:49 -08001766
1767 friend iterator;
1768 friend const_iterator;
1769 template <typename OtherValueType, size_t OtherRank>
Neil MacIntoshb63ec942015-11-04 12:42:27 -08001770 friend class strided_span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001771
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001772public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001773 // from raw data
Anna Gringauzef5100252015-11-12 12:48:49 -08001774 constexpr strided_span(pointer ptr, size_type size, bounds_type bounds)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001775 : data_(ptr), bounds_(std::move(bounds))
Neil MacIntosh68064d62015-11-03 19:17:11 -08001776 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001777 Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0);
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001778 // Bounds cross data boundaries
1779 Expects(this->bounds().total_size() <= size);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001780 (void) size;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001781 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001782
Anna Gringauzef5100252015-11-12 12:48:49 -08001783 // from static array of size N
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001784 template <size_type N>
1785 constexpr strided_span(value_type (&values)[N], bounds_type bounds)
1786 : strided_span(values, N, std::move(bounds))
1787 {
1788 }
Anna Gringauzef5100252015-11-12 12:48:49 -08001789
Neil MacIntosh68064d62015-11-03 19:17:11 -08001790 // from array view
Anna Gringauzec95eb572015-11-19 12:02:06 -08001791 template <typename OtherValueType, std::ptrdiff_t... Dimensions,
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001792 bool Enabled1 = (sizeof...(Dimensions) == Rank),
1793 bool Enabled2 = std::is_convertible<OtherValueType*, ValueType*>::value,
1794 typename Dummy = std::enable_if_t<Enabled1 && Enabled2>>
1795 constexpr strided_span(span<OtherValueType, Dimensions...> av, bounds_type bounds)
1796 : strided_span(av.data(), av.bounds().total_size(), std::move(bounds))
1797 {
1798 }
1799
Neil MacIntosh68064d62015-11-03 19:17:11 -08001800 // convertible
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001801 template <typename OtherValueType, typename Dummy = std::enable_if_t<std::is_convertible<
1802 OtherValueType (*)[], value_type (*)[]>::value>>
Anna Gringauzef5100252015-11-12 12:48:49 -08001803 constexpr strided_span(const strided_span<OtherValueType, Rank>& other)
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001804 : data_(other.data_), bounds_(other.bounds_)
1805 {
1806 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001807
Neil MacIntosh68064d62015-11-03 19:17:11 -08001808 // convert from bytes
Anna Gringauzef5100252015-11-12 12:48:49 -08001809 template <typename OtherValueType>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001810 constexpr strided_span<
1811 typename std::enable_if<std::is_same<value_type, const byte>::value, OtherValueType>::type,
1812 Rank>
1813 as_strided_span() const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001814 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001815 static_assert((sizeof(OtherValueType) >= sizeof(value_type)) &&
1816 (sizeof(OtherValueType) % sizeof(value_type) == 0),
1817 "OtherValueType should have a size to contain a multiple of ValueTypes");
1818 auto d = narrow_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001819
Neil MacIntosh68064d62015-11-03 19:17:11 -08001820 size_type size = this->bounds().total_size() / d;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001821 return {(OtherValueType*) this->data(), size,
1822 bounds_type{resize_extent(this->bounds().index_bounds(), d),
1823 resize_stride(this->bounds().strides(), d)}};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001824 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001825
Anna Gringauzef5100252015-11-12 12:48:49 -08001826 constexpr strided_span section(index_type origin, index_type extents) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001827 {
1828 size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001829 return {&this->operator[](origin), size,
1830 bounds_type{extents, details::make_stride(bounds())}};
Neil MacIntosh68064d62015-11-03 19:17:11 -08001831 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001832
Neil MacIntosh68064d62015-11-03 19:17:11 -08001833 constexpr reference operator[](const index_type& idx) const
1834 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001835 return data_[bounds_.linearize(idx)];
Neil MacIntosh68064d62015-11-03 19:17:11 -08001836 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001837
Anna Gringauzef5100252015-11-12 12:48:49 -08001838 template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
1839 constexpr Ret operator[](size_type idx) const
Neil MacIntosh68064d62015-11-03 19:17:11 -08001840 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001841 Expects(idx < bounds_.size()); // index is out of bounds of the array
1842 const size_type ridx = idx * bounds_.stride();
Anna Gringauzef5100252015-11-12 12:48:49 -08001843
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001844 // index is out of bounds of the underlying data
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001845 Expects(ridx < bounds_.total_size());
1846 return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()};
Anna Gringauzef5100252015-11-12 12:48:49 -08001847 }
1848
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001849 constexpr bounds_type bounds() const noexcept { return bounds_; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001850
1851 template <size_t Dim = 0>
1852 constexpr size_type extent() const noexcept
1853 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001854 static_assert(Dim < Rank,
1855 "dimension should be less than Rank (dimension count starts from 0)");
1856 return bounds_.template extent<Dim>();
Anna Gringauzef5100252015-11-12 12:48:49 -08001857 }
1858
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001859 constexpr size_type size() const noexcept { return bounds_.size(); }
Anna Gringauzef5100252015-11-12 12:48:49 -08001860
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001861 constexpr pointer data() const noexcept { return data_; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001862
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001863 constexpr explicit operator bool() const noexcept { return data_ != nullptr; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001864
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001865 constexpr iterator begin() const { return iterator{this, true}; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001866
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001867 constexpr iterator end() const { return iterator{this, false}; }
Anna Gringauzef5100252015-11-12 12:48:49 -08001868
1869 constexpr const_iterator cbegin() const
1870 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001871 return const_iterator{reinterpret_cast<const const_strided_span*>(this), true};
Anna Gringauzef5100252015-11-12 12:48:49 -08001872 }
1873
1874 constexpr const_iterator cend() const
1875 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001876 return const_iterator{reinterpret_cast<const const_strided_span*>(this), false};
Anna Gringauzef5100252015-11-12 12:48:49 -08001877 }
1878
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001879 constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; }
1880
1881 constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; }
1882
1883 constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{cend()}; }
1884
1885 constexpr const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; }
1886
1887 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1888 typename Dummy = std::enable_if_t<std::is_same<
1889 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1890 constexpr bool operator==(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001891 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001892 return bounds_.size() == other.bounds_.size() &&
1893 (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin()));
Anna Gringauzef5100252015-11-12 12:48:49 -08001894 }
1895
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001896 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1897 typename Dummy = std::enable_if_t<std::is_same<
1898 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1899 constexpr bool operator!=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001900 {
1901 return !(*this == other);
1902 }
1903
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001904 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1905 typename Dummy = std::enable_if_t<std::is_same<
1906 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1907 constexpr bool operator<(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001908 {
1909 return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
1910 }
1911
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001912 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1913 typename Dummy = std::enable_if_t<std::is_same<
1914 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1915 constexpr bool operator<=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001916 {
1917 return !(other < *this);
1918 }
1919
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001920 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1921 typename Dummy = std::enable_if_t<std::is_same<
1922 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1923 constexpr bool operator>(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001924 {
1925 return (other < *this);
1926 }
1927
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001928 template <typename OtherValueType, std::ptrdiff_t OtherRank,
1929 typename Dummy = std::enable_if_t<std::is_same<
1930 std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
1931 constexpr bool operator>=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
Anna Gringauzef5100252015-11-12 12:48:49 -08001932 {
1933 return !(*this < other);
Neil MacIntosh68064d62015-11-03 19:17:11 -08001934 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001935
1936private:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001937 static index_type resize_extent(const index_type& extent, std::ptrdiff_t d)
1938 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001939 // The last dimension of the array needs to contain a multiple of new type elements
1940 Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001941
Neil MacIntosh68064d62015-11-03 19:17:11 -08001942 index_type ret = extent;
Anna Gringauzef5100252015-11-12 12:48:49 -08001943 ret[Rank - 1] /= d;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001944
Neil MacIntosh68064d62015-11-03 19:17:11 -08001945 return ret;
1946 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001947
Anna Gringauzef5100252015-11-12 12:48:49 -08001948 template <bool Enabled = (Rank == 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001949 static index_type resize_stride(const index_type& strides, std::ptrdiff_t, void* = 0)
Neil MacIntosh68064d62015-11-03 19:17:11 -08001950 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001951 // Only strided arrays with regular strides can be resized
1952 Expects(strides[Rank - 1] == 1);
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001953
Neil MacIntosh68064d62015-11-03 19:17:11 -08001954 return strides;
1955 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001956
Anna Gringauzef5100252015-11-12 12:48:49 -08001957 template <bool Enabled = (Rank > 1), typename Dummy = std::enable_if_t<Enabled>>
Neil MacIntosh68064d62015-11-03 19:17:11 -08001958 static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
1959 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001960 // Only strided arrays with regular strides can be resized
1961 Expects(strides[Rank - 1] == 1);
1962 // The strides must have contiguous chunks of
1963 // memory that can contain a multiple of new type elements
1964 Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0));
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001965
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001966 for (size_t i = Rank - 1; i > 0; --i) {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001967 // Only strided arrays with regular strides can be resized
1968 Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0));
Anna Gringauzef5100252015-11-12 12:48:49 -08001969 }
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001970
Neil MacIntosh68064d62015-11-03 19:17:11 -08001971 index_type ret = strides / d;
Anna Gringauzef5100252015-11-12 12:48:49 -08001972 ret[Rank - 1] = 1;
Anna Gringauze17ed5c32015-08-30 23:30:15 -07001973
Neil MacIntosh68064d62015-11-03 19:17:11 -08001974 return ret;
1975 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001976};
1977
Anna Gringauze8aa42482015-11-11 12:41:11 -08001978template <class Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001979class contiguous_span_iterator
1980 : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001981{
Anna Gringauze8aa42482015-11-11 12:41:11 -08001982 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001983
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001984public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08001985 using typename Base::reference;
1986 using typename Base::pointer;
1987 using typename Base::difference_type;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001988
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07001989private:
Anna Gringauze8aa42482015-11-11 12:41:11 -08001990 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
1991 friend class span;
Neil MacIntoshf45fedb2015-10-15 14:29:35 -07001992
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001993 pointer data_;
Anna Gringauze8aa42482015-11-11 12:41:11 -08001994 const Span* m_validator;
Neil MacIntosh68064d62015-11-03 19:17:11 -08001995 void validateThis() const
1996 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08001997 // iterator is out of range of the array
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08001998 Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size());
Neil MacIntosh68064d62015-11-03 19:17:11 -08001999 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002000 contiguous_span_iterator(const Span* container, bool isbegin)
2001 : data_(isbegin ? container->data_ : container->data_ + container->size())
2002 , m_validator(container)
2003 {
2004 }
2005
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002006public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08002007 reference operator*() const noexcept
2008 {
2009 validateThis();
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002010 return *data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002011 }
2012 pointer operator->() const noexcept
2013 {
2014 validateThis();
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002015 return data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002016 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002017 contiguous_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002018 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002019 ++data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002020 return *this;
2021 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002022 contiguous_span_iterator operator++(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002023 {
2024 auto ret = *this;
2025 ++(*this);
2026 return ret;
2027 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002028 contiguous_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002029 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002030 --data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002031 return *this;
2032 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002033 contiguous_span_iterator operator--(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002034 {
2035 auto ret = *this;
2036 --(*this);
2037 return ret;
2038 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002039 contiguous_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002040 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002041 contiguous_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002042 return ret += n;
2043 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002044 contiguous_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002045 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002046 data_ += n;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002047 return *this;
2048 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002049 contiguous_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002050 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002051 contiguous_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002052 return ret -= n;
2053 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002054 contiguous_span_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002055 difference_type operator-(const contiguous_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002056 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002057 Expects(m_validator == rhs.m_validator);
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002058 return data_ - rhs.data_;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002059 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002060 reference operator[](difference_type n) const noexcept { return *(*this + n); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002061 bool 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 bool operator!=(const contiguous_span_iterator& rhs) const noexcept { return !(*this == rhs); }
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 !(rhs < *this); }
2073 bool operator>(const contiguous_span_iterator& rhs) const noexcept { return rhs < *this; }
2074 bool operator>=(const contiguous_span_iterator& rhs) const noexcept { return !(rhs > *this); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002075 void swap(contiguous_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002076 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002077 std::swap(data_, rhs.data_);
Neil MacIntosh68064d62015-11-03 19:17:11 -08002078 std::swap(m_validator, rhs.m_validator);
2079 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002080};
2081
Anna Gringauze8aa42482015-11-11 12:41:11 -08002082template <typename Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002083contiguous_span_iterator<Span> operator+(typename contiguous_span_iterator<Span>::difference_type n,
2084 const contiguous_span_iterator<Span>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002085{
Neil MacIntosh68064d62015-11-03 19:17:11 -08002086 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002087}
2088
Anna Gringauze8aa42482015-11-11 12:41:11 -08002089template <typename Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002090class general_span_iterator
2091 : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002092{
Anna Gringauze8aa42482015-11-11 12:41:11 -08002093 using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002094
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002095public:
Neil MacIntosh68064d62015-11-03 19:17:11 -08002096 using typename Base::reference;
2097 using typename Base::pointer;
2098 using typename Base::difference_type;
2099 using typename Base::value_type;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002100
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002101private:
Anna Gringauzef5100252015-11-12 12:48:49 -08002102 template <typename ValueType, size_t Rank>
2103 friend class strided_span;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002104
Anna Gringauzef5100252015-11-12 12:48:49 -08002105 const Span* m_container;
Anna Gringauze8aa42482015-11-11 12:41:11 -08002106 typename Span::bounds_type::iterator m_itr;
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002107 general_span_iterator(const Span* container, bool isbegin)
2108 : m_container(container)
2109 , m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
2110 {
2111 }
2112
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002113public:
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002114 reference operator*() noexcept { return (*m_container)[*m_itr]; }
2115 pointer operator->() noexcept { return &(*m_container)[*m_itr]; }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002116 general_span_iterator& operator++() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002117 {
2118 ++m_itr;
2119 return *this;
2120 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002121 general_span_iterator operator++(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002122 {
2123 auto ret = *this;
2124 ++(*this);
2125 return ret;
2126 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002127 general_span_iterator& operator--() noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002128 {
2129 --m_itr;
2130 return *this;
2131 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002132 general_span_iterator operator--(int) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002133 {
2134 auto ret = *this;
2135 --(*this);
2136 return ret;
2137 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002138 general_span_iterator operator+(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002139 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002140 general_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002141 return ret += n;
2142 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002143 general_span_iterator& operator+=(difference_type n) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002144 {
2145 m_itr += n;
2146 return *this;
2147 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002148 general_span_iterator operator-(difference_type n) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002149 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002150 general_span_iterator ret{*this};
Neil MacIntosh68064d62015-11-03 19:17:11 -08002151 return ret -= n;
2152 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002153 general_span_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002154 difference_type operator-(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002155 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002156 Expects(m_container == rhs.m_container);
Neil MacIntosh68064d62015-11-03 19:17:11 -08002157 return m_itr - rhs.m_itr;
2158 }
2159 value_type operator[](difference_type n) const noexcept
2160 {
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002161 return (*m_container)[m_itr[n]];
2162 ;
Neil MacIntosh68064d62015-11-03 19:17:11 -08002163 }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002164 bool operator==(const general_span_iterator& rhs) const noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002165 {
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002166 Expects(m_container == rhs.m_container);
Neil MacIntosh68064d62015-11-03 19:17:11 -08002167 return m_itr == rhs.m_itr;
2168 }
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002169 bool operator!=(const general_span_iterator& rhs) const noexcept { return !(*this == rhs); }
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 !(rhs < *this); }
2176 bool operator>(const general_span_iterator& rhs) const noexcept { return rhs < *this; }
2177 bool operator>=(const general_span_iterator& rhs) const noexcept { return !(rhs > *this); }
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002178 void swap(general_span_iterator& rhs) noexcept
Neil MacIntosh68064d62015-11-03 19:17:11 -08002179 {
2180 std::swap(m_itr, rhs.m_itr);
2181 std::swap(m_container, rhs.m_container);
2182 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002183};
2184
Anna Gringauze8aa42482015-11-11 12:41:11 -08002185template <typename Span>
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002186general_span_iterator<Span> operator+(typename general_span_iterator<Span>::difference_type n,
2187 const general_span_iterator<Span>& rhs) noexcept
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002188{
Neil MacIntosh68064d62015-11-03 19:17:11 -08002189 return rhs + n;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002190}
2191
Neil MacIntoshef626fd2015-09-29 16:41:37 -07002192} // namespace gsl
Neil MacIntosha9dcbe02015-08-20 18:09:14 -07002193
Neil MacIntoshd5316802015-09-30 21:54:08 -07002194#ifdef _MSC_VER
2195
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002196#undef constexpr
2197#pragma pop_macro("constexpr")
Gabriel Dos Reis6554e832015-09-28 05:10:44 -07002198
Neil MacIntoshd5316802015-09-30 21:54:08 -07002199#if _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002200#pragma warning(pop)
Neil MacIntoshd5316802015-09-30 21:54:08 -07002201
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002202#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
Lukas Haselsteinere51eb222015-11-15 23:08:35 +01002203#undef noexcept
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002204#pragma pop_macro("noexcept")
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002205#endif // GSL_THROW_ON_CONTRACT_VIOLATION
Neil MacIntoshd5316802015-09-30 21:54:08 -07002206
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002207#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
Neil MacIntoshe9a96022015-11-03 18:56:55 -08002208
Neil MacIntosh9a297122015-09-14 15:11:07 -07002209#endif // _MSC_VER <= 1800
Neil MacIntosh9a297122015-09-14 15:11:07 -07002210
Neil MacIntoshd5316802015-09-30 21:54:08 -07002211#endif // _MSC_VER
2212
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002213#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002214
Anna Gringauzef5100252015-11-12 12:48:49 -08002215#undef noexcept
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002216
2217#ifdef _MSC_VER
Neil MacIntoshd13f6da2015-11-20 16:03:00 -08002218#pragma warning(pop)
Neil MacIntosh292f81e2015-11-17 15:07:51 -08002219#pragma pop_macro("noexcept")
2220#endif
2221
Neil MacIntosh0cf947d2015-11-24 12:49:03 -08002222#endif // GSL_THROW_ON_CONTRACT_VIOLATION
Treb Connell51da1362015-09-24 18:08:34 -07002223
Neil MacIntoshb63ec942015-11-04 12:42:27 -08002224#endif // GSL_SPAN_H