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