blob: c08f24672a097383178641ab49fa00bf7bea0dd2 [file] [log] [blame]
Brian Silvermana6f7ce02018-07-07 15:04:00 -07001///////////////////////////////////////////////////////////////////////////////
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#ifndef GSL_STRING_SPAN_H
18#define GSL_STRING_SPAN_H
19
20#include <gsl/gsl_assert> // for Ensures, Expects
21#include <gsl/gsl_util> // for narrow_cast
22#include <gsl/span> // for operator!=, operator==, dynamic_extent
23
24#include <algorithm> // for equal, lexicographical_compare
25#include <array> // for array
26#include <cstddef> // for ptrdiff_t, size_t, nullptr_t
27#include <cstdint> // for PTRDIFF_MAX
28#include <cstring>
29#include <string> // for basic_string, allocator, char_traits
30#include <type_traits> // for declval, is_convertible, enable_if_t, add_...
31
32#ifdef _MSC_VER
33#pragma warning(push)
34
35// blanket turn off warnings from CppCoreCheck for now
36// so people aren't annoyed by them when running the tool.
37// more targeted suppressions will be added in a future update to the GSL
38#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495)
39
40#if _MSC_VER < 1910
41#pragma push_macro("constexpr")
42#define constexpr /*constexpr*/
43
44#endif // _MSC_VER < 1910
45#endif // _MSC_VER
46
47// In order to test the library, we need it to throw exceptions that we can catch
48#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
49#define GSL_NOEXCEPT /*noexcept*/
50#else
51#define GSL_NOEXCEPT noexcept
52#endif // GSL_THROW_ON_CONTRACT_VIOLATION
53
54namespace gsl
55{
56//
57// czstring and wzstring
58//
59// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
60// that allow static analysis to help find bugs.
61//
62// There are no additional features/semantics that we can find a way to add inside the
63// type system for these types that will not either incur significant runtime costs or
64// (sometimes needlessly) break existing programs when introduced.
65//
66
67template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
68using basic_zstring = CharT*;
69
70template <std::ptrdiff_t Extent = dynamic_extent>
71using czstring = basic_zstring<const char, Extent>;
72
73template <std::ptrdiff_t Extent = dynamic_extent>
74using cwzstring = basic_zstring<const wchar_t, Extent>;
75
76template <std::ptrdiff_t Extent = dynamic_extent>
77using cu16zstring = basic_zstring<const char16_t, Extent>;
78
79template <std::ptrdiff_t Extent = dynamic_extent>
80using cu32zstring = basic_zstring<const char32_t, Extent>;
81
82template <std::ptrdiff_t Extent = dynamic_extent>
83using zstring = basic_zstring<char, Extent>;
84
85template <std::ptrdiff_t Extent = dynamic_extent>
86using wzstring = basic_zstring<wchar_t, Extent>;
87
88template <std::ptrdiff_t Extent = dynamic_extent>
89using u16zstring = basic_zstring<char16_t, Extent>;
90
91template <std::ptrdiff_t Extent = dynamic_extent>
92using u32zstring = basic_zstring<char32_t, Extent>;
93
94namespace details
95{
96 template <class CharT>
97 std::ptrdiff_t string_length(const CharT* str, std::ptrdiff_t n)
98 {
99 if (str == nullptr || n <= 0) return 0;
100
101 const span<const CharT> str_span{str, n};
102
103 std::ptrdiff_t len = 0;
104 while (len < n && str_span[len]) len++;
105
106 return len;
107 }
108}
109
110//
111// ensure_sentinel()
112//
113// Provides a way to obtain an span from a contiguous sequence
114// that ends with a (non-inclusive) sentinel value.
115//
116// Will fail-fast if sentinel cannot be found before max elements are examined.
117//
118template <typename T, const T Sentinel>
119span<T, dynamic_extent> ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX)
120{
121 auto cur = seq;
122 while ((cur - seq) < max && *cur != Sentinel) ++cur;
123 Ensures(*cur == Sentinel);
124 return {seq, cur - seq};
125}
126
127//
128// ensure_z - creates a span for a zero terminated strings.
129// Will fail fast if a null-terminator cannot be found before
130// the limit of size_type.
131//
132template <typename CharT>
133span<CharT, dynamic_extent> ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRDIFF_MAX)
134{
135 return ensure_sentinel<CharT, CharT(0)>(sz, max);
136}
137
138template <typename CharT, std::size_t N>
139span<CharT, dynamic_extent> ensure_z(CharT (&sz)[N])
140{
141 return ensure_z(&sz[0], static_cast<std::ptrdiff_t>(N));
142}
143
144template <class Cont>
145span<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_extent>
146ensure_z(Cont& cont)
147{
148 return ensure_z(cont.data(), static_cast<std::ptrdiff_t>(cont.size()));
149}
150
151template <typename CharT, std::ptrdiff_t>
152class basic_string_span;
153
154namespace details
155{
156 template <typename T>
157 struct is_basic_string_span_oracle : std::false_type
158 {
159 };
160
161 template <typename CharT, std::ptrdiff_t Extent>
162 struct is_basic_string_span_oracle<basic_string_span<CharT, Extent>> : std::true_type
163 {
164 };
165
166 template <typename T>
167 struct is_basic_string_span : is_basic_string_span_oracle<std::remove_cv_t<T>>
168 {
169 };
170}
171
172//
173// string_span and relatives
174//
175template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
176class basic_string_span
177{
178public:
179 using element_type = CharT;
180 using pointer = std::add_pointer_t<element_type>;
181 using reference = std::add_lvalue_reference_t<element_type>;
182 using const_reference = std::add_lvalue_reference_t<std::add_const_t<element_type>>;
183 using impl_type = span<element_type, Extent>;
184
185 using index_type = typename impl_type::index_type;
186 using iterator = typename impl_type::iterator;
187 using const_iterator = typename impl_type::const_iterator;
188 using reverse_iterator = typename impl_type::reverse_iterator;
189 using const_reverse_iterator = typename impl_type::const_reverse_iterator;
190
191 // default (empty)
192 constexpr basic_string_span() GSL_NOEXCEPT = default;
193
194 // copy
195 constexpr basic_string_span(const basic_string_span& other) GSL_NOEXCEPT = default;
196
197 // assign
198 constexpr basic_string_span& operator=(const basic_string_span& other) GSL_NOEXCEPT = default;
199
200 constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {}
201 constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {}
202
203 // From static arrays - if 0-terminated, remove 0 from the view
204 // All other containers allow 0s within the length, so we do not remove them
205 template <std::size_t N>
206 constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr))
207 {
208 }
209
210 template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
211 constexpr basic_string_span(std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT : span_(arr)
212 {
213 }
214
215 template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
216 constexpr basic_string_span(const std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT
217 : span_(arr)
218 {
219 }
220
221 // Container signature should work for basic_string after C++17 version exists
222 template <class Traits, class Allocator>
223 constexpr basic_string_span(std::basic_string<element_type, Traits, Allocator>& str)
224 : span_(&str[0], narrow_cast<std::ptrdiff_t>(str.length()))
225 {
226 }
227
228 template <class Traits, class Allocator>
229 constexpr basic_string_span(const std::basic_string<element_type, Traits, Allocator>& str)
230 : span_(&str[0], str.length())
231 {
232 }
233
234 // from containers. Containers must have a pointer type and data() function signatures
235 template <class Container,
236 class = std::enable_if_t<
237 !details::is_basic_string_span<Container>::value &&
238 std::is_convertible<typename Container::pointer, pointer>::value &&
239 std::is_convertible<typename Container::pointer,
240 decltype(std::declval<Container>().data())>::value>>
241 constexpr basic_string_span(Container& cont) : span_(cont)
242 {
243 }
244
245 template <class Container,
246 class = std::enable_if_t<
247 !details::is_basic_string_span<Container>::value &&
248 std::is_convertible<typename Container::pointer, pointer>::value &&
249 std::is_convertible<typename Container::pointer,
250 decltype(std::declval<Container>().data())>::value>>
251 constexpr basic_string_span(const Container& cont) : span_(cont)
252 {
253 }
254
255 // from string_span
256 template <
257 class OtherValueType, std::ptrdiff_t OtherExtent,
258 class = std::enable_if_t<std::is_convertible<
259 typename basic_string_span<OtherValueType, OtherExtent>::impl_type, impl_type>::value>>
260 constexpr basic_string_span(basic_string_span<OtherValueType, OtherExtent> other)
261 : span_(other.data(), other.length())
262 {
263 }
264
265 template <index_type Count>
266 constexpr basic_string_span<element_type, Count> first() const
267 {
268 return {span_.template first<Count>()};
269 }
270
271 constexpr basic_string_span<element_type, dynamic_extent> first(index_type count) const
272 {
273 return {span_.first(count)};
274 }
275
276 template <index_type Count>
277 constexpr basic_string_span<element_type, Count> last() const
278 {
279 return {span_.template last<Count>()};
280 }
281
282 constexpr basic_string_span<element_type, dynamic_extent> last(index_type count) const
283 {
284 return {span_.last(count)};
285 }
286
287 template <index_type Offset, index_type Count>
288 constexpr basic_string_span<element_type, Count> subspan() const
289 {
290 return {span_.template subspan<Offset, Count>()};
291 }
292
293 constexpr basic_string_span<element_type, dynamic_extent>
294 subspan(index_type offset, index_type count = dynamic_extent) const
295 {
296 return {span_.subspan(offset, count)};
297 }
298
299 constexpr reference operator[](index_type idx) const { return span_[idx]; }
300 constexpr reference operator()(index_type idx) const { return span_[idx]; }
301
302 constexpr pointer data() const { return span_.data(); }
303
304 constexpr index_type length() const GSL_NOEXCEPT { return span_.size(); }
305 constexpr index_type size() const GSL_NOEXCEPT { return span_.size(); }
306 constexpr index_type size_bytes() const GSL_NOEXCEPT { return span_.size_bytes(); }
307 constexpr index_type length_bytes() const GSL_NOEXCEPT { return span_.length_bytes(); }
308 constexpr bool empty() const GSL_NOEXCEPT { return size() == 0; }
309
310 constexpr iterator begin() const GSL_NOEXCEPT { return span_.begin(); }
311 constexpr iterator end() const GSL_NOEXCEPT { return span_.end(); }
312
313 constexpr const_iterator cbegin() const GSL_NOEXCEPT { return span_.cbegin(); }
314 constexpr const_iterator cend() const GSL_NOEXCEPT { return span_.cend(); }
315
316 constexpr reverse_iterator rbegin() const GSL_NOEXCEPT { return span_.rbegin(); }
317 constexpr reverse_iterator rend() const GSL_NOEXCEPT { return span_.rend(); }
318
319 constexpr const_reverse_iterator crbegin() const GSL_NOEXCEPT { return span_.crbegin(); }
320 constexpr const_reverse_iterator crend() const GSL_NOEXCEPT { return span_.crend(); }
321
322private:
323 static impl_type remove_z(pointer const& sz, std::ptrdiff_t max)
324 {
325 return {sz, details::string_length(sz, max)};
326 }
327
328 template <std::size_t N>
329 static impl_type remove_z(element_type (&sz)[N])
330 {
331 return remove_z(&sz[0], narrow_cast<std::ptrdiff_t>(N));
332 }
333
334 impl_type span_;
335};
336
337template <std::ptrdiff_t Extent = dynamic_extent>
338using string_span = basic_string_span<char, Extent>;
339
340template <std::ptrdiff_t Extent = dynamic_extent>
341using cstring_span = basic_string_span<const char, Extent>;
342
343template <std::ptrdiff_t Extent = dynamic_extent>
344using wstring_span = basic_string_span<wchar_t, Extent>;
345
346template <std::ptrdiff_t Extent = dynamic_extent>
347using cwstring_span = basic_string_span<const wchar_t, Extent>;
348
349template <std::ptrdiff_t Extent = dynamic_extent>
350using u16string_span = basic_string_span<char16_t, Extent>;
351
352template <std::ptrdiff_t Extent = dynamic_extent>
353using cu16string_span = basic_string_span<const char16_t, Extent>;
354
355template <std::ptrdiff_t Extent = dynamic_extent>
356using u32string_span = basic_string_span<char32_t, Extent>;
357
358template <std::ptrdiff_t Extent = dynamic_extent>
359using cu32string_span = basic_string_span<const char32_t, Extent>;
360
361//
362// to_string() allow (explicit) conversions from string_span to string
363//
364
365template <typename CharT, std::ptrdiff_t Extent>
366std::basic_string<typename std::remove_const<CharT>::type>
367to_string(basic_string_span<CharT, Extent> view)
368{
369 return {view.data(), static_cast<std::size_t>(view.length())};
370}
371
372template <typename CharT, typename Traits = typename std::char_traits<CharT>,
373 typename Allocator = std::allocator<CharT>, typename gCharT, std::ptrdiff_t Extent>
374std::basic_string<CharT, Traits, Allocator> to_basic_string(basic_string_span<gCharT, Extent> view)
375{
376 return {view.data(), static_cast<std::size_t>(view.length())};
377}
378
379template <class ElementType, std::ptrdiff_t Extent>
380basic_string_span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
381as_bytes(basic_string_span<ElementType, Extent> s) noexcept
382{
383 return { reinterpret_cast<const byte*>(s.data()), s.size_bytes() };
384}
385
386template <class ElementType, std::ptrdiff_t Extent,
387 class = std::enable_if_t<!std::is_const<ElementType>::value>>
388basic_string_span<byte, details::calculate_byte_size<ElementType, Extent>::value>
389as_writeable_bytes(basic_string_span<ElementType, Extent> s) noexcept
390{
391 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
392}
393
394// zero-terminated string span, used to convert
395// zero-terminated spans to legacy strings
396template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
397class basic_zstring_span
398{
399public:
400 using value_type = CharT;
401 using const_value_type = std::add_const_t<CharT>;
402
403 using pointer = std::add_pointer_t<value_type>;
404 using const_pointer = std::add_pointer_t<const_value_type>;
405
406 using zstring_type = basic_zstring<value_type, Extent>;
407 using const_zstring_type = basic_zstring<const_value_type, Extent>;
408
409 using impl_type = span<value_type, Extent>;
410 using string_span_type = basic_string_span<value_type, Extent>;
411
412 constexpr basic_zstring_span(impl_type s) GSL_NOEXCEPT : span_(s)
413 {
414 // expects a zero-terminated span
415 Expects(s[s.size() - 1] == '\0');
416 }
417
418 // copy
419 constexpr basic_zstring_span(const basic_zstring_span& other) = default;
420
421 // move
422 constexpr basic_zstring_span(basic_zstring_span&& other) = default;
423
424 // assign
425 constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default;
426
427 // move assign
428 constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default;
429
430 constexpr bool empty() const GSL_NOEXCEPT { return span_.size() == 0; }
431
432 constexpr string_span_type as_string_span() const GSL_NOEXCEPT
433 {
434 auto sz = span_.size();
435 return { span_.data(), sz > 1 ? sz - 1 : 0 };
436 }
437 constexpr string_span_type ensure_z() const GSL_NOEXCEPT { return gsl::ensure_z(span_); }
438
439 constexpr const_zstring_type assume_z() const GSL_NOEXCEPT { return span_.data(); }
440
441private:
442 impl_type span_;
443};
444
445template <std::ptrdiff_t Max = dynamic_extent>
446using zstring_span = basic_zstring_span<char, Max>;
447
448template <std::ptrdiff_t Max = dynamic_extent>
449using wzstring_span = basic_zstring_span<wchar_t, Max>;
450
451template <std::ptrdiff_t Max = dynamic_extent>
452using u16zstring_span = basic_zstring_span<char16_t, Max>;
453
454template <std::ptrdiff_t Max = dynamic_extent>
455using u32zstring_span = basic_zstring_span<char32_t, Max>;
456
457template <std::ptrdiff_t Max = dynamic_extent>
458using czstring_span = basic_zstring_span<const char, Max>;
459
460template <std::ptrdiff_t Max = dynamic_extent>
461using cwzstring_span = basic_zstring_span<const wchar_t, Max>;
462
463template <std::ptrdiff_t Max = dynamic_extent>
464using cu16zstring_span = basic_zstring_span<const char16_t, Max>;
465
466template <std::ptrdiff_t Max = dynamic_extent>
467using cu32zstring_span = basic_zstring_span<const char32_t, Max>;
468
469// operator ==
470template <class CharT, std::ptrdiff_t Extent, class T,
471 class = std::enable_if_t<
472 details::is_basic_string_span<T>::value ||
473 std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
474bool operator==(const gsl::basic_string_span<CharT, Extent>& one, const T& other) GSL_NOEXCEPT
475{
476 const gsl::basic_string_span<std::add_const_t<CharT>> tmp(other);
477 return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
478}
479
480template <class CharT, std::ptrdiff_t Extent, class T,
481 class = std::enable_if_t<
482 !details::is_basic_string_span<T>::value &&
483 std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
484bool operator==(const T& one, const gsl::basic_string_span<CharT, Extent>& other) GSL_NOEXCEPT
485{
486 gsl::basic_string_span<std::add_const_t<CharT>> tmp(one);
487 return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
488}
489
490// operator !=
491template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
492 typename = std::enable_if_t<std::is_convertible<
493 T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
494bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
495{
496 return !(one == other);
497}
498
499template <
500 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
501 typename = std::enable_if_t<
502 std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
503 !gsl::details::is_basic_string_span<T>::value>>
504bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
505{
506 return !(one == other);
507}
508
509// operator<
510template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
511 typename = std::enable_if_t<std::is_convertible<
512 T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
513bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
514{
515 const gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
516 return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
517}
518
519template <
520 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
521 typename = std::enable_if_t<
522 std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
523 !gsl::details::is_basic_string_span<T>::value>>
524bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
525{
526 gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
527 return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
528}
529
530#ifndef _MSC_VER
531
532// VS treats temp and const containers as convertible to basic_string_span,
533// so the cases below are already covered by the previous operators
534
535template <
536 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
537 typename DataType = typename T::value_type,
538 typename = std::enable_if_t<
539 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
540 std::is_convertible<DataType*, CharT*>::value &&
541 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
542 DataType>::value>>
543bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
544{
545 gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
546 return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
547}
548
549template <
550 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
551 typename DataType = typename T::value_type,
552 typename = std::enable_if_t<
553 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
554 std::is_convertible<DataType*, CharT*>::value &&
555 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
556 DataType>::value>>
557bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
558{
559 gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
560 return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
561}
562#endif
563
564// operator <=
565template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
566 typename = std::enable_if_t<std::is_convertible<
567 T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
568bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
569{
570 return !(other < one);
571}
572
573template <
574 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
575 typename = std::enable_if_t<
576 std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
577 !gsl::details::is_basic_string_span<T>::value>>
578bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
579{
580 return !(other < one);
581}
582
583#ifndef _MSC_VER
584
585// VS treats temp and const containers as convertible to basic_string_span,
586// so the cases below are already covered by the previous operators
587
588template <
589 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
590 typename DataType = typename T::value_type,
591 typename = std::enable_if_t<
592 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
593 std::is_convertible<DataType*, CharT*>::value &&
594 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
595 DataType>::value>>
596bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
597{
598 return !(other < one);
599}
600
601template <
602 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
603 typename DataType = typename T::value_type,
604 typename = std::enable_if_t<
605 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
606 std::is_convertible<DataType*, CharT*>::value &&
607 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
608 DataType>::value>>
609bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
610{
611 return !(other < one);
612}
613#endif
614
615// operator>
616template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
617 typename = std::enable_if_t<std::is_convertible<
618 T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
619bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
620{
621 return other < one;
622}
623
624template <
625 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
626 typename = std::enable_if_t<
627 std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
628 !gsl::details::is_basic_string_span<T>::value>>
629bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
630{
631 return other < one;
632}
633
634#ifndef _MSC_VER
635
636// VS treats temp and const containers as convertible to basic_string_span,
637// so the cases below are already covered by the previous operators
638
639template <
640 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
641 typename DataType = typename T::value_type,
642 typename = std::enable_if_t<
643 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
644 std::is_convertible<DataType*, CharT*>::value &&
645 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
646 DataType>::value>>
647bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
648{
649 return other < one;
650}
651
652template <
653 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
654 typename DataType = typename T::value_type,
655 typename = std::enable_if_t<
656 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
657 std::is_convertible<DataType*, CharT*>::value &&
658 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
659 DataType>::value>>
660bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
661{
662 return other < one;
663}
664#endif
665
666// operator >=
667template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
668 typename = std::enable_if_t<std::is_convertible<
669 T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
670bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
671{
672 return !(one < other);
673}
674
675template <
676 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
677 typename = std::enable_if_t<
678 std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
679 !gsl::details::is_basic_string_span<T>::value>>
680bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
681{
682 return !(one < other);
683}
684
685#ifndef _MSC_VER
686
687// VS treats temp and const containers as convertible to basic_string_span,
688// so the cases below are already covered by the previous operators
689
690template <
691 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
692 typename DataType = typename T::value_type,
693 typename = std::enable_if_t<
694 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
695 std::is_convertible<DataType*, CharT*>::value &&
696 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
697 DataType>::value>>
698bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
699{
700 return !(one < other);
701}
702
703template <
704 typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
705 typename DataType = typename T::value_type,
706 typename = std::enable_if_t<
707 !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
708 std::is_convertible<DataType*, CharT*>::value &&
709 std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
710 DataType>::value>>
711bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
712{
713 return !(one < other);
714}
715#endif
716} // namespace gsl
717
718#undef GSL_NOEXCEPT
719
720#ifdef _MSC_VER
721#pragma warning(pop)
722
723#if _MSC_VER < 1910
724#undef constexpr
725#pragma pop_macro("constexpr")
726
727#endif // _MSC_VER < 1910
728#endif // _MSC_VER
729
730#endif // GSL_STRING_SPAN_H