diff --git a/include/string_span.h b/include/string_span.h index b681a5c..b6dce6b 100644 --- a/include/string_span.h +++ b/include/string_span.h @@ -20,6 +20,7 @@ #define GSL_STRING_SPAN_H #include "gsl_assert.h" +#include "gsl_util.h" #include "span.h" #include @@ -32,12 +33,12 @@ // VS 2013 workarounds #if _MSC_VER <= 1800 -#define GSL_MSVC_HAS_TYPE_DEDUCTION_BUG +#define GSL_MSVC_HAS_TYPE_DEDUCTION_BUG -// noexcept is not understood +// noexcept is not understood #ifndef GSL_THROW_ON_CONTRACT_VIOLATION #pragma push_macro("noexcept") -#define noexcept /* nothing */ +#define noexcept /* nothing */ #endif #endif // _MSC_VER <= 1800 @@ -50,16 +51,16 @@ #pragma push_macro("noexcept") #endif -#define noexcept /* nothing */ +#define noexcept /* nothing */ -#endif // GSL_THROW_ON_CONTRACT_VIOLATION +#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) +// 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 @@ -79,7 +80,7 @@ template using wzstring = wchar_t*; // -// ensure_sentinel() +// ensure_sentinel() // // Provides a way to obtain an span from a contiguous sequence // that ends with a (non-inclusive) sentinel value. @@ -97,7 +98,7 @@ span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX) // -// ensure_z - creates a string_span for a czstring or cwzstring. +// 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. // @@ -118,19 +119,22 @@ inline span ensure_z(char* const& sz, std::ptrdiff_t max) inline span ensure_z(const char* const& sz, std::ptrdiff_t max) { auto len = strnlen(sz, max); - Ensures(sz[len] == 0); return{ sz, static_cast(len) }; + Ensures(sz[len] == 0); + return{ sz, static_cast(len) }; } inline span ensure_z(wchar_t* const& sz, std::ptrdiff_t max) { auto len = wcsnlen(sz, max); - Ensures(sz[len] == 0); return{ sz, static_cast(len) }; + Ensures(sz[len] == 0); + return{ sz, static_cast(len) }; } inline span ensure_z(const wchar_t* const& sz, std::ptrdiff_t max) { auto len = wcsnlen(sz, max); - Ensures(sz[len] == 0); return{ sz, static_cast(len) }; + Ensures(sz[len] == 0); + return{ sz, static_cast(len) }; } template @@ -142,45 +146,7 @@ span::type, dynamic_range> return ensure_z(cont.data(), static_cast(cont.length())); } - -// TODO (neilmac) there is probably a better template-magic way to get the const and non-const overloads to share an implementation -inline span remove_z(char* const& sz, std::ptrdiff_t max) -{ - auto len = strnlen(sz, max); - return{ sz, static_cast(len) }; -} - -inline span remove_z(const char* const& sz, std::ptrdiff_t max) -{ - auto len = strnlen(sz, max); - return{ sz, static_cast(len) }; -} - -inline span remove_z(wchar_t* const& sz, std::ptrdiff_t max) -{ - auto len = wcsnlen(sz, max); - return{ sz, static_cast(len) }; -} - -inline span remove_z(const wchar_t* const& sz, std::ptrdiff_t max) -{ - auto len = wcsnlen(sz, max); - return{ sz, static_cast(len) }; -} - -template -span remove_z(T(&sz)[N]) -{ - return remove_z(&sz[0], static_cast(N)); -} - -template -span::type, dynamic_range> remove_z(Cont& cont) -{ - return remove_z(cont.data(), static_cast(cont.length())); -} - -template +template class basic_string_span; namespace details @@ -189,15 +155,56 @@ namespace details struct is_basic_string_span_oracle : std::false_type {}; - template - struct is_basic_string_span_oracle> : std::true_type + template + struct is_basic_string_span_oracle> : std::true_type {}; template struct is_basic_string_span : is_basic_string_span_oracle> {}; + + template + struct length_func + {}; + + template <> + struct length_func + { + std::ptrdiff_t operator()(char* const ptr, std::ptrdiff_t length) noexcept + { + return narrow_cast(strnlen(ptr, length)); + } + }; + + template <> + struct length_func + { + std::ptrdiff_t operator()(wchar_t* const ptr, std::ptrdiff_t length) noexcept + { + return narrow_cast(wcsnlen(ptr, length)); + } + }; + + template <> + struct length_func + { + std::ptrdiff_t operator()(const char* const ptr, std::ptrdiff_t length) noexcept + { + return narrow_cast(strnlen(ptr, length)); + } + }; + + template <> + struct length_func + { + std::ptrdiff_t operator()(const wchar_t* const ptr, std::ptrdiff_t length) noexcept + { + return narrow_cast(wcsnlen(ptr, length)); + } + }; } + // // string_span and relatives // @@ -212,85 +219,83 @@ class basic_string_span using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t; using bounds_type = static_bounds; - using underlying_type = span; + using impl_type = span; public: using size_type = ptrdiff_t; - using iterator = typename underlying_type::iterator; - using const_iterator = typename underlying_type::const_iterator; - using reverse_iterator = typename underlying_type::reverse_iterator; - using const_reverse_iterator = typename underlying_type::const_reverse_iterator; + 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; - // empty - constexpr basic_string_span() noexcept - : real(nullptr) - {} + // default (empty) + constexpr basic_string_span() = default; // copy - constexpr basic_string_span(const basic_string_span& other) noexcept - : real(other.real) - {} + constexpr basic_string_span(const basic_string_span& other) = default; // move - constexpr basic_string_span(const basic_string_span&& other) noexcept - : real(std::move(other.real)) - {} + constexpr basic_string_span(basic_string_span&& other) = default; + + // assign + constexpr basic_string_span& operator=(const basic_string_span& other) = default; + + // move assign + constexpr basic_string_span& operator=(basic_string_span&& other) = default; // from nullptr and length constexpr basic_string_span(std::nullptr_t ptr, size_type length) noexcept - : real(ptr, length) + : span_(ptr, length) {} // For pointers and static arrays - if 0-terminated, remove 0 from the view - // from c string - - constexpr basic_string_span(pointer& ptr) noexcept - : real(ensure_z(ptr)) - {} - - // from non-const pointer to const span - template, bool Enabled = std::is_const::value, typename Dummy = std::enable_if_t> - constexpr basic_string_span(ValueType*& ptr) noexcept - : real(ensure_z(ptr)) - {} - - // from raw data and length - remove 0 if needed + // from raw data and length constexpr basic_string_span(pointer ptr, size_type length) noexcept - : real(remove_z(ptr, length)) + : span_(remove_z(ptr, length)) {} // from static arrays and string literals template constexpr basic_string_span(value_type(&arr)[N]) noexcept - : real(remove_z(arr)) + : span_(remove_z(arr)) {} - // Those allow 0s in the middle, so we keep them + // Those allow 0s within the length, so we do not remove them + // from string constexpr basic_string_span(std::string& s) noexcept - : real(&(s.at(0)), static_cast(s.length())) + : span_(&(s.at(0)), narrow_cast(s.length())) {} - // from containers. It must have .size() and .data() function signatures + // from containers. Containers must have .size() and .data() function signatures template ::value - && !details::is_basic_string_span::value + && !details::is_basic_string_span::value && !(!std::is_const::value && std::is_const::value) // no converting const containers to non-const span && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value> > constexpr basic_string_span(Cont& cont) - : real(cont.data(), cont.size()) + : span_(cont.data(), cont.size()) {} + // disallow creation from temporary containers and strings + template ::value + && !details::is_basic_string_span::value + && std::is_convertible::value + && std::is_same().size(), *std::declval().data())>, DataType>::value> + > + basic_string_span(Cont&& cont) = delete; + // from span template , typename Dummy = std::enable_if_t::value && std::is_convertible::value> > - constexpr basic_string_span(const span& other) noexcept - : real(other) + constexpr basic_string_span(span other) noexcept + : span_(other) {} // from string_span @@ -298,131 +303,130 @@ public: typename OtherBounds = static_bounds, typename Dummy = std::enable_if_t::value && std::is_convertible::value> > - constexpr basic_string_span(const basic_string_span& other) noexcept - : real(other.data(), other.length()) + constexpr basic_string_span(basic_string_span other) noexcept + : span_(other.data(), other.length()) {} - // section on linear space + constexpr bool empty() const noexcept + { + return length() == 0; + } + + // first Count elements template constexpr basic_string_span first() const noexcept { - return{ real.template first() }; + return{ span_.template first() }; } constexpr basic_string_span first(size_type count) const noexcept { - return{ real.first(count) }; + return{ span_.first(count) }; } + // last Count elements template constexpr basic_string_span last() const noexcept { - return{ real.template last() }; + return{ span_.template last() }; } constexpr basic_string_span last(size_type count) const noexcept { - return{ real.last(count) }; + return{ span_.last(count) }; } + // Count elements starting from Offset template constexpr basic_string_span sub() const noexcept { - return{ real.template sub() }; + return{ span_.template sub() }; } constexpr basic_string_span sub(size_type offset, size_type count = dynamic_range) const noexcept { - return{ real.sub(offset, count) }; + return{ span_.sub(offset, count) }; } - constexpr const_reference operator[](size_type idx) const noexcept + constexpr reference operator[](size_type idx) const noexcept { - return real[idx]; - } - - constexpr reference operator[](size_type idx) noexcept - { - return real[idx]; + return span_[idx]; } constexpr pointer data() const noexcept { - return real.data(); + return span_.data(); } constexpr size_type length() const noexcept { - return real.size(); + return span_.size(); } constexpr size_type size() const noexcept { - return real.size(); - } - - constexpr size_type used_length() const noexcept - { - return length(); + return span_.size(); } constexpr size_type bytes() const noexcept { - return real.bytes(); - } - - constexpr size_type used_bytes() const noexcept - { - return bytes(); - } - - constexpr explicit operator bool() const noexcept - { - return real; + return span_.bytes(); } constexpr iterator begin() const noexcept { - return real.begin(); + return span_.begin(); } constexpr iterator end() const noexcept { - return real.end(); + return span_.end(); } constexpr const_iterator cbegin() const noexcept { - return real.cbegin(); + return span_.cbegin(); } constexpr const_iterator cend() const noexcept { - real.cend(); + span_.cend(); } constexpr reverse_iterator rbegin() const noexcept { - return real.rbegin(); + return span_.rbegin(); } constexpr reverse_iterator rend() const noexcept { - return real.rend(); + return span_.rend(); } constexpr const_reverse_iterator crbegin() const noexcept { - return real.crbegin(); + return span_.crbegin(); } constexpr const_reverse_iterator crend() const noexcept { - return real.crend(); + return span_.crend(); } private: - span real; + + static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) noexcept + { + return{ sz, details::length_func()(sz, max)}; + } + + template + static impl_type remove_z(value_type(&sz)[N]) noexcept + { + return remove_z(&sz[0], narrow_cast(N)); + } + + impl_type span_; }; template @@ -440,7 +444,7 @@ using cwstring_span = basic_string_span; // // to_string() allow (explicit) conversions from string_span to string // -#ifndef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG +#ifndef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG template std::basic_string::type> to_string(basic_string_span view) @@ -470,12 +474,13 @@ inline std::wstring to_string(wstring_span<> view) return{ view.data(), view.length() }; } -#endif +#endif template class basic_zstring_builder { public: + using impl_type = span; using string_span_type = basic_string_span; using value_type = CharT; using pointer = CharT*; @@ -499,7 +504,7 @@ public: iterator end() const { return sv_.end(); } private: - string_span_type sv_; + impl_type sv_; }; template @@ -509,69 +514,36 @@ template using wzstring_builder = basic_zstring_builder; } -/* -bool operator==(const gsl::cstring_span<>& one, const gsl::cstring_span<>& other) noexcept +template +bool operator==(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept { return std::equal(one.begin(), one.end(), other.begin(), other.end()); } -bool operator==(const gsl::cwstring_span<>& one, const gsl::cwstring_span<>& other) noexcept -{ - return std::equal(one.begin(), one.end(), other.begin(), other.end()); -} -*/ - - -template -bool operator==(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept -{ - return std::equal(one.begin(), one.end(), other.begin(), other.end()); -} - -/* -template , std::remove_cv_t>::value>> -constexpr bool operator==(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept -{ - return std::equal(one.begin(), one.end(), other.begin(), other.end()); -} -*/ -/* -template , std::remove_cv_t>::value>> -constexpr bool operator==(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept -{ - return std::equal(one.begin(), one.end(), other.begin(), other.end()); -} - -template , std::remove_cv_t>::value>> -constexpr bool operator!=(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept -{ - return !(one == other); -} - -template , std::remove_cv_t>::value>> -constexpr bool operator<(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept +template +bool operator<(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept { return std::lexicographical_compare(one.begin(), one.end(), other.begin(), other.end()); } -template , std::remove_cv_t>::value>> -constexpr bool operator<=(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept +template +bool operator<=(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept { return !(other < one); } -template , std::remove_cv_t>::value>> -constexpr bool operator>(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept +template +bool operator>(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept { return other < one; } -template , std::remove_cv_t>::value>> -constexpr bool operator>=(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept +template +bool operator>=(const gsl::basic_string_span& one, const gsl::basic_string_span& other) noexcept { return !(one < other); } -*/ + // VS 2013 workarounds #ifdef _MSC_VER @@ -592,7 +564,7 @@ constexpr bool operator>=(const gsl::basic_string_span& one, #endif // _MSC_VER <= 1800 #endif // _MSC_VER -#if defined(GSL_THROW_ON_CONTRACT_VIOLATION) +#if defined(GSL_THROW_ON_CONTRACT_VIOLATION) #undef noexcept diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index 90b7c3c..4e42cc5 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -14,12 +14,10 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include #include #include -#include -#include using namespace std; using namespace gsl; @@ -76,7 +74,7 @@ SUITE(string_span_tests) wstring_span<> v = stack_string; CHECK(v.length() == 5); } - } + } TEST(TestConstructFromConstCharPointer) { @@ -89,7 +87,7 @@ SUITE(string_span_tests) { char stack_string[] = "Hello"; string_span<> v = ensure_z(stack_string); - cstring_span<> v2 = v; + cstring_span<> v2 = v; CHECK(v.length() == v2.length()); } @@ -116,7 +114,7 @@ SUITE(string_span_tests) CHECK(s2.length() == 5); } - TEST(ComparisonAndImplicitConstructors) + TEST(EqualityAndImplicitConstructors) { { cstring_span<> span = "Hello"; @@ -132,25 +130,60 @@ SUITE(string_span_tests) CHECK(span == cstring_span<>("Hello")); // comparison to static array with no null termination - CHECK(span == cstring_span<>(ar)); + CHECK(span == cstring_span<>(ar)); // comparison to static array with null at the end CHECK(span == cstring_span<>(ar1)); // comparison to static array with null in the middle - CHECK(span == cstring_span<>(ar2)); + CHECK(span == cstring_span<>(ar2)); // comparison to null-terminated c string - CHECK(span == cstring_span<>(ptr, 5)); + CHECK(span == cstring_span<>(ptr, 5)); // comparison to string - CHECK(span == cstring_span<>(str)); + CHECK(span == cstring_span<>(str)); // comparison to vector of charaters with no null termination - CHECK(span == cstring_span<>(vec)); + CHECK(span == cstring_span<>(vec)); // comparison of the original data to string CHECK(span.data() == std::string("Hello")); + } + + { + char ar[] = { 'H', 'e', 'l', 'l', 'o' }; + + string_span<> span = ar; + + char ar1[] = "Hello"; + char ar2[10] = "Hello"; + char* ptr = ar; + std::string str = "Hello"; + std::vector vec = { 'H', 'e', 'l', 'l', 'o' }; + + // comparison to static array with no null termination + CHECK(span == string_span<>(ar)); + + // comparison to static array with null at the end + CHECK(span == string_span<>(ar1)); + + // comparison to static array with null in the middle + CHECK(span == string_span<>(ar2)); + + // comparison to null-terminated c string + CHECK(span == string_span<>(ptr, 5)); + + // comparison to string + CHECK(span == string_span<>(str)); + + // comparison to vector of charaters with no null termination + CHECK(span == string_span<>(vec)); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + cstring_span<> span = "Hello"; CHECK(span == "Hello"); CHECK(span == ar); @@ -159,7 +192,7 @@ SUITE(string_span_tests) CHECK(span == ptr); CHECK(span == str); CHECK(span == vec); - + char _ar[] = { 'H', 'e', 'l', 'l', 'o' }; char _ar1[] = "Hello"; char _ar2[10] = "Hello"; @@ -191,6 +224,7 @@ SUITE(string_span_tests) CHECK(_span == str); CHECK(_span == vec); } +#endif { std::vector str1 = { 'H', 'e', 'l', 'l', 'o' }; @@ -203,6 +237,78 @@ SUITE(string_span_tests) } } + + TEST(ComparisonAndImplicitConstructors) + { + { + cstring_span<> span = "Hello"; + + const char ar[] = { 'H', 'e', 'l', 'l', 'o' }; + const char ar1[] = "Hello"; + const char ar2[10] = "Hello"; + const char* ptr = "Hello"; + const std::string str = "Hello"; + const std::vector vec = { 'H', 'e', 'l', 'l', 'o' }; + + // comparison to literal + CHECK(span < cstring_span<>("Helloo")); + CHECK(span > cstring_span<>("Hell")); + + // comparison to static array with no null termination + CHECK(span >= cstring_span<>(ar)); + + // comparison to static array with null at the end + CHECK(span <= cstring_span<>(ar1)); + + // comparison to static array with null in the middle + CHECK(span >= cstring_span<>(ar2)); + + // comparison to null-terminated c string + CHECK(span <= cstring_span<>(ptr, 5)); + + // comparison to string + CHECK(span >= cstring_span<>(str)); + + // comparison to vector of charaters with no null termination + CHECK(span <= cstring_span<>(vec)); + } + + { + char ar[] = { 'H', 'e', 'l', 'l', 'o' }; + + string_span<> span = ar; + + char larr[] = "Hell"; + char rarr[] = "Helloo"; + + char ar1[] = "Hello"; + char ar2[10] = "Hello"; + char* ptr = ar; + std::string str = "Hello"; + std::vector vec = { 'H', 'e', 'l', 'l', 'o' }; + + + // comparison to static array with no null termination + CHECK(span <= string_span<>(ar)); + CHECK(span < string_span<>(rarr)); + CHECK(span > string_span<>(larr)); + + // comparison to static array with null at the end + CHECK(span >= string_span<>(ar1)); + + // comparison to static array with null in the middle + CHECK(span <= string_span<>(ar2)); + + // comparison to null-terminated c string + CHECK(span >= string_span<>(ptr, 5)); + + // comparison to string + CHECK(span <= string_span<>(str)); + + // comparison to vector of charaters with no null termination + CHECK(span >= string_span<>(vec)); + } + } TEST(EnzureRemoveZ) { // remove z from literals @@ -226,39 +332,17 @@ SUITE(string_span_tests) ptr[1] = 'b'; ptr[2] = '\0'; - string_span<> span(ptr); + string_span<> span = ensure_z(ptr); CHECK(span.length() == 2); delete[] ptr; } - - // ensuze z on c strings - { - char* ptr = new char[2]; - - ptr[0] = 'a'; - ptr[1] = 'b'; - - // do we want to have a constructor from pointer at all? - // the behavior is unpredictable if the string is not 0-terminated - - // CHECK_THROW((string_span<>(ptr).length() == 2), fail_fast); - - cstring_span<> sp1{ ptr, 2 }; // good - cstring_span<> sp2{ ptr, 3 }; // bad... but can't help there - - CHECK(sp1[1] == 'b'); - CHECK_THROW((void)(sp1[2] == 'c'), fail_fast); - - CHECK(sp2[1] == 'b'); - //CHECK_THROW((sp1[2] == 'c'), fail_fast); // buffer overflow - - delete[] ptr; - } } TEST(Constructors) { + // creating cstring_span + // from string temporary #ifdef CONFIRM_COMPILATION_ERRORS { @@ -363,14 +447,12 @@ SUITE(string_span_tests) CHECK(span.length() == 5); } - /////////////////////////////////////////////////// - // How string_span should behave with const data + // creating string_span // from string literal { #ifdef CONFIRM_COMPILATION_ERRORS string_span<> span = "Hello"; - CHECK(span.length() == 5); #endif } @@ -401,12 +483,10 @@ SUITE(string_span_tests) // from non-const ptr and length { - // does not compile with GCC (ISO standard does not allows converting string literals to char*) -#ifdef CONFIRM_COMPILATION_ERRORS - char* ptr = "Hello"; + char ar[] = { 'H', 'e', 'l', 'l', 'o' }; + char* ptr = ar; string_span<> span{ ptr, 5 }; CHECK(span.length() == 5); -#endif } // from const string @@ -459,11 +539,11 @@ SUITE(string_span_tests) CHECK(span.length() == 5); } - // from non-const span of non-const data from const vector (looks like a bug) + // from non-const span of non-const data from const vector { #ifdef CONFIRM_COMPILATION_ERRORS const std::vector vec = { 'H', 'e', 'l', 'l', 'o' }; - const span inner = vec; // fix error (happens inside the constructor) + const span inner = vec; string_span<> span = inner; CHECK(span.length() == 5); #endif @@ -500,12 +580,106 @@ SUITE(string_span_tests) // from const string_span of non-const data { std::vector vec = { 'H', 'e', 'l', 'l', 'o' }; - const string_span<> tmp = vec; // what does "const span" mean? + const string_span<> tmp = vec; string_span<> span = tmp; CHECK(span.length() == 5); } } + template + T move_wrapper(T&& t) + { + return std::move(t); + } + + template + T create() { return T{}; } + + template + void use(basic_string_span s) {} + + TEST(MoveConstructors) + { + // move string_span + { + cstring_span<> span = "Hello"; + auto span1 = std::move(span); + CHECK(span1.length() == 5); + } + { + cstring_span<> span = "Hello"; + auto span1 = move_wrapper(std::move(span)); + CHECK(span1.length() == 5); + } + { + cstring_span<> span = "Hello"; + auto span1 = move_wrapper(std::move(span)); + CHECK(span1.length() == 5); + } + + // move span + { + span span = ensure_z("Hello"); + cstring_span<> span1 = std::move(span); + CHECK(span1.length() == 5); + } + { + span span = ensure_z("Hello"); + cstring_span<> span2 = move_wrapper(std::move(span)); + CHECK(span2.length() == 5); + } + + // move string + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::string str = "Hello"; + string_span<> span = std::move(str); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::string str = "Hello"; + string_span<> span = move_wrapper(std::move(str)); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + use(create()); +#endif + } + + // move container + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::vector vec = { 'H', 'e', 'l', 'l', 'o' }; + string_span<> span = std::move(vec); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::vector vec = { 'H', 'e', 'l', 'l', 'o' }; + string_span<> span = move_wrapper>(std::move(vec)); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + use(create>()); +#endif + } + } + + TEST(Conversion) + { +#ifdef CONFIRM_COMPPILATION_ERRORS + cstring_span<> span = "Hello"; + cwstring_span<> wspan{ span }; + CHECK(wspan.length() == 5); +#endif + } } int main(int, const char *[])