blob: 2d958990338169c6e79ae179a82d1c61935d59ea [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 MacIntoshd3929c52016-02-24 16:11:33 -080075// [views.constants], constants
76constexpr const std::ptrdiff_t dynamic_extent = -1;
77
78
79// [span], class template span
80template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
81class span {
82public:
83 // constants and types
84 using element_type = ElementType;
85 using index_type = std::ptrdiff_t;
86 using pointer = element_type*;
87 using reference = element_type&;
88#if 0 // TODO
89 using iterator = /*implementation-defined */;
90 using const_iterator = /* implementation-defined */;
91 using reverse_iterator = std::reverse_iterator<iterator>;
92 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
93#endif
94 constexpr static const index_type extent = Extent;
95
96 // [span.cons], span constructors, copy, assignment, and destructor
Neil MacIntosh502cd662016-02-28 00:50:53 -080097 constexpr span() noexcept : storage_(nullptr, extent_type<0>())
98 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -080099
100 constexpr span(nullptr_t) noexcept : span()
101 {}
102
Neil MacIntosh502cd662016-02-28 00:50:53 -0800103 constexpr span(pointer ptr, index_type count) : storage_(ptr, count)
104 { Expects(((!ptr && count == 0) || (ptr && count >= 0))); }
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800105
Neil MacIntosh502cd662016-02-28 00:50:53 -0800106 constexpr span(pointer firstElem, pointer lastElem)
107 : storage_(firstElem, std::distance(firstElem, lastElem))
108 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800109
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800110 template <size_t N>
Neil MacIntoshf61a9bb2016-02-29 13:16:48 -0800111 constexpr span(element_type(&arr)[N])
112 : storage_(&arr[0], extent_type<N>())
113 {}
114
115 template <size_t N>
116 constexpr span(std::array<std::remove_const_t<element_type>, N>& arr)
117 : storage_(&arr[0], extent_type<N>())
118 {}
119
120 template <size_t N>
121 constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr)
122 : storage_(&arr[0], extent_type<N>())
Neil MacIntosh502cd662016-02-28 00:50:53 -0800123 {}
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800124
125#if 0 // TODO
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800126 template <class Container>
127 constexpr span(Container& cont);
128 template <class Container>
129 span(const Container&&) = delete;
130 constexpr span(const span& other) noexcept = default;
131 constexpr span(span&& other) noexcept = default;
132 template <class OtherElementType, ptrdiff_t OtherExtent>
133 constexpr span(const span<OtherElementType, OtherExtent>& other);
134 template <class OtherElementType, ptrdiff_t OtherExtent>
135 constexpr span(span<OtherElementType, OtherExtent>&& other);
136 ~span() noexcept = default;
137 constexpr span& operator=(const span& other) noexcept = default;
138 constexpr span& operator=(span&& other) noexcept = default;
139
140 // [span.sub], span subviews
141 template <ptrdiff_t Count>
142 constexpr span<element_type, Count> first() const;
143 template <ptrdiff_t Count>
144 constexpr span<element_type, Count> last() const;
145 template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent>
146 constexpr span<element_type, Count> subspan() const;
147 constexpr span<element_type, dynamic_extent> first(index_type count) const;
148 constexpr span<element_type, dynamic_extent> last(index_type count) const;
149 constexpr span<element_type, dynamic_extent> subspan(index_type offset, index_type count = dynamic_extent) const;
150#endif
151 // [span.obs], span observers
152 constexpr index_type length() const noexcept { return size(); }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800153 constexpr index_type size() const noexcept { return storage_.size(); }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800154 constexpr index_type length_bytes() const noexcept { return size_bytes(); }
155 constexpr index_type size_bytes() const noexcept { return size() * sizeof(element_type); }
156 constexpr bool empty() const noexcept { return size() == 0; }
157
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800158 // [span.elem], span element access
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800159 constexpr reference operator[](index_type idx) const
160 {
Neil MacIntosh502cd662016-02-28 00:50:53 -0800161 Expects(idx >= 0 && idx < storage_.size());
162 return storage_.data()[idx];
Neil MacIntoshcc22f2b2016-02-25 11:42:26 -0800163 }
164 constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
Neil MacIntosh502cd662016-02-28 00:50:53 -0800165 constexpr pointer data() const noexcept { return storage_.data(); }
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800166#if 0 // TODO
167 // [span.iter], span iterator support
168 iterator begin() const noexcept;
169 iterator end() const noexcept;
170
171 const_iterator cbegin() const noexcept;
172 const_iterator cend() const noexcept;
173
174 reverse_iterator rbegin() const noexcept;
175 reverse_iterator rend() const noexcept;
176
177 const_reverse_iterator crbegin() const noexcept;
178 const_reverse_iterator crend() const noexcept;
179#endif
180private:
Neil MacIntosh502cd662016-02-28 00:50:53 -0800181 template <index_type Extent>
182 class extent_type;
183
184 template <index_type Extent>
185 class extent_type
186 {
187 public:
188 static_assert(Extent >= 0, "A fixed-size span must be >= 0 in size.");
189
190 constexpr extent_type() noexcept {}
191
192 template <index_type Other>
193 constexpr extent_type(extent_type<Other>) noexcept
194 {
195 static_assert(Other == Extent,
196 "Mismatch between fixed-size extent and size of initializing data.");
197 }
198
199 constexpr extent_type(index_type size)
200 { Expects(size == Extent); }
201
202 constexpr inline index_type size() const noexcept { return Extent; }
203 };
204
205 template <>
206 class extent_type<dynamic_extent>
207 {
208 public:
209 template <index_type Other>
210 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
211 {}
212
213 explicit constexpr extent_type(index_type size) : size_(size)
214 { Expects(size >= 0); }
215
216 constexpr inline index_type size() const noexcept
217 { return size_; }
218
219 private:
220 index_type size_;
221 };
222
223 // this implementation detail class lets us take advantage of the
224 // empty base class optimization to pay for only storage of a single
225 // pointer in the case of fixed-size spans
226 template <class ExtentType>
227 class storage_type : public ExtentType
228 {
229 public:
230 template <class OtherExtentType>
231 storage_type(pointer data, OtherExtentType ext)
232 : ExtentType(ext), data_(data) {}
233
234 //storage_type(pointer data, ExtentType ext)
235 // : ExtentType(ext), data_(data) {}
236
237 constexpr inline pointer data() const noexcept
238 { return data_; }
239
240 private:
241 pointer data_;
242 };
243
244 storage_type<extent_type<Extent>> storage_;
Neil MacIntoshd3929c52016-02-24 16:11:33 -0800245};
246
247
248#if 0 // TODO
249// [span.comparison], span comparison operators
250template <class ElementType, ptrdiff_t Extent>
251constexpr bool operator==(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
252
253template <class ElementType, ptrdiff_t Extent>
254constexpr bool operator!=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
255
256template <class ElementType, ptrdiff_t Extent>
257constexpr bool operator<(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
258
259template <class ElementType, ptrdiff_t Extent>
260constexpr bool operator<=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
261
262template <class ElementType, ptrdiff_t Extent>
263constexpr bool operator>(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
264
265template <class ElementType, ptrdiff_t Extent>
266constexpr bool operator>=(const span<ElementType, Extent>& l, const span<ElementType, Extent>& r) const noexcept;
267#endif
268
269
270#if 0 // TODO
271// [span.objectrep], views of object representation
272template <class ElementType, ptrdiff_t Extent>
273constexpr span<const char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_bytes(span<ElementType, Extent> s) noexcept;
274
275template <class ElementType, ptrdiff_t Extent>
276constexpr span<char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_writeable_bytes(span<ElementType, Extent>) noexcept;
277#endif
Neil MacIntoshcec26a22016-02-24 11:26:28 -0800278
279} // namespace gsl
280
281#ifdef _MSC_VER
282
283#undef constexpr
284#pragma pop_macro("constexpr")
285
286#if _MSC_VER <= 1800
287#pragma warning(pop)
288
289#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
290#undef noexcept
291#pragma pop_macro("noexcept")
292#endif // GSL_THROW_ON_CONTRACT_VIOLATION
293
294#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
295
296#endif // _MSC_VER <= 1800
297
298#endif // _MSC_VER
299
300#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
301
302#undef noexcept
303
304#ifdef _MSC_VER
305#pragma warning(pop)
306#pragma pop_macro("noexcept")
307#endif
308
309#endif // GSL_THROW_ON_CONTRACT_VIOLATION
310
311#endif // GSL_SPAN_H