blob: 7e8c1192fde7e6b9e8324fb3ba720ce780641bfd [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
17#pragma once
18
19#ifndef GSL_SPAN_H
20#define GSL_SPAN_H
21
22#include "gsl_assert.h"
23#include "gsl_util.h"
Neil MacIntoshcec26a22016-02-24 11:26:28 -080024#include <array>
Neil MacIntoshcec26a22016-02-24 11:26:28 -080025#include <limits>
Neil MacIntoshd3929c52016-02-24 16:11:33 -080026#include <iterator>
Neil MacIntoshcec26a22016-02-24 11:26:28 -080027#include <stdexcept>
28#include <type_traits>
29#include <utility>
30
31#ifdef _MSC_VER
32
33// turn off some warnings that are noisy about our Expects statements
34#pragma warning(push)
35#pragma warning(disable : 4127) // conditional expression is constant
36
37// No MSVC does constexpr fully yet
38#pragma push_macro("constexpr")
39#define constexpr
40
41// VS 2013 workarounds
42#if _MSC_VER <= 1800
43
44#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
45#define GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
46
47// noexcept is not understood
48#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
49#pragma push_macro("noexcept")
50#define noexcept /* nothing */
51#endif
52
53// turn off some misguided warnings
54#pragma warning(push)
55#pragma warning(disable : 4351) // warns about newly introduced aggregate initializer behavior
56#pragma warning(disable : 4512) // warns that assignment op could not be generated
57
58#endif // _MSC_VER <= 1800
59
60#endif // _MSC_VER
61
62#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
63
64#ifdef _MSC_VER
65#pragma push_macro("noexcept")
66#endif
67
68#define noexcept /* nothing */
69
70#endif // GSL_THROW_ON_CONTRACT_VIOLATION
71
72namespace gsl
73{
74
Neil MacIntoshc40094a2016-03-01 12:11:41 -080075template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
76class span;
77
78
79namespace details
80{
81template <class T>
82struct is_span_oracle : std::false_type
83{
84};
85
86template <class ElementType, std::ptrdiff_t Extent>
87struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
88{
89};
90
91template <class T>
92struct is_span : is_span_oracle<std::remove_cv_t<T>>
93{
94};
Neil MacIntosh717a2e32016-03-16 19:39:55 -070095
96template <class From, class To>
97struct is_allowed_pointer_conversion
98 : std::integral_constant<bool,
99 std::is_pointer<From>::value &&
100 std::is_pointer<To>::value &&
101 std::is_convertible<From, To>::value
102 >
103{
104};
105
106template <class From, class To>
107struct is_allowed_integral_conversion
108 : std::integral_constant<bool,
109 std::is_integral<From>::value &&
110 std::is_integral<To>::value &&
111 sizeof(From) == sizeof(To) &&
112 alignof(From) == alignof(To) &&
113 std::is_convertible<From, To>::value
114 >
115{
116};
117
118template <class From, class To>
119struct is_allowed_element_type_conversion
120 : std::integral_constant<bool,
121 std::is_same<From, std::remove_cv_t<To>>::value ||
122 is_allowed_pointer_conversion<From, To>::value ||
123 is_allowed_integral_conversion<From, To>::value
124 >
125{
126};
127
128template <class From>
129struct is_allowed_element_type_conversion<From, char>
130 : std::integral_constant<bool, !std::is_const<From>::value>
131{
132};
133
134template <class From>
135struct is_allowed_element_type_conversion<From, const char>
136 : std::integral_constant<bool, true>
137{
138};
139
140
141
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800142} // namespace details
143
144
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800145// [views.constants], constants
146constexpr const std::ptrdiff_t dynamic_extent = -1;
147
148
149// [span], class template span
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800150template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800151class span {
152public:
153 // constants and types
154 using element_type = ElementType;
155 using index_type = std::ptrdiff_t;
156 using pointer = element_type*;
157 using reference = element_type&;
158#if 0 // TODO
159 using iterator = /*implementation-defined */;
160 using const_iterator = /* implementation-defined */;
161 using reverse_iterator = std::reverse_iterator<iterator>;
162 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
163#endif
164 constexpr static const index_type extent = Extent;
165
166 // [span.cons], span constructors, copy, assignment, and destructor
Neil MacIntosh502cd662016-02-28 00:50:53 -0800167 constexpr span() noexcept : storage_(nullptr, extent_type<0>())
168 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800169
170 constexpr span(nullptr_t) noexcept : span()
171 {}
172
Neil MacIntosh502cd662016-02-28 00:50:53 -0800173 constexpr span(pointer ptr, index_type count) : storage_(ptr, count)
174 { Expects(((!ptr && count == 0) || (ptr && count >= 0))); }
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800175
Neil MacIntosh502cd662016-02-28 00:50:53 -0800176 constexpr span(pointer firstElem, pointer lastElem)
177 : storage_(firstElem, std::distance(firstElem, lastElem))
178 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800179
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800180 template <size_t N>
Neil MacIntoshf61a9bb2016-02-29 13:16:48 -0800181 constexpr span(element_type(&arr)[N])
182 : storage_(&arr[0], extent_type<N>())
183 {}
184
185 template <size_t N>
186 constexpr span(std::array<std::remove_const_t<element_type>, N>& arr)
187 : storage_(&arr[0], extent_type<N>())
188 {}
189
Neil MacIntosh3d4c3492016-03-17 17:20:33 -0700190 template <size_t N, class = std::enable_if_t<is_const<element_type>::value>>
Neil MacIntoshf61a9bb2016-02-29 13:16:48 -0800191 constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr)
192 : storage_(&arr[0], extent_type<N>())
Neil MacIntosh502cd662016-02-28 00:50:53 -0800193 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800194
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800195 // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
196 // on Container to be a contiguous sequence container.
197 template <class Container,
198 class = std::enable_if_t<!details::is_span<Container>::value &&
199 std::is_convertible<Container::pointer, pointer>::value &&
200 std::is_convertible<Container::pointer, decltype(std::declval<Container>().data())>::value>
201 >
202 constexpr span(Container& cont) : span(cont.data(), cont.size()) {}
203
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800204 template <class Container,
Neil MacIntosh3d4c3492016-03-17 17:20:33 -0700205 class = std::enable_if_t<std::is_const<element_type>::value &&
206 !details::is_span<Container>::value &&
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800207 std::is_convertible<Container::pointer, pointer>::value &&
208 std::is_convertible<Container::pointer, decltype(std::declval<Container>().data())>::value>
209 >
Neil MacIntosh3d4c3492016-03-17 17:20:33 -0700210 constexpr span(const Container& cont) : span(cont.data(), cont.size()) {}
211
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800212 constexpr span(const span& other) noexcept = default;
213 constexpr span(span&& other) noexcept = default;
Neil MacIntosh717a2e32016-03-16 19:39:55 -0700214
215 template <class OtherElementType, std::ptrdiff_t OtherExtent,
216 class = std::enable_if_t<!std::is_same<element_type, OtherElementType>::value &&
217 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value
218 >
219 >
220 constexpr span(const span<OtherElementType, OtherExtent>& other)
221 : storage_(reinterpret_cast<pointer>(other.data()), other.length())
222 {}
223
224 template <class OtherElementType, std::ptrdiff_t OtherExtent,
225 class = std::enable_if_t<!std::is_same<element_type, OtherElementType>::value &&
226 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value
227 >
228 >
229 constexpr span(span<OtherElementType, OtherExtent>&& other)
230 : storage_(reinterpret_cast<pointer>(other.data()), other.length())
231 {
232 }
233
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800234 ~span() noexcept = default;
235 constexpr span& operator=(const span& other) noexcept = default;
236 constexpr span& operator=(span&& other) noexcept = default;
Neil MacIntosh3d4c3492016-03-17 17:20:33 -0700237#if 0 // TODO
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800238
239 // [span.sub], span subviews
240 template <ptrdiff_t Count>
241 constexpr span<element_type, Count> first() const;
242 template <ptrdiff_t Count>
243 constexpr span<element_type, Count> last() const;
244 template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
245 constexpr span<element_type, Count> subspan() const;
246 constexpr span<element_type, dynamic_extent> first(index_type count) const;
247 constexpr span<element_type, dynamic_extent> last(index_type count) const;
248 constexpr span<element_type, dynamic_extent> subspan(index_type offset, index_type count = dynamic_extent) const;
249#endif
250 // [span.obs], span observers
251 constexpr index_type length() const noexcept { return size(); }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800252 constexpr index_type size() const noexcept { return storage_.size(); }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800253 constexpr index_type length_bytes() const noexcept { return size_bytes(); }
254 constexpr index_type size_bytes() const noexcept { return size() * sizeof(element_type); }
255 constexpr bool empty() const noexcept { return size() == 0; }
256
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800257 // [span.elem], span element access
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800258 constexpr reference operator[](index_type idx) const
259 {
Neil MacIntosh502cd662016-02-28 00:50:53 -0800260 Expects(idx >= 0 && idx < storage_.size());
261 return storage_.data()[idx];
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800262 }
263 constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800264 constexpr pointer data() const noexcept { return storage_.data(); }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800265#if 0 // TODO
266 // [span.iter], span iterator support
267 iterator begin() const noexcept;
268 iterator end() const noexcept;
269
270 const_iterator cbegin() const noexcept;
271 const_iterator cend() const noexcept;
272
273 reverse_iterator rbegin() const noexcept;
274 reverse_iterator rend() const noexcept;
275
276 const_reverse_iterator crbegin() const noexcept;
277 const_reverse_iterator crend() const noexcept;
278#endif
279private:
Neil MacIntosh502cd662016-02-28 00:50:53 -0800280 template <index_type Extent>
281 class extent_type;
282
283 template <index_type Extent>
284 class extent_type
285 {
286 public:
287 static_assert(Extent >= 0, "A fixed-size span must be >= 0 in size.");
288
289 constexpr extent_type() noexcept {}
290
291 template <index_type Other>
292 constexpr extent_type(extent_type<Other>) noexcept
293 {
294 static_assert(Other == Extent,
295 "Mismatch between fixed-size extent and size of initializing data.");
296 }
297
298 constexpr extent_type(index_type size)
299 { Expects(size == Extent); }
300
301 constexpr inline index_type size() const noexcept { return Extent; }
302 };
303
304 template <>
305 class extent_type<dynamic_extent>
306 {
307 public:
308 template <index_type Other>
309 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
310 {}
311
312 explicit constexpr extent_type(index_type size) : size_(size)
313 { Expects(size >= 0); }
314
315 constexpr inline index_type size() const noexcept
316 { return size_; }
317
318 private:
319 index_type size_;
320 };
321
322 // this implementation detail class lets us take advantage of the
323 // empty base class optimization to pay for only storage of a single
324 // pointer in the case of fixed-size spans
325 template <class ExtentType>
326 class storage_type : public ExtentType
327 {
328 public:
329 template <class OtherExtentType>
330 storage_type(pointer data, OtherExtentType ext)
331 : ExtentType(ext), data_(data) {}
332
Neil MacIntosh502cd662016-02-28 00:50:53 -0800333 constexpr inline pointer data() const noexcept
334 { return data_; }
335
336 private:
337 pointer data_;
338 };
339
340 storage_type<extent_type<Extent>> storage_;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800341};
342
343
344#if 0 // TODO
345// [span.comparison], span comparison operators
346template <class ElementType, ptrdiff_t Extent>
347constexpr bool operator==(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
348
349template <class ElementType, ptrdiff_t Extent>
350constexpr bool operator!=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
351
352template <class ElementType, ptrdiff_t Extent>
353constexpr bool operator<(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
354
355template <class ElementType, ptrdiff_t Extent>
356constexpr bool operator<=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
357
358template <class ElementType, ptrdiff_t Extent>
359constexpr bool operator>(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
360
361template <class ElementType, ptrdiff_t Extent>
362constexpr bool operator>=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
363#endif
364
365
366#if 0 // TODO
367// [span.objectrep], views of object representation
368template <class ElementType, ptrdiff_t Extent>
369constexpr span<const char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_bytes(span<ElementType, Extent> s) noexcept;
370
371template <class ElementType, ptrdiff_t Extent>
372constexpr span<char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_writeable_bytes(span<ElementType, Extent>) noexcept;
373#endif
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800374
375} // namespace gsl
376
377#ifdef _MSC_VER
378
379#undef constexpr
380#pragma pop_macro("constexpr")
381
382#if _MSC_VER <= 1800
383#pragma warning(pop)
384
385#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
386#undef noexcept
387#pragma pop_macro("noexcept")
388#endif // GSL_THROW_ON_CONTRACT_VIOLATION
389
390#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
391
392#endif // _MSC_VER <= 1800
393
394#endif // _MSC_VER
395
396#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
397
398#undef noexcept
399
400#ifdef _MSC_VER
401#pragma warning(pop)
402#pragma pop_macro("noexcept")
403#endif
404
405#endif // GSL_THROW_ON_CONTRACT_VIOLATION
406
407#endif // GSL_SPAN_H