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 47 namespace 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 60 template <typename CharT, std::ptrdiff_t Extent = dynamic_extent> 61 using basic_zstring = CharT*; 62 63 template <std::ptrdiff_t Extent = dynamic_extent> 64 using czstring = basic_zstring<const char, Extent>; 65 66 template <std::ptrdiff_t Extent = dynamic_extent> 67 using cwzstring = basic_zstring<const wchar_t, Extent>; 68 69 template <std::ptrdiff_t Extent = dynamic_extent> 70 using cu16zstring = basic_zstring<const char16_t, Extent>; 71 72 template <std::ptrdiff_t Extent = dynamic_extent> 73 using cu32zstring = basic_zstring<const char32_t, Extent>; 74 75 template <std::ptrdiff_t Extent = dynamic_extent> 76 using zstring = basic_zstring<char, Extent>; 77 78 template <std::ptrdiff_t Extent = dynamic_extent> 79 using wzstring = basic_zstring<wchar_t, Extent>; 80 81 template <std::ptrdiff_t Extent = dynamic_extent> 82 using u16zstring = basic_zstring<char16_t, Extent>; 83 84 template <std::ptrdiff_t Extent = dynamic_extent> 85 using u32zstring = basic_zstring<char32_t, Extent>; 86 87 namespace 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 // 111 template <typename T, const T Sentinel> 112 span<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 // 131 template <typename CharT> 132 span<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 137 template <typename CharT, std::size_t N> 138 span<CharT, dynamic_extent> ensure_z(CharT (&sz)[N]) 139 { 140 return ensure_z(&sz[0], narrow_cast<std::ptrdiff_t>(N)); 141 } 142 143 template <class Cont> 144 span<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_extent> 145 ensure_z(Cont& cont) 146 { 147 return ensure_z(cont.data(), narrow_cast<std::ptrdiff_t>(cont.size())); 148 } 149 150 template <typename CharT, std::ptrdiff_t> 151 class basic_string_span; 152 153 namespace 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 // 173 template <typename CharT, std::ptrdiff_t Extent = dynamic_extent> 174 class basic_string_span 175 { 176 public: 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 312 private: 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 327 template <std::ptrdiff_t Extent = dynamic_extent> 328 using string_span = basic_string_span<char, Extent>; 329 330 template <std::ptrdiff_t Extent = dynamic_extent> 331 using cstring_span = basic_string_span<const char, Extent>; 332 333 template <std::ptrdiff_t Extent = dynamic_extent> 334 using wstring_span = basic_string_span<wchar_t, Extent>; 335 336 template <std::ptrdiff_t Extent = dynamic_extent> 337 using cwstring_span = basic_string_span<const wchar_t, Extent>; 338 339 template <std::ptrdiff_t Extent = dynamic_extent> 340 using u16string_span = basic_string_span<char16_t, Extent>; 341 342 template <std::ptrdiff_t Extent = dynamic_extent> 343 using cu16string_span = basic_string_span<const char16_t, Extent>; 344 345 template <std::ptrdiff_t Extent = dynamic_extent> 346 using u32string_span = basic_string_span<char32_t, Extent>; 347 348 template <std::ptrdiff_t Extent = dynamic_extent> 349 using cu32string_span = basic_string_span<const char32_t, Extent>; 350 351 // 352 // to_string() allow (explicit) conversions from string_span to string 353 // 354 355 template <typename CharT, std::ptrdiff_t Extent> 356 std::basic_string<typename std::remove_const<CharT>::type> 357 to_string(basic_string_span<CharT, Extent> view) 358 { 359 return {view.data(), narrow_cast<std::size_t>(view.length())}; 360 } 361 362 template <typename CharT, typename Traits = typename std::char_traits<CharT>, 363 typename Allocator = std::allocator<CharT>, typename gCharT, std::ptrdiff_t Extent> 364 std::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 369 template <class ElementType, std::ptrdiff_t Extent> 370 basic_string_span<const byte, details::calculate_byte_size<ElementType, Extent>::value> 371 as_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 377 template <class ElementType, std::ptrdiff_t Extent, 378 class = std::enable_if_t<!std::is_const<ElementType>::value>> 379 basic_string_span<byte, details::calculate_byte_size<ElementType, Extent>::value> 380 as_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 388 template <typename CharT, std::ptrdiff_t Extent = dynamic_extent> 389 class basic_zstring_span { 390 public: 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 432 private: 433 impl_type span_; 434 }; 435 436 template <std::ptrdiff_t Max = dynamic_extent> 437 using zstring_span = basic_zstring_span<char, Max>; 438 439 template <std::ptrdiff_t Max = dynamic_extent> 440 using wzstring_span = basic_zstring_span<wchar_t, Max>; 441 442 template <std::ptrdiff_t Max = dynamic_extent> 443 using u16zstring_span = basic_zstring_span<char16_t, Max>; 444 445 template <std::ptrdiff_t Max = dynamic_extent> 446 using u32zstring_span = basic_zstring_span<char32_t, Max>; 447 448 template <std::ptrdiff_t Max = dynamic_extent> 449 using czstring_span = basic_zstring_span<const char, Max>; 450 451 template <std::ptrdiff_t Max = dynamic_extent> 452 using cwzstring_span = basic_zstring_span<const wchar_t, Max>; 453 454 template <std::ptrdiff_t Max = dynamic_extent> 455 using cu16zstring_span = basic_zstring_span<const char16_t, Max>; 456 457 template <std::ptrdiff_t Max = dynamic_extent> 458 using cu32zstring_span = basic_zstring_span<const char32_t, Max>; 459 460 // operator == 461 template <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>> 465 bool 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 471 template <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>> 475 bool 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 != 482 template <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>> 485 bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other) 486 { 487 return !(one == other); 488 } 489 490 template < 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>> 495 bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other) 496 { 497 return !(one == other); 498 } 499 500 // operator< 501 template <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>> 504 bool 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 510 template < 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>> 515 bool 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 526 template < 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>> 534 bool 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 540 template < 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>> 548 bool 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 <= 556 template <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>> 559 bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) 560 { 561 return !(other < one); 562 } 563 564 template < 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>> 569 bool 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 579 template < 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>> 587 bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) 588 { 589 return !(other < one); 590 } 591 592 template < 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>> 600 bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) 601 { 602 return !(other < one); 603 } 604 #endif 605 606 // operator> 607 template <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>> 610 bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) 611 { 612 return other < one; 613 } 614 615 template < 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>> 620 bool 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 630 template < 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>> 638 bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) 639 { 640 return other < one; 641 } 642 643 template < 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>> 651 bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) 652 { 653 return other < one; 654 } 655 #endif 656 657 // operator >= 658 template <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>> 661 bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) 662 { 663 return !(one < other); 664 } 665 666 template < 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>> 671 bool 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 681 template < 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>> 689 bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) 690 { 691 return !(one < other); 692 } 693 694 template < 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>> 702 bool 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