blob: eab2659eab17be893c77d13783149c399aacd6fe [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};
95} // namespace details
96
97
Neil MacIntoshd3929c52016-02-24 16:11:33 -080098// [views.constants], constants
99constexpr const std::ptrdiff_t dynamic_extent = -1;
100
101
102// [span], class template span
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800103template <class ElementType, std::ptrdiff_t Extent>
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800104class span {
105public:
106 // constants and types
107 using element_type = ElementType;
108 using index_type = std::ptrdiff_t;
109 using pointer = element_type*;
110 using reference = element_type&;
111#if 0 // TODO
112 using iterator = /*implementation-defined */;
113 using const_iterator = /* implementation-defined */;
114 using reverse_iterator = std::reverse_iterator<iterator>;
115 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
116#endif
117 constexpr static const index_type extent = Extent;
118
119 // [span.cons], span constructors, copy, assignment, and destructor
Neil MacIntosh502cd662016-02-28 00:50:53 -0800120 constexpr span() noexcept : storage_(nullptr, extent_type<0>())
121 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800122
123 constexpr span(nullptr_t) noexcept : span()
124 {}
125
Neil MacIntosh502cd662016-02-28 00:50:53 -0800126 constexpr span(pointer ptr, index_type count) : storage_(ptr, count)
127 { Expects(((!ptr && count == 0) || (ptr && count >= 0))); }
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800128
Neil MacIntosh502cd662016-02-28 00:50:53 -0800129 constexpr span(pointer firstElem, pointer lastElem)
130 : storage_(firstElem, std::distance(firstElem, lastElem))
131 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800132
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800133 template <size_t N>
Neil MacIntoshf61a9bb2016-02-29 13:16:48 -0800134 constexpr span(element_type(&arr)[N])
135 : storage_(&arr[0], extent_type<N>())
136 {}
137
138 template <size_t N>
139 constexpr span(std::array<std::remove_const_t<element_type>, N>& arr)
140 : storage_(&arr[0], extent_type<N>())
141 {}
142
143 template <size_t N>
144 constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr)
145 : storage_(&arr[0], extent_type<N>())
Neil MacIntosh502cd662016-02-28 00:50:53 -0800146 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800147
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800148 // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
149 // on Container to be a contiguous sequence container.
150 template <class Container,
151 class = std::enable_if_t<!details::is_span<Container>::value &&
152 std::is_convertible<Container::pointer, pointer>::value &&
153 std::is_convertible<Container::pointer, decltype(std::declval<Container>().data())>::value>
154 >
155 constexpr span(Container& cont) : span(cont.data(), cont.size()) {}
156
157 // NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement
158 // on Container to be a contiguous sequence container.
159 template <class Container,
160 class = std::enable_if_t<!details::is_span<Container>::value &&
161 std::is_convertible<Container::pointer, pointer>::value &&
162 std::is_convertible<Container::pointer, decltype(std::declval<Container>().data())>::value>
163 >
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800164 span(const Container&&) = delete;
Neil MacIntoshc40094a2016-03-01 12:11:41 -0800165
166#if 0 // TODO
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800167 constexpr span(const span& other) noexcept = default;
168 constexpr span(span&& other) noexcept = default;
169 template <class OtherElementType, ptrdiff_t OtherExtent>
170 constexpr span(const span<OtherElementType, OtherExtent>& other);
171 template <class OtherElementType, ptrdiff_t OtherExtent>
172 constexpr span(span<OtherElementType, OtherExtent>&& other);
173 ~span() noexcept = default;
174 constexpr span& operator=(const span& other) noexcept = default;
175 constexpr span& operator=(span&& other) noexcept = default;
176
177 // [span.sub], span subviews
178 template <ptrdiff_t Count>
179 constexpr span<element_type, Count> first() const;
180 template <ptrdiff_t Count>
181 constexpr span<element_type, Count> last() const;
182 template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
183 constexpr span<element_type, Count> subspan() const;
184 constexpr span<element_type, dynamic_extent> first(index_type count) const;
185 constexpr span<element_type, dynamic_extent> last(index_type count) const;
186 constexpr span<element_type, dynamic_extent> subspan(index_type offset, index_type count = dynamic_extent) const;
187#endif
188 // [span.obs], span observers
189 constexpr index_type length() const noexcept { return size(); }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800190 constexpr index_type size() const noexcept { return storage_.size(); }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800191 constexpr index_type length_bytes() const noexcept { return size_bytes(); }
192 constexpr index_type size_bytes() const noexcept { return size() * sizeof(element_type); }
193 constexpr bool empty() const noexcept { return size() == 0; }
194
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800195 // [span.elem], span element access
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800196 constexpr reference operator[](index_type idx) const
197 {
Neil MacIntosh502cd662016-02-28 00:50:53 -0800198 Expects(idx >= 0 && idx < storage_.size());
199 return storage_.data()[idx];
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800200 }
201 constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800202 constexpr pointer data() const noexcept { return storage_.data(); }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800203#if 0 // TODO
204 // [span.iter], span iterator support
205 iterator begin() const noexcept;
206 iterator end() const noexcept;
207
208 const_iterator cbegin() const noexcept;
209 const_iterator cend() const noexcept;
210
211 reverse_iterator rbegin() const noexcept;
212 reverse_iterator rend() const noexcept;
213
214 const_reverse_iterator crbegin() const noexcept;
215 const_reverse_iterator crend() const noexcept;
216#endif
217private:
Neil MacIntosh502cd662016-02-28 00:50:53 -0800218 template <index_type Extent>
219 class extent_type;
220
221 template <index_type Extent>
222 class extent_type
223 {
224 public:
225 static_assert(Extent >= 0, "A fixed-size span must be >= 0 in size.");
226
227 constexpr extent_type() noexcept {}
228
229 template <index_type Other>
230 constexpr extent_type(extent_type<Other>) noexcept
231 {
232 static_assert(Other == Extent,
233 "Mismatch between fixed-size extent and size of initializing data.");
234 }
235
236 constexpr extent_type(index_type size)
237 { Expects(size == Extent); }
238
239 constexpr inline index_type size() const noexcept { return Extent; }
240 };
241
242 template <>
243 class extent_type<dynamic_extent>
244 {
245 public:
246 template <index_type Other>
247 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
248 {}
249
250 explicit constexpr extent_type(index_type size) : size_(size)
251 { Expects(size >= 0); }
252
253 constexpr inline index_type size() const noexcept
254 { return size_; }
255
256 private:
257 index_type size_;
258 };
259
260 // this implementation detail class lets us take advantage of the
261 // empty base class optimization to pay for only storage of a single
262 // pointer in the case of fixed-size spans
263 template <class ExtentType>
264 class storage_type : public ExtentType
265 {
266 public:
267 template <class OtherExtentType>
268 storage_type(pointer data, OtherExtentType ext)
269 : ExtentType(ext), data_(data) {}
270
Neil MacIntosh502cd662016-02-28 00:50:53 -0800271 constexpr inline pointer data() const noexcept
272 { return data_; }
273
274 private:
275 pointer data_;
276 };
277
278 storage_type<extent_type<Extent>> storage_;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800279};
280
281
282#if 0 // TODO
283// [span.comparison], span comparison operators
284template <class ElementType, ptrdiff_t Extent>
285constexpr bool operator==(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
286
287template <class ElementType, ptrdiff_t Extent>
288constexpr bool operator!=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
289
290template <class ElementType, ptrdiff_t Extent>
291constexpr bool operator<(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
292
293template <class ElementType, ptrdiff_t Extent>
294constexpr bool operator<=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
295
296template <class ElementType, ptrdiff_t Extent>
297constexpr bool operator>(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
298
299template <class ElementType, ptrdiff_t Extent>
300constexpr bool operator>=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
301#endif
302
303
304#if 0 // TODO
305// [span.objectrep], views of object representation
306template <class ElementType, ptrdiff_t Extent>
307constexpr span<const char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_bytes(span<ElementType, Extent> s) noexcept;
308
309template <class ElementType, ptrdiff_t Extent>
310constexpr span<char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_writeable_bytes(span<ElementType, Extent>) noexcept;
311#endif
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800312
313} // namespace gsl
314
315#ifdef _MSC_VER
316
317#undef constexpr
318#pragma pop_macro("constexpr")
319
320#if _MSC_VER <= 1800
321#pragma warning(pop)
322
323#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
324#undef noexcept
325#pragma pop_macro("noexcept")
326#endif // GSL_THROW_ON_CONTRACT_VIOLATION
327
328#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
329
330#endif // _MSC_VER <= 1800
331
332#endif // _MSC_VER
333
334#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
335
336#undef noexcept
337
338#ifdef _MSC_VER
339#pragma warning(pop)
340#pragma pop_macro("noexcept")
341#endif
342
343#endif // GSL_THROW_ON_CONTRACT_VIOLATION
344
345#endif // GSL_SPAN_H