| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Copyright (c) 2015 Microsoft Corporation. All rights reserved. |
| // |
| // This code is licensed under the MIT License (MIT). |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #pragma once |
| |
| #ifndef GSL_STRING_SPAN_H |
| #define GSL_STRING_SPAN_H |
| |
| #include "gsl_assert" |
| #include "gsl_util" |
| #include "span" |
| #include <cstdint> |
| #include <cstring> |
| #include <string> |
| |
| #ifdef _MSC_VER |
| |
| // No MSVC does constexpr fully yet |
| #pragma push_macro("constexpr") |
| #define constexpr /*constexpr*/ |
| |
| #pragma warning(push) |
| |
| // blanket turn off warnings from CppCoreCheck for now |
| // so people aren't annoyed by them when running the tool. |
| // more targeted suppressions will be added in a future update to the GSL |
| #pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495) |
| |
| // VS 2013 workarounds |
| #if _MSC_VER <= 1800 |
| |
| #define GSL_MSVC_HAS_TYPE_DEDUCTION_BUG |
| #define GSL_MSVC_HAS_SFINAE_SUBSTITUTION_ICE |
| #define GSL_MSVC_NO_CPP14_STD_EQUAL |
| #define GSL_MSVC_NO_DEFAULT_MOVE_CTOR |
| |
| // noexcept is not understood |
| #ifndef GSL_THROW_ON_CONTRACT_VIOLATION |
| #pragma push_macro("noexcept") |
| #define noexcept /*noexcept*/ |
| #endif |
| |
| #endif // _MSC_VER <= 1800 |
| #endif // _MSC_VER |
| |
| // In order to test the library, we need it to throw exceptions that we can catch |
| #ifdef GSL_THROW_ON_CONTRACT_VIOLATION |
| |
| #ifdef _MSC_VER |
| #pragma push_macro("noexcept") |
| #endif |
| |
| #define noexcept /*noexcept*/ |
| |
| #endif // GSL_THROW_ON_CONTRACT_VIOLATION |
| |
| namespace gsl |
| { |
| // |
| // czstring and wzstring |
| // |
| // These are "tag" typedef's for C-style strings (i.e. null-terminated character arrays) |
| // that allow static analysis to help find bugs. |
| // |
| // There are no additional features/semantics that we can find a way to add inside the |
| // type system for these types that will not either incur significant runtime costs or |
| // (sometimes needlessly) break existing programs when introduced. |
| // |
| |
| template <typename CharT, std::ptrdiff_t Extent = dynamic_extent> |
| using basic_zstring = CharT*; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using czstring = basic_zstring<const char, Extent>; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using cwzstring = basic_zstring<const wchar_t, Extent>; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using zstring = basic_zstring<char, Extent>; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using wzstring = basic_zstring<wchar_t, Extent>; |
| |
| namespace details |
| { |
| inline std::ptrdiff_t string_length(const char *str, std::ptrdiff_t n) |
| { |
| if (str == nullptr || n <= 0) |
| return 0; |
| |
| span<const char> str_span{str, n}; |
| |
| std::ptrdiff_t len = 0; |
| while (len < n && str_span[len]) |
| len++; |
| |
| return len; |
| } |
| |
| inline std::ptrdiff_t wstring_length(const wchar_t *str, std::ptrdiff_t n) |
| { |
| if (str == nullptr || n <= 0) |
| return 0; |
| |
| span<const wchar_t> str_span{str, n}; |
| |
| std::ptrdiff_t len = 0; |
| while (len < n && str_span[len]) |
| len++; |
| |
| return len; |
| } |
| } |
| |
| // |
| // ensure_sentinel() |
| // |
| // Provides a way to obtain an span from a contiguous sequence |
| // that ends with a (non-inclusive) sentinel value. |
| // |
| // Will fail-fast if sentinel cannot be found before max elements are examined. |
| // |
| template <typename T, const T Sentinel> |
| span<T, dynamic_extent> ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX) |
| { |
| auto cur = seq; |
| while ((cur - seq) < max && *cur != Sentinel) ++cur; |
| Ensures(*cur == Sentinel); |
| return {seq, cur - seq}; |
| } |
| |
| // |
| // ensure_z - creates a span for a czstring or cwzstring. |
| // Will fail fast if a null-terminator cannot be found before |
| // the limit of size_type. |
| // |
| template <typename T> |
| inline span<T, dynamic_extent> ensure_z(T* const& sz, std::ptrdiff_t max = PTRDIFF_MAX) |
| { |
| return ensure_sentinel<T, 0>(sz, max); |
| } |
| |
| // TODO (neilmac) there is probably a better template-magic way to get the const and non-const |
| // overloads to share an implementation |
| inline span<char, dynamic_extent> ensure_z(char* const& sz, std::ptrdiff_t max) |
| { |
| auto len = details::string_length(sz, max); |
| Ensures(sz[len] == 0); |
| return {sz, len}; |
| } |
| |
| inline span<const char, dynamic_extent> ensure_z(const char* const& sz, std::ptrdiff_t max) |
| { |
| auto len = details::string_length(sz, max); |
| Ensures(sz[len] == 0); |
| return {sz, len}; |
| } |
| |
| inline span<wchar_t, dynamic_extent> ensure_z(wchar_t* const& sz, std::ptrdiff_t max) |
| { |
| auto len = details::wstring_length(sz, max); |
| Ensures(sz[len] == 0); |
| return {sz, len}; |
| } |
| |
| inline span<const wchar_t, dynamic_extent> ensure_z(const wchar_t* const& sz, std::ptrdiff_t max) |
| { |
| auto len = details::wstring_length(sz, max); |
| Ensures(sz[len] == 0); |
| return {sz, len}; |
| } |
| |
| template <typename T, size_t N> |
| span<T, dynamic_extent> ensure_z(T (&sz)[N]) |
| { |
| return ensure_z(&sz[0], static_cast<std::ptrdiff_t>(N)); |
| } |
| |
| template <class Cont> |
| span<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_extent> |
| ensure_z(Cont& cont) |
| { |
| return ensure_z(cont.data(), static_cast<std::ptrdiff_t>(cont.length())); |
| } |
| |
| template <typename CharT, std::ptrdiff_t> |
| class basic_string_span; |
| |
| namespace details |
| { |
| template <typename T> |
| struct is_basic_string_span_oracle : std::false_type |
| { |
| }; |
| |
| template <typename CharT, std::ptrdiff_t Extent> |
| struct is_basic_string_span_oracle<basic_string_span<CharT, Extent>> : std::true_type |
| { |
| }; |
| |
| template <typename T> |
| struct is_basic_string_span : is_basic_string_span_oracle<std::remove_cv_t<T>> |
| { |
| }; |
| |
| template <typename T> |
| struct length_func |
| { |
| }; |
| |
| template <> |
| struct length_func<char> |
| { |
| std::ptrdiff_t operator()(char* const ptr, std::ptrdiff_t length) noexcept |
| { |
| return details::string_length(ptr, length); |
| } |
| }; |
| |
| template <> |
| struct length_func<wchar_t> |
| { |
| std::ptrdiff_t operator()(wchar_t* const ptr, std::ptrdiff_t length) noexcept |
| { |
| return details::wstring_length(ptr, length); |
| } |
| }; |
| |
| template <> |
| struct length_func<const char> |
| { |
| std::ptrdiff_t operator()(const char* const ptr, std::ptrdiff_t length) noexcept |
| { |
| return details::string_length(ptr, length); |
| } |
| }; |
| |
| template <> |
| struct length_func<const wchar_t> |
| { |
| std::ptrdiff_t operator()(const wchar_t* const ptr, std::ptrdiff_t length) noexcept |
| { |
| return details::wstring_length(ptr, length); |
| } |
| }; |
| } |
| |
| // |
| // string_span and relatives |
| // |
| template <typename CharT, std::ptrdiff_t Extent = dynamic_extent> |
| class basic_string_span |
| { |
| public: |
| using element_type = CharT; |
| using pointer = std::add_pointer_t<element_type>; |
| using reference = std::add_lvalue_reference_t<element_type>; |
| using const_reference = std::add_lvalue_reference_t<std::add_const_t<element_type>>; |
| using impl_type = span<element_type, Extent>; |
| |
| using index_type = typename impl_type::index_type; |
| using iterator = typename impl_type::iterator; |
| using const_iterator = typename impl_type::const_iterator; |
| using reverse_iterator = typename impl_type::reverse_iterator; |
| using const_reverse_iterator = typename impl_type::const_reverse_iterator; |
| |
| // default (empty) |
| constexpr basic_string_span() noexcept = default; |
| |
| // copy |
| constexpr basic_string_span(const basic_string_span& other) noexcept = default; |
| |
| // move |
| #ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR |
| constexpr basic_string_span(basic_string_span&& other) noexcept = default; |
| #else |
| constexpr basic_string_span(basic_string_span&& other) : span_(std::move(other.span_)) {} |
| #endif |
| |
| // assign |
| constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; |
| |
| // move assign |
| #ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR |
| constexpr basic_string_span& operator=(basic_string_span&& other) noexcept = default; |
| #else |
| constexpr basic_string_span& operator=(basic_string_span&& other) noexcept |
| { |
| span_ = std::move(other.span_); |
| return *this; |
| } |
| #endif |
| |
| // from nullptr |
| constexpr basic_string_span(std::nullptr_t ptr) noexcept : span_(ptr) {} |
| |
| constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {} |
| constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} |
| |
| // From static arrays - if 0-terminated, remove 0 from the view |
| // All other containers allow 0s within the length, so we do not remove them |
| template <size_t N> |
| constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr)) |
| { |
| } |
| |
| template <size_t N, class ArrayElementType = std::remove_const_t<element_type>> |
| constexpr basic_string_span(std::array<ArrayElementType, N>& arr) noexcept : span_(arr) |
| { |
| } |
| |
| template <size_t N, class ArrayElementType = std::remove_const_t<element_type>> |
| constexpr basic_string_span(const std::array<ArrayElementType, N>& arr) noexcept : span_(arr) |
| { |
| } |
| |
| // Container signature should work for basic_string after C++17 version exists |
| template <class Traits, class Allocator> |
| constexpr basic_string_span(std::basic_string<element_type, Traits, Allocator>& str) |
| : span_(&str[0], str.length()) |
| { |
| } |
| |
| template <class Traits, class Allocator> |
| constexpr basic_string_span(const std::basic_string<element_type, Traits, Allocator>& str) |
| : span_(&str[0], str.length()) |
| { |
| } |
| |
| // from containers. Containers must have a pointer type and data() function signatures |
| template <class Container, |
| class = std::enable_if_t< |
| !details::is_basic_string_span<Container>::value && |
| std::is_convertible<typename Container::pointer, pointer>::value && |
| std::is_convertible<typename Container::pointer, |
| decltype(std::declval<Container>().data())>::value>> |
| constexpr basic_string_span(Container& cont) : span_(cont) |
| { |
| } |
| |
| template <class Container, |
| class = std::enable_if_t< |
| !details::is_basic_string_span<Container>::value && |
| std::is_convertible<typename Container::pointer, pointer>::value && |
| std::is_convertible<typename Container::pointer, |
| decltype(std::declval<Container>().data())>::value>> |
| constexpr basic_string_span(const Container& cont) : span_(cont) |
| { |
| } |
| |
| // from string_span |
| template < |
| class OtherValueType, std::ptrdiff_t OtherExtent, |
| class = std::enable_if_t<std::is_convertible< |
| typename basic_string_span<OtherValueType, OtherExtent>::impl_type, impl_type>::value>> |
| constexpr basic_string_span(basic_string_span<OtherValueType, OtherExtent> other) |
| : span_(other.data(), other.length()) |
| { |
| } |
| |
| template <index_type Count> |
| constexpr basic_string_span<element_type, Count> first() const |
| { |
| return {span_.template first<Count>()}; |
| } |
| |
| constexpr basic_string_span<element_type, dynamic_extent> first(index_type count) const |
| { |
| return {span_.first(count)}; |
| } |
| |
| template <index_type Count> |
| constexpr basic_string_span<element_type, Count> last() const |
| { |
| return {span_.template last<Count>()}; |
| } |
| |
| constexpr basic_string_span<element_type, dynamic_extent> last(index_type count) const |
| { |
| return {span_.last(count)}; |
| } |
| |
| template <index_type Offset, index_type Count> |
| constexpr basic_string_span<element_type, Count> subspan() const |
| { |
| return {span_.template subspan<Offset, Count>()}; |
| } |
| |
| constexpr basic_string_span<element_type, dynamic_extent> |
| subspan(index_type offset, index_type count = dynamic_extent) const |
| { |
| return {span_.subspan(offset, count)}; |
| } |
| |
| constexpr reference operator[](index_type idx) const { return span_[idx]; } |
| constexpr reference operator()(index_type idx) const { return span_[idx]; } |
| |
| constexpr pointer data() const { return span_.data(); } |
| |
| constexpr index_type length() const noexcept { return span_.size(); } |
| constexpr index_type size() const noexcept { return span_.size(); } |
| constexpr index_type size_bytes() const noexcept { return span_.size_bytes(); } |
| constexpr index_type length_bytes() const noexcept { return span_.length_bytes(); } |
| constexpr bool empty() const noexcept { return size() == 0; } |
| |
| constexpr iterator begin() const noexcept { return span_.begin(); } |
| constexpr iterator end() const noexcept { return span_.end(); } |
| |
| constexpr const_iterator cbegin() const noexcept { return span_.cbegin(); } |
| constexpr const_iterator cend() const noexcept { return span_.cend(); } |
| |
| constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); } |
| constexpr reverse_iterator rend() const noexcept { return span_.rend(); } |
| |
| constexpr const_reverse_iterator crbegin() const noexcept { return span_.crbegin(); } |
| constexpr const_reverse_iterator crend() const noexcept { return span_.crend(); } |
| |
| private: |
| static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) |
| { |
| return {sz, details::length_func<element_type>()(sz, max)}; |
| } |
| |
| template <size_t N> |
| static impl_type remove_z(element_type (&sz)[N]) |
| { |
| return remove_z(&sz[0], narrow_cast<std::ptrdiff_t>(N)); |
| } |
| |
| impl_type span_; |
| }; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using string_span = basic_string_span<char, Extent>; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using cstring_span = basic_string_span<const char, Extent>; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using wstring_span = basic_string_span<wchar_t, Extent>; |
| |
| template <std::ptrdiff_t Extent = dynamic_extent> |
| using cwstring_span = basic_string_span<const wchar_t, Extent>; |
| |
| // |
| // to_string() allow (explicit) conversions from string_span to string |
| // |
| #ifndef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG |
| |
| template <typename CharT, std::ptrdiff_t Extent> |
| std::basic_string<typename std::remove_const<CharT>::type> |
| to_string(basic_string_span<CharT, Extent> view) |
| { |
| return {view.data(), static_cast<size_t>(view.length())}; |
| } |
| |
| #else |
| |
| inline std::string to_string(cstring_span<> view) |
| { |
| return {view.data(), static_cast<size_t>(view.length())}; |
| } |
| |
| inline std::string to_string(string_span<> view) |
| { |
| return {view.data(), static_cast<size_t>(view.length())}; |
| } |
| |
| inline std::wstring to_string(cwstring_span<> view) |
| { |
| return {view.data(), static_cast<size_t>(view.length())}; |
| } |
| |
| inline std::wstring to_string(wstring_span<> view) |
| { |
| return {view.data(), static_cast<size_t>(view.length())}; |
| } |
| |
| #endif |
| |
| template <typename CharT, |
| typename Traits = typename std::char_traits<CharT>, |
| typename Allocator = std::allocator<CharT>, |
| typename gCharT, |
| std::ptrdiff_t Extent> |
| std::basic_string<CharT, Traits, Allocator> to_basic_string(basic_string_span<gCharT, Extent> view) |
| { |
| return {view.data(), static_cast<size_t>(view.length())}; |
| } |
| |
| // zero-terminated string span, used to convert |
| // zero-terminated spans to legacy strings |
| template <typename CharT, std::ptrdiff_t Extent = dynamic_extent> |
| class basic_zstring_span |
| { |
| public: |
| using value_type = CharT; |
| using const_value_type = std::add_const_t<CharT>; |
| |
| using pointer = std::add_pointer_t<value_type>; |
| using const_pointer = std::add_pointer_t<const_value_type>; |
| |
| using zstring_type = basic_zstring<value_type, Extent>; |
| using const_zstring_type = basic_zstring<const_value_type, Extent>; |
| |
| using impl_type = span<value_type, Extent>; |
| using string_span_type = basic_string_span<value_type, Extent>; |
| |
| constexpr basic_zstring_span(impl_type s) noexcept : span_(s) |
| { |
| // expects a zero-terminated span |
| Expects(s[s.size() - 1] == '\0'); |
| } |
| |
| // copy |
| constexpr basic_zstring_span(const basic_zstring_span& other) = default; |
| |
| // move |
| #ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR |
| constexpr basic_zstring_span(basic_zstring_span&& other) = default; |
| #else |
| constexpr basic_zstring_span(basic_zstring_span&& other) : span_(std::move(other.span_)) {} |
| #endif |
| |
| // assign |
| constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default; |
| |
| // move assign |
| #ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR |
| constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default; |
| #else |
| constexpr basic_zstring_span& operator=(basic_zstring_span&& other) |
| { |
| span_ = std::move(other.span_); |
| return *this; |
| } |
| #endif |
| |
| constexpr bool empty() const noexcept { return span_.size() == 0; } |
| |
| constexpr string_span_type as_string_span() const noexcept |
| { |
| auto sz = span_.size(); |
| return span_.first(sz <= 0 ? 0 : sz - 1); |
| } |
| |
| constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(span_); } |
| |
| constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } |
| |
| private: |
| impl_type span_; |
| }; |
| |
| template <std::ptrdiff_t Max = dynamic_extent> |
| using zstring_span = basic_zstring_span<char, Max>; |
| |
| template <std::ptrdiff_t Max = dynamic_extent> |
| using wzstring_span = basic_zstring_span<wchar_t, Max>; |
| |
| template <std::ptrdiff_t Max = dynamic_extent> |
| using czstring_span = basic_zstring_span<const char, Max>; |
| |
| template <std::ptrdiff_t Max = dynamic_extent> |
| using cwzstring_span = basic_zstring_span<const wchar_t, Max>; |
| |
| // operator == |
| template <class CharT, std::ptrdiff_t Extent, class T, |
| class = std::enable_if_t< |
| details::is_basic_string_span<T>::value || |
| std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>> |
| bool operator==(const gsl::basic_string_span<CharT, Extent>& one, const T& other) noexcept |
| { |
| gsl::basic_string_span<std::add_const_t<CharT>> tmp(other); |
| #ifdef GSL_MSVC_NO_CPP14_STD_EQUAL |
| return (one.size() == tmp.size()) && std::equal(one.begin(), one.end(), tmp.begin()); |
| #else |
| return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); |
| #endif |
| } |
| |
| template <class CharT, std::ptrdiff_t Extent, class T, |
| class = std::enable_if_t< |
| !details::is_basic_string_span<T>::value && |
| std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>> |
| bool operator==(const T& one, const gsl::basic_string_span<CharT, Extent>& other) noexcept |
| { |
| gsl::basic_string_span<std::add_const_t<CharT>> tmp(one); |
| #ifdef GSL_MSVC_NO_CPP14_STD_EQUAL |
| return (tmp.size() == other.size()) && std::equal(tmp.begin(), tmp.end(), other.begin()); |
| #else |
| return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end()); |
| #endif |
| } |
| |
| // operator != |
| template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename = std::enable_if_t<std::is_convertible< |
| T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>> |
| bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| return !(one == other); |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename Dummy = std::enable_if_t< |
| std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value && |
| !gsl::details::is_basic_string_span<T>::value>> |
| bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| return !(one == other); |
| } |
| |
| // operator< |
| template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename = std::enable_if_t<std::is_convertible< |
| T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>> |
| bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other); |
| return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename Dummy = std::enable_if_t< |
| std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value && |
| !gsl::details::is_basic_string_span<T>::value>> |
| bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one); |
| return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); |
| } |
| |
| #ifndef _MSC_VER |
| |
| // VS treats temp and const containers as convertible to basic_string_span, |
| // so the cases below are already covered by the previous operators |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other); |
| return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one); |
| return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); |
| } |
| #endif |
| |
| // operator <= |
| template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename = std::enable_if_t<std::is_convertible< |
| T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>> |
| bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| return !(other < one); |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename Dummy = std::enable_if_t< |
| std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value && |
| !gsl::details::is_basic_string_span<T>::value>> |
| bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| return !(other < one); |
| } |
| |
| #ifndef _MSC_VER |
| |
| // VS treats temp and const containers as convertible to basic_string_span, |
| // so the cases below are already covered by the previous operators |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| return !(other < one); |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| return !(other < one); |
| } |
| #endif |
| |
| // operator> |
| template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename = std::enable_if_t<std::is_convertible< |
| T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>> |
| bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| return other < one; |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename Dummy = std::enable_if_t< |
| std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value && |
| !gsl::details::is_basic_string_span<T>::value>> |
| bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| return other < one; |
| } |
| |
| #ifndef _MSC_VER |
| |
| // VS treats temp and const containers as convertible to basic_string_span, |
| // so the cases below are already covered by the previous operators |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| return other < one; |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| return other < one; |
| } |
| #endif |
| |
| // operator >= |
| template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename = std::enable_if_t<std::is_convertible< |
| T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>> |
| bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| return !(one < other); |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename Dummy = std::enable_if_t< |
| std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value && |
| !gsl::details::is_basic_string_span<T>::value>> |
| bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| return !(one < other); |
| } |
| |
| #ifndef _MSC_VER |
| |
| // VS treats temp and const containers as convertible to basic_string_span, |
| // so the cases below are already covered by the previous operators |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept |
| { |
| return !(one < other); |
| } |
| |
| template < |
| typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, |
| typename DataType = typename T::value_type, |
| typename Dummy = std::enable_if_t< |
| !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value && |
| std::is_convertible<DataType*, CharT*>::value && |
| std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, |
| DataType>::value>> |
| bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept |
| { |
| return !(one < other); |
| } |
| #endif |
| } // namespace GSL |
| |
| #ifdef _MSC_VER |
| |
| #pragma warning(pop) |
| |
| #undef constexpr |
| #pragma pop_macro("constexpr") |
| |
| // VS 2013 workarounds |
| #if _MSC_VER <= 1800 |
| |
| #ifndef GSL_THROW_ON_CONTRACT_VIOLATION |
| #undef noexcept |
| #pragma pop_macro("noexcept") |
| #endif // GSL_THROW_ON_CONTRACT_VIOLATION |
| |
| #undef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG |
| #undef GSL_MSVC_HAS_SFINAE_SUBSTITUTION_ICE |
| #undef GSL_MSVC_NO_CPP14_STD_EQUAL |
| #undef GSL_MSVC_NO_DEFAULT_MOVE_CTOR |
| |
| #endif // _MSC_VER <= 1800 |
| #endif // _MSC_VER |
| |
| #if defined(GSL_THROW_ON_CONTRACT_VIOLATION) |
| |
| #undef noexcept |
| |
| #ifdef _MSC_VER |
| #pragma pop_macro("noexcept") |
| #endif |
| |
| #endif // GSL_THROW_ON_CONTRACT_VIOLATION |
| #endif // GSL_STRING_SPAN_H |