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