blob: 004afc78a0ce6d7caaa2af4eeac8255bb730d0d6 [file] [log] [blame]
Neil MacIntosh94afa1f2016-08-01 18:49:48 -07001
Neil MacIntoshcec26a22016-02-24 11:26:28 -08002///////////////////////////////////////////////////////////////////////////////
3//
4// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
5//
6// This code is licensed under the MIT License (MIT).
7//
8// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
13// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
14// THE SOFTWARE.
15//
16///////////////////////////////////////////////////////////////////////////////
17
18#pragma once
19
20#ifndef GSL_SPAN_H
21#define GSL_SPAN_H
22
23#include "gsl_assert.h"
Neil MacIntosh26747242016-06-26 17:00:56 +030024#include "gsl_byte.h"
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070025#include "gsl_util.h"
Neil MacIntoshcec26a22016-02-24 11:26:28 -080026#include <array>
Neil MacIntoshd3929c52016-02-24 16:11:33 -080027#include <iterator>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070028#include <limits>
Neil MacIntoshcec26a22016-02-24 11:26:28 -080029#include <stdexcept>
30#include <type_traits>
31#include <utility>
32
33#ifdef _MSC_VER
34
Neil MacIntoshcec26a22016-02-24 11:26:28 -080035#pragma warning(push)
Neil MacIntosha9f0ce22016-03-31 12:01:07 -070036
37// turn off some warnings that are noisy about our Expects statements
Neil MacIntoshcec26a22016-02-24 11:26:28 -080038#pragma warning(disable : 4127) // conditional expression is constant
39
Neil MacIntosha9f0ce22016-03-31 12:01:07 -070040// blanket turn off warnings from CppCoreCheck for now
41// so people aren't annoyed by them when running the tool.
42// more targeted suppressions will be added in a future update to the GSL
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070043#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495)
Neil MacIntosha9f0ce22016-03-31 12:01:07 -070044
Neil MacIntoshcec26a22016-02-24 11:26:28 -080045// No MSVC does constexpr fully yet
46#pragma push_macro("constexpr")
47#define constexpr
48
49// VS 2013 workarounds
50#if _MSC_VER <= 1800
51
52#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
Neil MacIntosh8e31f532016-07-29 11:16:06 -070053#define GSL_MSVC_NO_DEFAULT_MOVE_CTOR
54#define GSL_MSVC_NO_CPP14_STD_EQUAL
Neil MacIntoshcec26a22016-02-24 11:26:28 -080055
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070056// noexcept is not understood
Neil MacIntoshcec26a22016-02-24 11:26:28 -080057#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
58#pragma push_macro("noexcept")
59#define noexcept /* nothing */
60#endif
61
Neil MacIntosh8e31f532016-07-29 11:16:06 -070062#pragma push_macro("alignof")
63#define alignof __alignof
64
Neil MacIntoshcec26a22016-02-24 11:26:28 -080065// turn off some misguided warnings
66#pragma warning(push)
67#pragma warning(disable : 4351) // warns about newly introduced aggregate initializer behavior
68#pragma warning(disable : 4512) // warns that assignment op could not be generated
69
70#endif // _MSC_VER <= 1800
71
72#endif // _MSC_VER
73
74#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
75
76#ifdef _MSC_VER
77#pragma push_macro("noexcept")
78#endif
79
80#define noexcept /* nothing */
81
82#endif // GSL_THROW_ON_CONTRACT_VIOLATION
83
84namespace gsl
85{
86
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070087// [views.constants], constants
Neil MacIntoshc94a66f2016-06-12 18:28:19 -070088constexpr const std::ptrdiff_t dynamic_extent = -1;
89
Neil MacIntoshc366f442016-07-26 18:34:27 -070090template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
91class span;
92
Neil MacIntoshc94a66f2016-06-12 18:28:19 -070093// implementation details
Neil MacIntoshc40094a2016-03-01 12:11:41 -080094namespace details
95{
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070096 template <class T>
97 struct is_span_oracle : std::false_type
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -070098 {
Neil MacIntoshb03b04b2016-07-20 13:17:47 -070099 };
100
101 template <class ElementType, std::ptrdiff_t Extent>
102 struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
103 {
104 };
105
106 template <class T>
Neil MacIntoshc366f442016-07-26 18:34:27 -0700107 struct is_span : public is_span_oracle<std::remove_cv_t<T>>
108 {
109 };
110
111 template <class T>
112 struct is_std_array_oracle : std::false_type
113 {
114 };
115
116 template <class ElementType, size_t Extent>
117 struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
118 {
119 };
120
121 template <class T>
122 struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700123 {
124 };
125
126 template <class From, class To>
127 struct is_allowed_pointer_conversion
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700128 : public std::integral_constant<bool, std::is_pointer<From>::value &&
129 std::is_pointer<To>::value &&
130 std::is_convertible<From, To>::value>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700131 {
132 };
133
134 template <class From, class To>
135 struct is_allowed_integral_conversion
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700136 : public std::integral_constant<
137 bool, std::is_integral<From>::value && std::is_integral<To>::value &&
138 sizeof(From) == sizeof(To) && alignof(From) == alignof(To) &&
139 std::is_convertible<From, To>::value>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700140 {
141 };
142
143 template <std::ptrdiff_t From, std::ptrdiff_t To>
144 struct is_allowed_extent_conversion
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700145 : public std::integral_constant<bool, From == To || From == gsl::dynamic_extent ||
146 To == gsl::dynamic_extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700147 {
148 };
149
150 template <class From, class To>
151 struct is_allowed_element_type_conversion
Neil MacIntoshc366f442016-07-26 18:34:27 -0700152 : public std::integral_constant<bool, std::is_same<From, std::remove_cv_t<To>>::value ||
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700153 is_allowed_pointer_conversion<From, To>::value ||
154 is_allowed_integral_conversion<From, To>::value>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700155 {
156 };
157
158 template <class From>
159 struct is_allowed_element_type_conversion<From, byte>
Neil MacIntoshc366f442016-07-26 18:34:27 -0700160 : public std::integral_constant<bool, !std::is_const<From>::value>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700161 {
162 };
163
164 template <class From>
Neil MacIntoshc366f442016-07-26 18:34:27 -0700165 struct is_allowed_element_type_conversion<From, const byte> : public std::true_type
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700166 {
167 };
168
169 template <class Span>
170 class const_span_iterator
171 {
172 public:
173 using iterator_category = std::random_access_iterator_tag;
174 using value_type = typename Span::element_type;
175 using difference_type = std::ptrdiff_t;
176
177 using const_pointer = std::add_const_t<value_type*>;
178 using pointer = const_pointer;
179
180 using const_reference = std::add_const_t<value_type&>;
181 using reference = const_reference;
182
183 constexpr const_span_iterator() : const_span_iterator(nullptr, 0) {}
184 constexpr const_span_iterator(const Span* span, typename Span::index_type index)
185 : span_(span), index_(index)
186 {
187 Expects(span == nullptr || (index_ >= 0 && index <= span_->length()));
188 }
189
190 constexpr reference operator*() const
191 {
192 Expects(span_);
193 return (*span_)[index_];
194 }
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700195
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700196 constexpr pointer operator->() const
197 {
198 Expects(span_);
199 return &((*span_)[index_]);
200 }
201
202 constexpr const_span_iterator& operator++() noexcept
203 {
204 Expects(span_ && index_ >= 0 && index_ < span_->length());
205 ++index_;
206 return *this;
207 }
208
209 constexpr const_span_iterator operator++(int) noexcept
210 {
211 auto ret = *this;
212 ++(*this);
213 return ret;
214 }
215
216 constexpr const_span_iterator& operator--() noexcept
217 {
218 Expects(span_ && index_ > 0 && index_ <= span_->length());
219 --index_;
220 return *this;
221 }
222
223 constexpr const_span_iterator operator--(int) noexcept
224 {
225 auto ret = *this;
226 --(*this);
227 return ret;
228 }
229
230 constexpr const_span_iterator operator+(difference_type n) const noexcept
231 {
Neil MacIntosh4de3d4e2016-07-26 18:44:13 -0700232 auto ret = *this;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700233 return ret += n;
234 }
235
236 constexpr const_span_iterator& operator+=(difference_type n) noexcept
237 {
238 Expects(span_ && (index_ + n) >= 0 && (index_ + n) <= span_->length());
239 index_ += n;
240 return *this;
241 }
242
243 constexpr const_span_iterator operator-(difference_type n) const noexcept
244 {
Neil MacIntosh4de3d4e2016-07-26 18:44:13 -0700245 auto ret = *this;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700246 return ret -= n;
247 }
248
249 constexpr const_span_iterator& operator-=(difference_type n) noexcept
250 {
251 return *this += -n;
252 }
253
254 constexpr difference_type operator-(const const_span_iterator& rhs) const noexcept
255 {
256 Expects(span_ == rhs.span_);
257 return index_ - rhs.index_;
258 }
259
260 constexpr reference operator[](difference_type n) const noexcept { return *(*this + n); }
261
262 constexpr bool operator==(const const_span_iterator& rhs) const noexcept
263 {
264 return span_ == rhs.span_ && index_ == rhs.index_;
265 }
266
267 constexpr bool operator!=(const const_span_iterator& rhs) const noexcept
268 {
269 return !(*this == rhs);
270 }
271
272 constexpr bool operator<(const const_span_iterator& rhs) const noexcept
273 {
274 Expects(span_ == rhs.span_);
275 return index_ < rhs.index_;
276 }
277
278 constexpr bool operator<=(const const_span_iterator& rhs) const noexcept
279 {
280 return !(rhs < *this);
281 }
282
283 constexpr bool operator>(const const_span_iterator& rhs) const noexcept
284 {
285 return rhs < *this;
286 }
287
288 constexpr bool operator>=(const const_span_iterator& rhs) const noexcept
289 {
290 return !(rhs > *this);
291 }
292
293 void swap(const_span_iterator& rhs) noexcept
294 {
295 std::swap(index_, rhs.index_);
Neil MacIntoshc366f442016-07-26 18:34:27 -0700296 std::swap(span_, rhs.span_);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700297 }
298
299 private:
300 const Span* span_;
Neil MacIntoshc366f442016-07-26 18:34:27 -0700301 std::ptrdiff_t index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700302 };
303
304 template <class Span>
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700305 class span_iterator
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700306 {
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700307 public:
308 using iterator_category = std::random_access_iterator_tag;
309 using value_type = typename Span::element_type;
310 using difference_type = std::ptrdiff_t;
311
312 using pointer = value_type*;
313 using reference = value_type&;
314
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700315 constexpr span_iterator() : span_iterator(nullptr, 0) {}
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700316 constexpr span_iterator(const Span* span, typename Span::index_type index)
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700317 : span_(span), index_(index)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700318 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700319 Expects(span == nullptr || (index_ >= 0 && index <= span_->length()));
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700320 }
321
322 constexpr reference operator*() const
323 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700324 Expects(span_);
325 return (*span_)[index_];
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700326 }
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700327
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700328 constexpr pointer operator->() const
329 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700330 Expects(span_);
331 return &((*span_)[index_]);
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700332 }
333
334 constexpr span_iterator& operator++() noexcept
335 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700336 Expects(span_ && index_ >= 0 && index_ < span_->length());
337 ++index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700338 return *this;
339 }
340
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700341 constexpr span_iterator operator++(int) noexcept
342 {
343 auto ret = *this;
344 ++(*this);
345 return ret;
346 }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700347
348 constexpr span_iterator& operator--() noexcept
349 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700350 Expects(span_ && index_ > 0 && index_ <= span_->length());
351 --index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700352 return *this;
353 }
354
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700355 constexpr span_iterator operator--(int) noexcept
356 {
357 auto ret = *this;
358 --(*this);
359 return ret;
360 }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700361
362 constexpr span_iterator operator+(difference_type n) const noexcept
363 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700364 auto ret = *this;
365 return ret += n;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700366 }
367
368 constexpr span_iterator& operator+=(difference_type n) noexcept
369 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700370 Expects(span_ && (index_ + n) >= 0 && (index_ + n) <= span_->length());
371 index_ += n;
372 return *this;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700373 }
374
375 constexpr span_iterator operator-(difference_type n) const noexcept
376 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700377 auto ret = *this;
378 return ret -= n;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700379 }
380
381 constexpr span_iterator& operator-=(difference_type n) noexcept
382 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700383 return *this += -n;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700384 }
385
386 constexpr difference_type operator-(const span_iterator& rhs) const noexcept
387 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700388 Expects(span_ == rhs.span_);
389 return index_ - rhs.index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700390 }
391
392 constexpr reference operator[](difference_type n) const noexcept { return *(*this + n); }
393
394 constexpr bool operator==(const span_iterator& rhs) const noexcept
395 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700396 return span_ == rhs.span_ && index_ == rhs.index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700397 }
398
399 constexpr bool operator!=(const span_iterator& rhs) const noexcept
400 {
401 return !(*this == rhs);
402 }
403
404 constexpr bool operator<(const span_iterator& rhs) const noexcept
405 {
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700406 Expects(span_ == rhs.span_);
407 return index_ < rhs.index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700408 }
409
410 constexpr bool operator<=(const span_iterator& rhs) const noexcept
411 {
412 return !(rhs < *this);
413 }
414
415 constexpr bool operator>(const span_iterator& rhs) const noexcept { return rhs < *this; }
416
417 constexpr bool operator>=(const span_iterator& rhs) const noexcept
418 {
419 return !(rhs > *this);
420 }
421
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700422 void swap(span_iterator& rhs) noexcept
423 {
424 std::swap(index_, rhs.index_);
425 std::swap(span_, rhs.span_);
426 }
427
Neil MacIntoshc366f442016-07-26 18:34:27 -0700428 private:
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700429 const Span* span_;
430 std::ptrdiff_t index_;
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700431 };
432
433 template <typename Span>
434 constexpr const_span_iterator<Span>
435 operator+(typename const_span_iterator<Span>::difference_type n,
436 const const_span_iterator<Span>& rhs) noexcept
437 {
438 return rhs + n;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700439 }
440
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700441 template <typename Span>
442 constexpr const_span_iterator<Span>
443 operator-(typename const_span_iterator<Span>::difference_type n,
444 const const_span_iterator<Span>& rhs) noexcept
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700445 {
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700446 return rhs - n;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700447 }
448
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700449 template <typename Span>
450 constexpr span_iterator<Span> operator+(typename span_iterator<Span>::difference_type n,
451 const span_iterator<Span>& rhs) noexcept
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700452 {
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700453 return rhs + n;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700454 }
455
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700456 template <typename Span>
457 constexpr span_iterator<Span> operator-(typename span_iterator<Span>::difference_type n,
458 const span_iterator<Span>& rhs) noexcept
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700459 {
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700460 return rhs - n;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700461 }
462
Neil MacIntoshc366f442016-07-26 18:34:27 -0700463 template <std::ptrdiff_t Ext>
464 class extent_type
465 {
466 public:
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700467 using index_type = std::ptrdiff_t;
Neil MacIntoshc366f442016-07-26 18:34:27 -0700468
469 static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
470
471 constexpr extent_type() noexcept {}
472
473 template <index_type Other>
474 constexpr extent_type(extent_type<Other> ext) noexcept
475 {
476 static_assert(Other == Ext || Other == dynamic_extent,
477 "Mismatch between fixed-size extent and size of initializing data.");
478 Expects(ext.size() == Ext);
479 }
480
481 constexpr extent_type(index_type size) { Expects(size == Ext); }
482
483 constexpr inline index_type size() const noexcept { return Ext; }
484 };
485
486 template <>
487 class extent_type<dynamic_extent>
488 {
489 public:
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700490 using index_type = std::ptrdiff_t;
Neil MacIntoshc366f442016-07-26 18:34:27 -0700491
492 template <index_type Other>
493 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
494 {
495 }
496
497 explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
498
499 constexpr inline index_type size() const noexcept { return size_; }
500
501 private:
502 index_type size_;
503 };
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800504} // namespace details
505
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700506// [span], class template span
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800507template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700508class span
509{
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800510public:
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700511 // constants and types
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800512 using element_type = ElementType;
513 using index_type = std::ptrdiff_t;
514 using pointer = element_type*;
515 using reference = element_type&;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700516
517 using iterator = details::span_iterator<span<ElementType, Extent>>;
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700518 using const_iterator = details::const_span_iterator<span<ElementType,Extent>>;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800519 using reverse_iterator = std::reverse_iterator<iterator>;
Neil MacIntosh26747242016-06-26 17:00:56 +0300520 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700521
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800522 constexpr static const index_type extent = Extent;
523
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700524 // [span.cons], span constructors, copy, assignment, and destructor
Neil MacIntoshc366f442016-07-26 18:34:27 -0700525 constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800526
Neil MacIntoshc366f442016-07-26 18:34:27 -0700527 constexpr span(std::nullptr_t) noexcept : span() {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800528
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700529 constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800530
Neil MacIntosh502cd662016-02-28 00:50:53 -0800531 constexpr span(pointer firstElem, pointer lastElem)
532 : storage_(firstElem, std::distance(firstElem, lastElem))
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700533 {
534 }
Neil MacIntoshf61a9bb2016-02-29 13:16:48 -0800535
536 template <size_t N>
Neil MacIntoshc366f442016-07-26 18:34:27 -0700537 constexpr span(element_type (&arr)[N]) noexcept : storage_(&arr[0], details::extent_type<N>())
538 {
539 }
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700540
Neil MacIntoshc366f442016-07-26 18:34:27 -0700541 template <size_t N, class ArrayElementType = std::remove_const_t<element_type>>
542 constexpr span(std::array<ArrayElementType, N>& arr) noexcept
543 : storage_(&arr[0], details::extent_type<N>())
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700544 {
545 }
546
547 template <size_t N>
Neil MacIntoshf2ab3a52016-07-20 09:24:49 -0700548 constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
Neil MacIntoshc366f442016-07-26 18:34:27 -0700549 : storage_(&arr[0], details::extent_type<N>())
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700550 {
551 }
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800552
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800553 // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
554 // on Container to be a contiguous sequence container.
555 template <class Container,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700556 class = std::enable_if_t<
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700557 !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
Neil MacIntoshc366f442016-07-26 18:34:27 -0700558 std::is_convertible<typename Container::pointer, pointer>::value &&
559 std::is_convertible<typename Container::pointer,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700560 decltype(std::declval<Container>().data())>::value>>
561 constexpr span(Container& cont) : span(cont.data(), cont.size())
562 {
563 }
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800564
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800565 template <class Container,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700566 class = std::enable_if_t<
567 std::is_const<element_type>::value && !details::is_span<Container>::value &&
Neil MacIntoshc366f442016-07-26 18:34:27 -0700568 std::is_convertible<typename Container::pointer, pointer>::value &&
569 std::is_convertible<typename Container::pointer,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700570 decltype(std::declval<Container>().data())>::value>>
571 constexpr span(const Container& cont) : span(cont.data(), cont.size())
572 {
573 }
Neil MacIntosh3d4c3492016-03-17 17:20:33 -0700574
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800575 constexpr span(const span& other) noexcept = default;
Neil MacIntosh8e31f532016-07-29 11:16:06 -0700576#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800577 constexpr span(span&& other) noexcept = default;
Neil MacIntosh8e31f532016-07-29 11:16:06 -0700578#else
579 constexpr span(span&& other) noexcept : storage_(std::move(other.storage_)) {}
580#endif
Neil MacIntosh717a2e32016-03-16 19:39:55 -0700581
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700582 template <
583 class OtherElementType, std::ptrdiff_t OtherExtent,
Neil MacIntoshc94a66f2016-06-12 18:28:19 -0700584 class = std::enable_if_t<
585 details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700586 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
587 constexpr span(const span<OtherElementType, OtherExtent>& other)
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700588 : storage_(reinterpret_cast<pointer>(other.data()),
589 details::extent_type<OtherExtent>(other.size()))
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700590 {
591 }
592
593 template <
594 class OtherElementType, std::ptrdiff_t OtherExtent,
595 class = std::enable_if_t<
596 details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
597 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
Neil MacIntosh717a2e32016-03-16 19:39:55 -0700598 constexpr span(span<OtherElementType, OtherExtent>&& other)
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700599 : storage_(reinterpret_cast<pointer>(other.data()),
600 details::extent_type<OtherExtent>(other.size()))
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700601 {
602 }
Neil MacIntosh717a2e32016-03-16 19:39:55 -0700603
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800604 ~span() noexcept = default;
605 constexpr span& operator=(const span& other) noexcept = default;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800606
Neil MacIntosh8e31f532016-07-29 11:16:06 -0700607#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR
608 constexpr span& operator=(span&& other) noexcept = default;
609#else
Neil MacIntosh1bd2d042016-08-01 13:10:02 -0700610 constexpr span& operator=(span&& other) noexcept
611 {
612 storage_ = std::move(other.storage_);
613 return *this;
614 }
Neil MacIntosh8e31f532016-07-29 11:16:06 -0700615#endif
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700616 // [span.sub], span subviews
Neil MacIntoshc366f442016-07-26 18:34:27 -0700617 template <std::ptrdiff_t Count>
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700618 constexpr span<element_type, Count> first() const
619 {
620 Expects(Count >= 0 && Count <= size());
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700621 return {data(), Count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700622 }
623
Neil MacIntoshc366f442016-07-26 18:34:27 -0700624 template <std::ptrdiff_t Count>
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700625 constexpr span<element_type, Count> last() const
626 {
627 Expects(Count >= 0 && Count <= size());
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700628 return {data() + (size() - Count), Count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700629 }
630
Neil MacIntoshc366f442016-07-26 18:34:27 -0700631 template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700632 constexpr span<element_type, Count> subspan() const
633 {
Neil MacIntoshc366f442016-07-26 18:34:27 -0700634 Expects((Offset == 0 || (Offset > 0 && Offset <= size())) &&
635 (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700636 return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700637 }
638
639 constexpr span<element_type, dynamic_extent> first(index_type count) const
640 {
641 Expects(count >= 0 && count <= size());
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700642 return {data(), count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700643 }
644
645 constexpr span<element_type, dynamic_extent> last(index_type count) const
646 {
647 Expects(count >= 0 && count <= size());
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700648 return {data() + (size() - count), count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700649 }
650
651 constexpr span<element_type, dynamic_extent> subspan(index_type offset,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700652 index_type count = dynamic_extent) const
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700653 {
Neil MacIntoshc366f442016-07-26 18:34:27 -0700654 Expects((offset == 0 || (offset > 0 && offset <= size())) &&
655 (count == dynamic_extent || (count >= 0 && offset + count <= size())));
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700656 return {data() + offset, count == dynamic_extent ? size() - offset : count};
Neil MacIntoshc8a412f2016-03-18 16:49:29 -0700657 }
658
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700659 // [span.obs], span observers
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800660 constexpr index_type length() const noexcept { return size(); }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700661 constexpr index_type size() const noexcept { return storage_.size(); }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800662 constexpr index_type length_bytes() const noexcept { return size_bytes(); }
663 constexpr index_type size_bytes() const noexcept { return size() * sizeof(element_type); }
664 constexpr bool empty() const noexcept { return size() == 0; }
665
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700666 // [span.elem], span element access
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800667 constexpr reference operator[](index_type idx) const
668 {
Neil MacIntosh502cd662016-02-28 00:50:53 -0800669 Expects(idx >= 0 && idx < storage_.size());
Neil MacIntoshf2ab3a52016-07-20 09:24:49 -0700670 return data()[idx];
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800671 }
672 constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800673 constexpr pointer data() const noexcept { return storage_.data(); }
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700674
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700675 // [span.iter], span iterator support
Neil MacIntoshd9d6ff02016-05-29 13:52:28 -0700676 iterator begin() const noexcept { return {this, 0}; }
677 iterator end() const noexcept { return {this, length()}; }
Neil MacIntosh30a038c2016-07-18 11:38:01 -0700678
679 const_iterator cbegin() const noexcept { return {this, 0}; }
680 const_iterator cend() const noexcept { return {this, length()}; }
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700681
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700682 reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
683 reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
Neil MacIntosh30a038c2016-07-18 11:38:01 -0700684
Neil MacIntosh94afa1f2016-08-01 18:49:48 -0700685 const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; }
686 const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800687
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800688private:
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700689 // this implementation detail class lets us take advantage of the
Neil MacIntosh502cd662016-02-28 00:50:53 -0800690 // empty base class optimization to pay for only storage of a single
691 // pointer in the case of fixed-size spans
692 template <class ExtentType>
693 class storage_type : public ExtentType
694 {
695 public:
696 template <class OtherExtentType>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700697 constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
698 {
Neil MacIntosh4de3d4e2016-07-26 18:44:13 -0700699 Expects((!data && ExtentType::size() == 0) || (data && ExtentType::size() >= 0));
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700700 }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800701
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700702 constexpr inline pointer data() const noexcept { return data_; }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800703
704 private:
705 pointer data_;
706 };
707
Neil MacIntoshc366f442016-07-26 18:34:27 -0700708 storage_type<details::extent_type<Extent>> storage_;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800709};
710
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700711// [span.comparison], span comparison operators
Neil MacIntoshc366f442016-07-26 18:34:27 -0700712template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700713constexpr bool operator==(const span<ElementType, FirstExtent>& l,
714 const span<ElementType, SecondExtent>& r)
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700715{
Neil MacIntosh8e31f532016-07-29 11:16:06 -0700716#ifdef GSL_MSVC_NO_CPP14_STD_EQUAL
717 return (l.size() == r.size()) && std::equal(l.begin(), l.end(), r.begin());
718#else
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700719 return std::equal(l.begin(), l.end(), r.begin(), r.end());
Neil MacIntosh8e31f532016-07-29 11:16:06 -0700720#endif
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700721}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800722
Neil MacIntoshc366f442016-07-26 18:34:27 -0700723template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700724constexpr bool operator!=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r)
725{
726 return !(l == r);
727}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800728
Neil MacIntoshc366f442016-07-26 18:34:27 -0700729template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700730constexpr bool operator<(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r)
731{
732 return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
733}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800734
Neil MacIntoshc366f442016-07-26 18:34:27 -0700735template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700736constexpr bool operator<=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r)
737{
738 return !(l > r);
739}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800740
Neil MacIntoshc366f442016-07-26 18:34:27 -0700741template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700742constexpr bool operator>(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r)
743{
744 return r < l;
745}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800746
Neil MacIntoshc366f442016-07-26 18:34:27 -0700747template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700748constexpr bool operator>=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r)
749{
750 return !(l < r);
751}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800752
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700753namespace details
754{
755 // if we only supported compilers with good constexpr support then
756 // this pair of classes could collapse down to a constexpr function
757
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700758 // we should use a narrow_cast<> to go to size_t, but older compilers may not see it as
759 // constexpr
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700760 // and so will fail compilation of the template
Neil MacIntoshc366f442016-07-26 18:34:27 -0700761 template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700762 struct calculate_byte_size
763 : std::integral_constant<std::ptrdiff_t,
Neil MacIntoshc366f442016-07-26 18:34:27 -0700764 static_cast<std::ptrdiff_t>(sizeof(ElementType) *
Neil MacIntosh6fadce92016-07-26 19:19:47 -0700765 static_cast<std::size_t>(Extent))>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700766 {
767 };
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700768
769 template <class ElementType>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700770 struct calculate_byte_size<ElementType, dynamic_extent>
771 : std::integral_constant<std::ptrdiff_t, dynamic_extent>
772 {
773 };
Neil MacIntoshba8ebef2016-05-29 17:06:29 -0700774}
775
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700776// [span.objectrep], views of object representation
Neil MacIntoshc366f442016-07-26 18:34:27 -0700777template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700778span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
779as_bytes(span<ElementType, Extent> s) noexcept
780{
781 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
782}
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800783
Neil MacIntoshc366f442016-07-26 18:34:27 -0700784template <class ElementType, std::ptrdiff_t Extent,
Neil MacIntoshb03b04b2016-07-20 13:17:47 -0700785 class = std::enable_if_t<!std::is_const<ElementType>::value>>
786span<byte, details::calculate_byte_size<ElementType, Extent>::value>
787as_writeable_bytes(span<ElementType, Extent> s) noexcept
788{
789 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
790}
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800791
792} // namespace gsl
793
794#ifdef _MSC_VER
795
796#undef constexpr
797#pragma pop_macro("constexpr")
798
799#if _MSC_VER <= 1800
800#pragma warning(pop)
801
802#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
803#undef noexcept
804#pragma pop_macro("noexcept")
805#endif // GSL_THROW_ON_CONTRACT_VIOLATION
806
Neil MacIntosh8e31f532016-07-29 11:16:06 -0700807#pragma pop_macro("alignof")
808
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800809#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
810
811#endif // _MSC_VER <= 1800
812
813#endif // _MSC_VER
814
815#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
816
817#undef noexcept
818
819#ifdef _MSC_VER
820#pragma warning(pop)
821#pragma pop_macro("noexcept")
822#endif
823
824#endif // GSL_THROW_ON_CONTRACT_VIOLATION
825
826#endif // GSL_SPAN_H