blob: b4da532165727953664f1db92b3d657f06859733 [file] [log] [blame]
Neil MacIntoshcec26a22016-02-24 11:26:28 -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//
15///////////////////////////////////////////////////////////////////////////////
16
Neil MacIntoshcec26a22016-02-24 11:26:28 -080017#ifndef GSL_SPAN_H
18#define GSL_SPAN_H
19
Tiago0d33bf62017-11-28 07:13:49 -080020#include <gsl/gsl_assert> // for Expects
21#include <gsl/gsl_byte> // for byte
22#include <gsl/gsl_util> // for narrow_cast, narrow
Tiagoebe7ebf2017-04-20 07:51:37 -070023
Tiago0d33bf62017-11-28 07:13:49 -080024#include <algorithm> // for lexicographical_compare
25#include <array> // for array
26#include <cstddef> // for ptrdiff_t, size_t, nullptr_t
27#include <iterator> // for reverse_iterator, distance, random_access_...
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070028#include <limits>
Neil MacIntoshcec26a22016-02-24 11:26:28 -080029#include <stdexcept>
Tiago0d33bf62017-11-28 07:13:49 -080030#include <type_traits> // for enable_if_t, declval, is_convertible, inte...
Neil MacIntoshcec26a22016-02-24 11:26:28 -080031#include <utility>
Anna Gringauze1995e862018-08-19 17:10:53 -070032#include <memory> // for std::addressof
Neil MacIntoshcec26a22016-02-24 11:26:28 -080033
Anna Gringauze6418b5f2019-01-15 10:27:34 -080034#if defined(_MSC_VER) && !defined(__clang__)
Tiagoebe7ebf2017-04-20 07:51:37 -070035#pragma warning(push)
Neil MacIntoshcec26a22016-02-24 11:26:28 -080036
Tiagoebe7ebf2017-04-20 07:51:37 -070037// turn off some warnings that are noisy about our Expects statements
38#pragma warning(disable : 4127) // conditional expression is constant
Neil MacIntoshb2ee4842017-07-13 13:53:56 -070039#pragma warning(disable : 4702) // unreachable code
Neil MacIntosha9f0ce22016-03-31 12:01:07 -070040
Anna Gringauzecea0d0a2018-08-12 21:44:17 -070041// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
42#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
43#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
Neil MacIntoshcec26a22016-02-24 11:26:28 -080044
Tiagoebe7ebf2017-04-20 07:51:37 -070045#if _MSC_VER < 1910
46#pragma push_macro("constexpr")
47#define constexpr /*constexpr*/
Neil MacIntosh6a33b972018-03-03 19:12:45 -080048#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
Neil MacIntosha9f0ce22016-03-31 12:01:07 -070049
Anna Gringauze5016ce42018-08-17 11:36:06 -070050#endif // _MSC_VER < 1910
51#endif // _MSC_VER
Neil MacIntosh6a33b972018-03-03 19:12:45 -080052
53// See if we have enough C++17 power to use a static constexpr data member
54// without needing an out-of-line definition
55#if !(defined(__cplusplus) && (__cplusplus >= 201703L))
56#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
57#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
58
meneteffdaf0f2018-06-08 20:41:06 +020059// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
Anna Gringauzecea0d0a2018-08-12 21:44:17 -070060// While there is a conversion from signed to unsigned, it happens at
61// compiletime, so the compiler wouldn't have to warn indiscriminently, but
62// could check if the source value actually doesn't fit into the target type
meneteffdaf0f2018-06-08 20:41:06 +020063// and only warn in those cases.
Anna Gringauze6418b5f2019-01-15 10:27:34 -080064#if defined(__GNUC__) && __GNUC__ > 6
meneteffdaf0f2018-06-08 20:41:06 +020065#pragma GCC diagnostic push
66#pragma GCC diagnostic ignored "-Wsign-conversion"
67#endif
68
Neil MacIntoshcec26a22016-02-24 11:26:28 -080069namespace gsl
70{
71
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070072// [views.constants], constants
Neil MacIntoshc94a66f2016-06-12 18:28:19 -070073constexpr const std::ptrdiff_t dynamic_extent = -1;
74
Neil MacIntoshc366f442016-07-26 18:34:27 -070075template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
76class span;
77
Neil MacIntoshc94a66f2016-06-12 18:28:19 -070078// implementation details
Neil MacIntoshc40094a2016-03-01 12:11:41 -080079namespace details
80{
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070081 template <class T>
82 struct is_span_oracle : std::false_type
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -070083 {
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070084 };
85
86 template <class ElementType, std::ptrdiff_t Extent>
87 struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
88 {
89 };
90
91 template <class T>
Neil MacIntoshc366f442016-07-26 18:34:27 -070092 struct is_span : public is_span_oracle<std::remove_cv_t<T>>
93 {
94 };
95
96 template <class T>
97 struct is_std_array_oracle : std::false_type
98 {
99 };
100
Casey Carter3819df62017-02-13 12:11:45 -0800101 template <class ElementType, std::size_t Extent>
Neil MacIntoshc366f442016-07-26 18:34:27 -0700102 struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
103 {
104 };
105
106 template <class T>
107 struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700108 {
109 };
110
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700111 template <std::ptrdiff_t From, std::ptrdiff_t To>
112 struct is_allowed_extent_conversion
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700113 : public std::integral_constant<bool, From == To || From == gsl::dynamic_extent ||
114 To == gsl::dynamic_extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700115 {
116 };
117
118 template <class From, class To>
119 struct is_allowed_element_type_conversion
Neil MacIntosh831be5d2016-09-14 22:01:02 -0700120 : public std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700121 {
122 };
123
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700124 template <class Span, bool IsConst>
Neil MacIntosh6c7be2c2016-08-01 21:41:20 -0700125 class span_iterator
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700126 {
Eric Niebler9d13cb12016-12-09 20:19:50 -0800127 using element_type_ = typename Span::element_type;
Tiagoebe7ebf2017-04-20 07:51:37 -0700128
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700129 public:
Alex Howlettc9e423d2018-03-05 15:04:22 -0500130#ifdef _MSC_VER
131 // Tell Microsoft standard library that span_iterators are checked.
132 using _Unchecked_type = typename Span::pointer;
133#endif
134
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700135 using iterator_category = std::random_access_iterator_tag;
Maciej T. Nowakc2f953f2017-04-13 22:55:20 +0200136 using value_type = std::remove_cv_t<element_type_>;
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700137 using difference_type = typename Span::index_type;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700138
Tiagoebe7ebf2017-04-20 07:51:37 -0700139 using reference = std::conditional_t<IsConst, const element_type_, element_type_>&;
Eric Niebler9d13cb12016-12-09 20:19:50 -0800140 using pointer = std::add_pointer_t<reference>;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700141
Casey Carter39902b62017-05-26 15:41:12 -0700142 span_iterator() = default;
Neil MacIntosh0dd5f562016-08-08 13:33:02 -0700143
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700144 constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept
paweldacb3870ca2018-02-21 22:33:07 +0100145 : span_(span), index_(idx)
Anna Gringauze5016ce42018-08-17 11:36:06 -0700146 {}
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700147
Casey Carter39902b62017-05-26 15:41:12 -0700148 friend span_iterator<Span, true>;
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700149 template <bool B, std::enable_if_t<!B && IsConst>* = nullptr>
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700150 constexpr span_iterator(const span_iterator<Span, B>& other) noexcept
Neil MacIntosh0dd5f562016-08-08 13:33:02 -0700151 : span_iterator(other.span_, other.index_)
Anna Gringauze5016ce42018-08-17 11:36:06 -0700152 {}
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700153
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700154 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800155 constexpr reference operator*() const
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700156 {
Neil MacIntosh72688ff2018-02-10 18:58:28 -0800157 Expects(index_ != span_->size());
Anna Gringauzee7bcdf52017-09-18 15:16:23 -0700158 return *(span_->data() + index_);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700159 }
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700160
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800161 constexpr pointer operator->() const
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700162 {
Neil MacIntosh72688ff2018-02-10 18:58:28 -0800163 Expects(index_ != span_->size());
Casey Carter39902b62017-05-26 15:41:12 -0700164 return span_->data() + index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700165 }
166
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800167 constexpr span_iterator& operator++()
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700168 {
Neil MacIntosh72688ff2018-02-10 18:58:28 -0800169 Expects(0 <= index_ && index_ != span_->size());
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700170 ++index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700171 return *this;
172 }
173
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800174 constexpr span_iterator operator++(int)
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700175 {
176 auto ret = *this;
177 ++(*this);
178 return ret;
179 }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700180
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800181 constexpr span_iterator& operator--()
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700182 {
Neil MacIntosh72688ff2018-02-10 18:58:28 -0800183 Expects(index_ != 0 && index_ <= span_->size());
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700184 --index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700185 return *this;
186 }
187
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800188 constexpr span_iterator operator--(int)
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700189 {
190 auto ret = *this;
191 --(*this);
192 return ret;
193 }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700194
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800195 constexpr span_iterator operator+(difference_type n) const
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700196 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700197 auto ret = *this;
198 return ret += n;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700199 }
200
Casey Carterd6a22422018-05-09 14:01:22 -0700201 friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs)
202 {
203 return rhs + n;
204 }
205
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800206 constexpr span_iterator& operator+=(difference_type n)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700207 {
Neil MacIntosh72688ff2018-02-10 18:58:28 -0800208 Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700209 index_ += n;
210 return *this;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700211 }
212
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800213 constexpr span_iterator operator-(difference_type n) const
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700214 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700215 auto ret = *this;
216 return ret -= n;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700217 }
218
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800219 constexpr span_iterator& operator-=(difference_type n) { return *this += -n; }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700220
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800221 constexpr difference_type operator-(span_iterator rhs) const
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700222 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700223 Expects(span_ == rhs.span_);
224 return index_ - rhs.index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700225 }
226
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700227 constexpr reference operator[](difference_type n) const { return *(*this + n); }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700228
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700229 constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700230 {
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700231 return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700232 }
233
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700234 constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700235 {
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700236 return !(lhs == rhs);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700237 }
238
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700239 constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700240 {
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700241 return lhs.index_ < rhs.index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700242 }
243
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700244 constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700245 {
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700246 return !(rhs < lhs);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700247 }
248
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700249 constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700250 {
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700251 return rhs < lhs;
252 }
253
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700254 constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700255 {
256 return !(rhs > lhs);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700257 }
258
Anna Gringauze51ae6782018-05-22 18:07:49 -0700259#ifdef _MSC_VER
260 // MSVC++ iterator debugging support; allows STL algorithms in 15.8+
261 // to unwrap span_iterator to a pointer type after a range check in STL
262 // algorithm calls
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700263 friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
264 { // test that [lhs, rhs) forms a valid range inside an STL algorithm
265 Expects(lhs.span_ == rhs.span_ // range spans have to match
266 && lhs.index_ <= rhs.index_); // range must not be transposed
Anna Gringauze51ae6782018-05-22 18:07:49 -0700267 }
268
269 constexpr void _Verify_offset(const difference_type n) const noexcept
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700270 { // test that the iterator *this + n is a valid range in an STL
Anna Gringauze51ae6782018-05-22 18:07:49 -0700271 // algorithm call
272 Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
273 }
274
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700275 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
Anna Gringauze51ae6782018-05-22 18:07:49 -0700276 constexpr pointer _Unwrapped() const noexcept
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700277 { // after seeking *this to a high water mark, or using one of the
Anna Gringauze51ae6782018-05-22 18:07:49 -0700278 // _Verify_xxx functions above, unwrap this span_iterator to a raw
279 // pointer
280 return span_->data() + index_;
281 }
282
283 // Tell the STL that span_iterator should not be unwrapped if it can't
284 // validate in advance, even in release / optimized builds:
285#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
286 static constexpr const bool _Unwrap_when_unverified = false;
287#else
288 static constexpr bool _Unwrap_when_unverified = false;
289#endif
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700290 GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
Anna Gringauze51ae6782018-05-22 18:07:49 -0700291 constexpr void _Seek_to(const pointer p) noexcept
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700292 { // adjust the position of *this to previously verified location p
Anna Gringauze51ae6782018-05-22 18:07:49 -0700293 // after _Unwrapped
294 index_ = p - span_->data();
295 }
296#endif
297
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700298 protected:
Casey Carter39902b62017-05-26 15:41:12 -0700299 const Span* span_ = nullptr;
300 std::ptrdiff_t index_ = 0;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700301 };
302
Neil MacIntoshc366f442016-07-26 18:34:27 -0700303 template <std::ptrdiff_t Ext>
304 class extent_type
305 {
306 public:
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700307 using index_type = std::ptrdiff_t;
Neil MacIntoshc366f442016-07-26 18:34:27 -0700308
309 static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
310
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700311 constexpr extent_type() noexcept {}
Neil MacIntoshc366f442016-07-26 18:34:27 -0700312
313 template <index_type Other>
Casey Carter96eaf272017-01-28 00:08:48 -0800314 constexpr extent_type(extent_type<Other> ext)
Neil MacIntoshc366f442016-07-26 18:34:27 -0700315 {
316 static_assert(Other == Ext || Other == dynamic_extent,
317 "Mismatch between fixed-size extent and size of initializing data.");
318 Expects(ext.size() == Ext);
319 }
320
321 constexpr extent_type(index_type size) { Expects(size == Ext); }
322
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700323 constexpr index_type size() const noexcept { return Ext; }
Neil MacIntoshc366f442016-07-26 18:34:27 -0700324 };
325
326 template <>
327 class extent_type<dynamic_extent>
328 {
329 public:
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700330 using index_type = std::ptrdiff_t;
Neil MacIntoshc366f442016-07-26 18:34:27 -0700331
332 template <index_type Other>
333 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
Anna Gringauze5016ce42018-08-17 11:36:06 -0700334 {}
Neil MacIntoshc366f442016-07-26 18:34:27 -0700335
336 explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
337
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700338 constexpr index_type size() const noexcept { return size_; }
Neil MacIntoshc366f442016-07-26 18:34:27 -0700339
340 private:
341 index_type size_;
342 };
Neil MacIntosh6a33b972018-03-03 19:12:45 -0800343
344 template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset, std::ptrdiff_t Count>
345 struct calculate_subspan_type
346 {
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700347 using type = span<ElementType, Count != dynamic_extent
348 ? Count
349 : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
Neil MacIntosh6a33b972018-03-03 19:12:45 -0800350 };
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800351} // namespace details
352
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700353// [span], class template span
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800354template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700355class span
356{
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800357public:
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700358 // constants and types
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800359 using element_type = ElementType;
Tiagoebe7ebf2017-04-20 07:51:37 -0700360 using value_type = std::remove_cv_t<ElementType>;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800361 using index_type = std::ptrdiff_t;
362 using pointer = element_type*;
363 using reference = element_type&;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700364
Neil MacIntosh82389aa2016-08-08 12:06:47 -0700365 using iterator = details::span_iterator<span<ElementType, Extent>, false>;
366 using const_iterator = details::span_iterator<span<ElementType, Extent>, true>;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800367 using reverse_iterator = std::reverse_iterator<iterator>;
Neil MacIntosh26747242016-06-26 17:00:56 +0300368 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700369
Maciej T. Nowakc2f953f2017-04-13 22:55:20 +0200370 using size_type = index_type;
371
Neil MacIntosh6a33b972018-03-03 19:12:45 -0800372#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700373 static constexpr const index_type extent{Extent};
Neil MacIntosh6a33b972018-03-03 19:12:45 -0800374#else
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700375 static constexpr index_type extent{Extent};
Neil MacIntosh6a33b972018-03-03 19:12:45 -0800376#endif
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800377
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700378 // [span.cons], span constructors, copy, assignment, and destructor
Casey Carter96eaf272017-01-28 00:08:48 -0800379 template <bool Dependent = false,
Tiagoebe7ebf2017-04-20 07:51:37 -0700380 // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE,
381 // since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
382 class = std::enable_if_t<(Dependent || Extent <= 0)>>
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700383 constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
Anna Gringauze5016ce42018-08-17 11:36:06 -0700384 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800385
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700386 constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800387
Neil MacIntosh502cd662016-02-28 00:50:53 -0800388 constexpr span(pointer firstElem, pointer lastElem)
389 : storage_(firstElem, std::distance(firstElem, lastElem))
Anna Gringauze5016ce42018-08-17 11:36:06 -0700390 {}
Neil MacIntoshf61a9bb2016-02-29 13:16:48 -0800391
Casey Carter3819df62017-02-13 12:11:45 -0800392 template <std::size_t N>
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700393 constexpr span(element_type (&arr)[N]) noexcept
Anna Gringauze1995e862018-08-19 17:10:53 -0700394 : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type<N>())
Anna Gringauze5016ce42018-08-17 11:36:06 -0700395 {}
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700396
Dave Hillc02ddae2018-11-05 15:39:41 -0800397 template <std::size_t N, class = std::enable_if_t<(N > 0)>>
398 constexpr span(std::array<std::remove_const_t<element_type>, N>& arr) noexcept
399 : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
400 {
401 }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700402
Dave Hillc02ddae2018-11-05 15:39:41 -0800403 constexpr span(std::array<std::remove_const_t<element_type>, 0>&) noexcept
404 : storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
405 {
406 }
407
408 template <std::size_t N, class = std::enable_if_t<(N > 0)>>
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700409 constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
Dave Hillc02ddae2018-11-05 15:39:41 -0800410 : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
411 {
412 }
413
414 constexpr span(const std::array<std::remove_const_t<element_type>, 0>&) noexcept
415 : storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
416 {
417 }
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800418
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800419 // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
420 // on Container to be a contiguous sequence container.
421 template <class Container,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700422 class = std::enable_if_t<
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700423 !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
Neil MacIntoshc366f442016-07-26 18:34:27 -0700424 std::is_convertible<typename Container::pointer, pointer>::value &&
425 std::is_convertible<typename Container::pointer,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700426 decltype(std::declval<Container>().data())>::value>>
Gary Furnish612747a2016-10-04 21:13:18 -0600427 constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
Anna Gringauze5016ce42018-08-17 11:36:06 -0700428 {}
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800429
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800430 template <class Container,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700431 class = std::enable_if_t<
432 std::is_const<element_type>::value && !details::is_span<Container>::value &&
Neil MacIntoshc366f442016-07-26 18:34:27 -0700433 std::is_convertible<typename Container::pointer, pointer>::value &&
434 std::is_convertible<typename Container::pointer,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700435 decltype(std::declval<Container>().data())>::value>>
Gary Furnish612747a2016-10-04 21:13:18 -0600436 constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
Anna Gringauze5016ce42018-08-17 11:36:06 -0700437 {}
Neil MacIntosh3d4c3492016-03-17 17:20:33 -0700438
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700439 constexpr span(const span& other) noexcept = default;
Neil MacIntosh717a2e32016-03-16 19:39:55 -0700440
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700441 template <
442 class OtherElementType, std::ptrdiff_t OtherExtent,
Neil MacIntoshc94a66f2016-06-12 18:28:19 -0700443 class = std::enable_if_t<
444 details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700445 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
446 constexpr span(const span<OtherElementType, OtherExtent>& other)
Neil MacIntosh831be5d2016-09-14 22:01:02 -0700447 : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
Anna Gringauze5016ce42018-08-17 11:36:06 -0700448 {}
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700449
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700450 ~span() noexcept = default;
451 constexpr span& operator=(const span& other) noexcept = default;
Casey Carterd6a22422018-05-09 14:01:22 -0700452
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700453 // [span.sub], span subviews
Neil MacIntoshc366f442016-07-26 18:34:27 -0700454 template <std::ptrdiff_t Count>
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700455 constexpr span<element_type, Count> first() const
456 {
457 Expects(Count >= 0 && Count <= size());
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700458 return {data(), Count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700459 }
460
Neil MacIntoshc366f442016-07-26 18:34:27 -0700461 template <std::ptrdiff_t Count>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700462 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700463 constexpr span<element_type, Count> last() const
464 {
Anna Gringauze9a789792017-11-03 16:13:39 -0700465 Expects(Count >= 0 && size() - Count >= 0);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700466 return {data() + (size() - Count), Count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700467 }
468
Neil MacIntoshc366f442016-07-26 18:34:27 -0700469 template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700470 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
471 constexpr auto subspan() const ->
472 typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700473 {
Anna Gringauze9a789792017-11-03 16:13:39 -0700474 Expects((Offset >= 0 && size() - Offset >= 0) &&
Neil MacIntoshc366f442016-07-26 18:34:27 -0700475 (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
Anna Gringauze9a789792017-11-03 16:13:39 -0700476
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700477 return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700478 }
479
480 constexpr span<element_type, dynamic_extent> first(index_type count) const
481 {
482 Expects(count >= 0 && count <= size());
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700483 return {data(), count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700484 }
485
486 constexpr span<element_type, dynamic_extent> last(index_type count) const
487 {
Anna Gringauze9a789792017-11-03 16:13:39 -0700488 return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700489 }
490
491 constexpr span<element_type, dynamic_extent> subspan(index_type offset,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700492 index_type count = dynamic_extent) const
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700493 {
Anna Gringauze9a789792017-11-03 16:13:39 -0700494 return make_subspan(offset, count, subspan_selector<Extent>{});
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700495 }
496
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700497 // [span.obs], span observers
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700498 constexpr index_type size() const noexcept { return storage_.size(); }
499 constexpr index_type size_bytes() const noexcept
Tiagoebe7ebf2017-04-20 07:51:37 -0700500 {
501 return size() * narrow_cast<index_type>(sizeof(element_type));
502 }
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700503 constexpr bool empty() const noexcept { return size() == 0; }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800504
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700505 // [span.elem], span element access
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700506 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800507 constexpr reference operator[](index_type idx) const
508 {
Anna Gringauze5016ce42018-08-17 11:36:06 -0700509 Expects(CheckRange(idx, storage_.size()));
Neil MacIntoshf2ab3a52016-07-20 09:24:49 -0700510 return data()[idx];
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800511 }
Rian Quinn6cffe0d2016-10-26 15:11:24 -0600512
513 constexpr reference at(index_type idx) const { return this->operator[](idx); }
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800514 constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700515 constexpr pointer data() const noexcept { return storage_.data(); }
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700516
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700517 // [span.iter], span iterator support
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700518 constexpr iterator begin() const noexcept { return {this, 0}; }
519 constexpr iterator end() const noexcept { return {this, size()}; }
Neil MacIntosh30a038c2016-07-18 11:38:01 -0700520
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700521 constexpr const_iterator cbegin() const noexcept { return {this, 0}; }
522 constexpr const_iterator cend() const noexcept { return {this, size()}; }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700523
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700524 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
525 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
Neil MacIntosh30a038c2016-07-18 11:38:01 -0700526
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700527 constexpr const_reverse_iterator crbegin() const noexcept
528 {
529 return const_reverse_iterator{cend()};
530 }
531 constexpr const_reverse_iterator crend() const noexcept
532 {
533 return const_reverse_iterator{cbegin()};
534 }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800535
Casey Carterd6a22422018-05-09 14:01:22 -0700536#ifdef _MSC_VER
537 // Tell MSVC how to unwrap spans in range-based-for
538 constexpr pointer _Unchecked_begin() const noexcept { return data(); }
Anna Gringauze5016ce42018-08-17 11:36:06 -0700539 constexpr pointer _Unchecked_end() const noexcept
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700540 {
541 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
542 return data() + size();
543 }
Casey Carterd6a22422018-05-09 14:01:22 -0700544#endif // _MSC_VER
545
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800546private:
Alex Green7a7d0252019-01-14 19:44:45 -0500547 static constexpr bool CheckRange(index_type idx, index_type size) noexcept
Anna Gringauze5016ce42018-08-17 11:36:06 -0700548 {
549 // Optimization:
550 //
551 // idx >= 0 && idx < size
552 // =>
553 // static_cast<size_t>(idx) < static_cast<size_t>(size)
554 //
555 // because size >=0 by span construction, and negative idx will
556 // wrap around to a value always greater than size when casted.
557
558 // check if we have enough space to wrap around
kile05a7093f2018-11-28 11:52:11 -0800559#if defined(__cpp_if_constexpr)
560 if constexpr (sizeof(index_type) <= sizeof(size_t))
561#else
Anna Gringauze585f48c2018-08-19 16:27:30 -0700562 if (sizeof(index_type) <= sizeof(size_t))
kile05a7093f2018-11-28 11:52:11 -0800563#endif
Anna Gringauze5016ce42018-08-17 11:36:06 -0700564 {
565 return narrow_cast<size_t>(idx) < narrow_cast<size_t>(size);
566 }
567 else
568 {
569 return idx >= 0 && idx < size;
570 }
571 }
572
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700573 // Needed to remove unnecessary null check in subspans
Casey Carterd6a22422018-05-09 14:01:22 -0700574 struct KnownNotNull
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700575 {
576 pointer p;
577 };
578
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700579 // this implementation detail class lets us take advantage of the
Neil MacIntosh502cd662016-02-28 00:50:53 -0800580 // empty base class optimization to pay for only storage of a single
581 // pointer in the case of fixed-size spans
582 template <class ExtentType>
583 class storage_type : public ExtentType
584 {
585 public:
Casey Carterd6a22422018-05-09 14:01:22 -0700586 // KnownNotNull parameter is needed to remove unnecessary null check
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700587 // in subspans and constructors from arrays
Neil MacIntosh502cd662016-02-28 00:50:53 -0800588 template <class OtherExtentType>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700589 constexpr storage_type(KnownNotNull data, OtherExtentType ext)
590 : ExtentType(ext), data_(data.p)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700591 {
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700592 Expects(ExtentType::size() >= 0);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700593 }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800594
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700595 template <class OtherExtentType>
596 constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
597 {
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700598 Expects(ExtentType::size() >= 0);
599 Expects(data || ExtentType::size() == 0);
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700600 }
601
602 constexpr pointer data() const noexcept { return data_; }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800603
604 private:
605 pointer data_;
606 };
607
Neil MacIntoshc366f442016-07-26 18:34:27 -0700608 storage_type<details::extent_type<Extent>> storage_;
Anna Gringauze9a789792017-11-03 16:13:39 -0700609
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700610 // The rest is needed to remove unnecessary null check
611 // in subspans and constructors from arrays
612 constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {}
Anna Gringauze9a789792017-11-03 16:13:39 -0700613
614 template <std::ptrdiff_t CallerExtent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700615 class subspan_selector
616 {
617 };
Anna Gringauze9a789792017-11-03 16:13:39 -0700618
619 template <std::ptrdiff_t CallerExtent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700620 span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count,
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800621 subspan_selector<CallerExtent>) const
Anna Gringauze9a789792017-11-03 16:13:39 -0700622 {
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700623 const span<element_type, dynamic_extent> tmp(*this);
Anna Gringauze9a789792017-11-03 16:13:39 -0700624 return tmp.subspan(offset, count);
625 }
626
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700627 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
628 span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count,
Anna Gringauzecbd64c92018-03-03 19:12:23 -0800629 subspan_selector<dynamic_extent>) const
Anna Gringauze9a789792017-11-03 16:13:39 -0700630 {
631 Expects(offset >= 0 && size() - offset >= 0);
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700632
633 if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
Anna Gringauze9a789792017-11-03 16:13:39 -0700634
635 Expects(count >= 0 && size() - offset >= count);
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700636 return {KnownNotNull{data() + offset}, count};
Anna Gringauze9a789792017-11-03 16:13:39 -0700637 }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800638};
639
Neil MacIntosh6a33b972018-03-03 19:12:45 -0800640#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
641template <class ElementType, std::ptrdiff_t Extent>
642constexpr const typename span<ElementType, Extent>::index_type span<ElementType, Extent>::extent;
643#endif
644
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700645// [span.comparison], span comparison operators
Neil MacIntoshc366f442016-07-26 18:34:27 -0700646template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700647constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700648{
649 return std::equal(l.begin(), l.end(), r.begin(), r.end());
650}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800651
Neil MacIntoshc366f442016-07-26 18:34:27 -0700652template <class ElementType, std::ptrdiff_t Extent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700653constexpr bool operator!=(span<ElementType, Extent> l, span<ElementType, Extent> r)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700654{
655 return !(l == r);
656}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800657
Neil MacIntoshc366f442016-07-26 18:34:27 -0700658template <class ElementType, std::ptrdiff_t Extent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700659constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700660{
661 return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
662}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800663
Neil MacIntoshc366f442016-07-26 18:34:27 -0700664template <class ElementType, std::ptrdiff_t Extent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700665constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700666{
667 return !(l > r);
668}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800669
Neil MacIntoshc366f442016-07-26 18:34:27 -0700670template <class ElementType, std::ptrdiff_t Extent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700671constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700672{
673 return r < l;
674}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800675
Neil MacIntoshc366f442016-07-26 18:34:27 -0700676template <class ElementType, std::ptrdiff_t Extent>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700677constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700678{
679 return !(l < r);
680}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800681
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700682namespace details
683{
684 // if we only supported compilers with good constexpr support then
685 // this pair of classes could collapse down to a constexpr function
686
Casey Carter3819df62017-02-13 12:11:45 -0800687 // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700688 // constexpr
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700689 // and so will fail compilation of the template
Neil MacIntoshc366f442016-07-26 18:34:27 -0700690 template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700691 struct calculate_byte_size
692 : std::integral_constant<std::ptrdiff_t,
Neil MacIntoshc366f442016-07-26 18:34:27 -0700693 static_cast<std::ptrdiff_t>(sizeof(ElementType) *
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700694 static_cast<std::size_t>(Extent))>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700695 {
696 };
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700697
698 template <class ElementType>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700699 struct calculate_byte_size<ElementType, dynamic_extent>
700 : std::integral_constant<std::ptrdiff_t, dynamic_extent>
701 {
702 };
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700703} // namespace details
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700704
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700705// [span.objectrep], views of object representation
Neil MacIntoshc366f442016-07-26 18:34:27 -0700706template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700707span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700708as_bytes(span<ElementType, Extent> s) noexcept
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700709{
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700710 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700711 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
712}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800713
Neil MacIntoshc366f442016-07-26 18:34:27 -0700714template <class ElementType, std::ptrdiff_t Extent,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700715 class = std::enable_if_t<!std::is_const<ElementType>::value>>
716span<byte, details::calculate_byte_size<ElementType, Extent>::value>
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700717as_writeable_bytes(span<ElementType, Extent> s) noexcept
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700718{
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700719 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700720 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
721}
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800722
Rian Quinn2df9f852016-11-16 11:17:04 -0700723//
724// make_span() - Utility functions for creating spans
725//
726template <class ElementType>
Anna Gringauzecea0d0a2018-08-12 21:44:17 -0700727constexpr span<ElementType> make_span(ElementType* ptr,
728 typename span<ElementType>::index_type count)
Tiagoebe7ebf2017-04-20 07:51:37 -0700729{
730 return span<ElementType>(ptr, count);
731}
Rian Quinn2df9f852016-11-16 11:17:04 -0700732
733template <class ElementType>
beinhaerter7eb8f412018-02-23 22:35:36 +0100734constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
Tiagoebe7ebf2017-04-20 07:51:37 -0700735{
736 return span<ElementType>(firstElem, lastElem);
737}
Rian Quinn2df9f852016-11-16 11:17:04 -0700738
Casey Carter3819df62017-02-13 12:11:45 -0800739template <class ElementType, std::size_t N>
Anna Gringauzec6bf25a2018-03-15 12:14:29 -0700740constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept
Tiagoebe7ebf2017-04-20 07:51:37 -0700741{
ewoudvc64c0ca62017-04-25 21:01:49 +0200742 return span<ElementType, N>(arr);
Tiagoebe7ebf2017-04-20 07:51:37 -0700743}
Rian Quinn2df9f852016-11-16 11:17:04 -0700744
745template <class Container>
beinhaerter7eb8f412018-02-23 22:35:36 +0100746constexpr span<typename Container::value_type> make_span(Container& cont)
Tiagoebe7ebf2017-04-20 07:51:37 -0700747{
748 return span<typename Container::value_type>(cont);
749}
Rian Quinn2df9f852016-11-16 11:17:04 -0700750
751template <class Container>
beinhaerter7eb8f412018-02-23 22:35:36 +0100752constexpr span<const typename Container::value_type> make_span(const Container& cont)
Tiagoebe7ebf2017-04-20 07:51:37 -0700753{
754 return span<const typename Container::value_type>(cont);
755}
Rian Quinn2df9f852016-11-16 11:17:04 -0700756
757template <class Ptr>
beinhaerter7eb8f412018-02-23 22:35:36 +0100758constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count)
Tiagoebe7ebf2017-04-20 07:51:37 -0700759{
760 return span<typename Ptr::element_type>(cont, count);
761}
Rian Quinn2df9f852016-11-16 11:17:04 -0700762
763template <class Ptr>
beinhaerter7eb8f412018-02-23 22:35:36 +0100764constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
Tiagoebe7ebf2017-04-20 07:51:37 -0700765{
766 return span<typename Ptr::element_type>(cont);
767}
Rian Quinn2df9f852016-11-16 11:17:04 -0700768
ericLemanissier134f2db2016-08-23 10:30:06 +0200769// Specialization of gsl::at for span
770template <class ElementType, std::ptrdiff_t Extent>
paweldacb3870ca2018-02-21 22:33:07 +0100771constexpr ElementType& at(span<ElementType, Extent> s, index i)
ericLemanissier134f2db2016-08-23 10:30:06 +0200772{
773 // No bounds checking here because it is done in span::operator[] called below
paweldacb3870ca2018-02-21 22:33:07 +0100774 return s[i];
ericLemanissier134f2db2016-08-23 10:30:06 +0200775}
776
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800777} // namespace gsl
778
Anna Gringauze6418b5f2019-01-15 10:27:34 -0800779#if defined(_MSC_VER) && !defined(__clang__)
Tiagoebe7ebf2017-04-20 07:51:37 -0700780#if _MSC_VER < 1910
781#undef constexpr
782#pragma pop_macro("constexpr")
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800783
Tiagoebe7ebf2017-04-20 07:51:37 -0700784#endif // _MSC_VER < 1910
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800785
Tiagoebe7ebf2017-04-20 07:51:37 -0700786#pragma warning(pop)
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800787#endif // _MSC_VER
788
Anna Gringauze6418b5f2019-01-15 10:27:34 -0800789#if defined(__GNUC__) && __GNUC__ > 6
meneteffdaf0f2018-06-08 20:41:06 +0200790#pragma GCC diagnostic pop
791#endif // __GNUC__ > 6
792
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800793#endif // GSL_SPAN_H