Merge pull request #223 from annagrin/dev/annagrin/string_span_operator_fixes

string span operator fixes
This commit is contained in:
Neil MacIntosh 2015-12-08 12:01:23 -08:00
commit f569813c18
2 changed files with 461 additions and 47 deletions

View File

@ -213,6 +213,7 @@ namespace details
template <typename CharT, std::ptrdiff_t Extent = dynamic_range> template <typename CharT, std::ptrdiff_t Extent = dynamic_range>
class basic_string_span class basic_string_span
{ {
public:
using value_type = CharT; using value_type = CharT;
using const_value_type = std::add_const_t<value_type>; using const_value_type = std::add_const_t<value_type>;
using pointer = std::add_pointer_t<value_type>; using pointer = std::add_pointer_t<value_type>;
@ -221,7 +222,6 @@ class basic_string_span
using bounds_type = static_bounds<Extent>; using bounds_type = static_bounds<Extent>;
using impl_type = span<value_type, Extent>; using impl_type = span<value_type, Extent>;
public:
using size_type = ptrdiff_t; using size_type = ptrdiff_t;
using iterator = typename impl_type::iterator; using iterator = typename impl_type::iterator;
using const_iterator = typename impl_type::const_iterator; using const_iterator = typename impl_type::const_iterator;
@ -243,17 +243,17 @@ public:
// move assign // move assign
constexpr basic_string_span& operator=(basic_string_span&& other) = default; constexpr basic_string_span& operator=(basic_string_span&& other) = default;
// from nullptr
constexpr basic_string_span(std::nullptr_t ptr) noexcept
: span_(ptr)
{}
// from nullptr and length // from nullptr and length
constexpr basic_string_span(std::nullptr_t ptr, size_type length) noexcept constexpr basic_string_span(std::nullptr_t ptr, size_type length) noexcept
: span_(ptr, length) : span_(ptr, length)
{} {}
// For pointers and static arrays - if 0-terminated, remove 0 from the view // From static arrays - if 0-terminated, remove 0 from the view
// from raw data and length
constexpr basic_string_span(pointer ptr, size_type length) noexcept
: span_(remove_z(ptr, length))
{}
// from static arrays and string literals // from static arrays and string literals
template<size_t N> template<size_t N>
@ -263,9 +263,14 @@ public:
// Those allow 0s within the length, so we do not remove them // Those allow 0s within the length, so we do not remove them
// from raw data and length
constexpr basic_string_span(pointer ptr, size_type length) noexcept
: span_(ptr, length)
{}
// from string // from string
constexpr basic_string_span(std::string& s) noexcept constexpr basic_string_span(std::string& s) noexcept
: span_(&(s.at(0)), narrow_cast<std::ptrdiff_t>(s.length())) : span_(const_cast<pointer>(s.data()), narrow_cast<std::ptrdiff_t>(s.length()))
{} {}
// from containers. Containers must have .size() and .data() function signatures // from containers. Containers must have .size() and .data() function signatures
@ -523,36 +528,326 @@ template <size_t Max = dynamic_range>
using wzstring_builder = basic_zstring_builder<wchar_t, Max>; using wzstring_builder = basic_zstring_builder<wchar_t, Max>;
} }
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range> // operator ==
bool operator==(const gsl::basic_string_span<CharT, Extent>& one, const gsl::basic_string_span<CharT, Extent>& other) noexcept template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, 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 std::equal(one.begin(), one.end(), other.begin(), other.end()); gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
} }
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range> template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
bool operator<(const gsl::basic_string_span<CharT, Extent>& one, const gsl::basic_string_span<CharT, Extent>& other) noexcept 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 std::lexicographical_compare(one.begin(), one.end(), other.begin(), other.end()); gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
} }
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range> #ifndef _MSC_VER
bool operator<=(const gsl::basic_string_span<CharT, Extent>& one, const gsl::basic_string_span<CharT, Extent>& other) noexcept
// 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_range, 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::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
}
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, 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::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
}
#endif
// operator !=
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, 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_range, 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_range, 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_range, 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
// operator<
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, 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_range, 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_range, 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_range, 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_range, 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); return !(other < one);
} }
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range> template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
bool operator>(const gsl::basic_string_span<CharT, Extent>& one, const gsl::basic_string_span<CharT, Extent>& other) noexcept 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_range, 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_range, 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_range, 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; return other < one;
} }
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range> template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
bool operator>=(const gsl::basic_string_span<CharT, Extent>& one, const gsl::basic_string_span<CharT, Extent>& other) noexcept 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_range, 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_range, 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_range, 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); return !(one < other);
} }
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, 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_range, 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_range, 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
// VS 2013 workarounds // VS 2013 workarounds
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -14,11 +14,10 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <cstdlib>
#include <string_span.h> #include <string_span.h>
#include <vector> #include <vector>
#include <cstdlib>
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
@ -126,6 +125,7 @@ SUITE(string_span_tests)
const char* ptr = "Hello"; const char* ptr = "Hello";
const std::string str = "Hello"; const std::string str = "Hello";
const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' }; const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
gsl::span<const char> sp = ensure_z("Hello");
// comparison to literal // comparison to literal
CHECK(span == cstring_span<>("Hello")); CHECK(span == cstring_span<>("Hello"));
@ -148,6 +148,12 @@ SUITE(string_span_tests)
// comparison to vector of charaters with no null termination // comparison to vector of charaters with no null termination
CHECK(span == cstring_span<>(vec)); CHECK(span == cstring_span<>(vec));
// comparison to span
CHECK(span == cstring_span<>(sp));
// comparison to string_span
CHECK(span == span);
// comparison of the original data to string // comparison of the original data to string
CHECK(span.data() == std::string("Hello")); CHECK(span.data() == std::string("Hello"));
} }
@ -162,6 +168,7 @@ SUITE(string_span_tests)
char* ptr = ar; char* ptr = ar;
std::string str = "Hello"; std::string str = "Hello";
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' }; std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
gsl::span<char> sp = ensure_z(ar1);
// comparison to static array with no null termination // comparison to static array with no null termination
CHECK(span == string_span<>(ar)); CHECK(span == string_span<>(ar));
@ -180,52 +187,133 @@ SUITE(string_span_tests)
// comparison to vector of charaters with no null termination // comparison to vector of charaters with no null termination
CHECK(span == string_span<>(vec)); CHECK(span == string_span<>(vec));
// comparison to span
CHECK(span == string_span<>(sp));
// comparison to string_span
CHECK(span == span);
} }
#ifdef CONFIRM_COMPILATION_ERRORS
{ {
const char ar[] = { 'H', 'e', 'l', 'l', 'o' };
const char ar1[] = "Hello";
const char ar2[10] = "Hello";
const std::string str = "Hello";
const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
gsl::span<const char> sp = ensure_z("Hello");
cstring_span<> span = "Hello"; cstring_span<> span = "Hello";
// const span, const other type
CHECK(span == "Hello"); CHECK(span == "Hello");
CHECK(span == ar); CHECK(span == ar);
CHECK(span == ar1); CHECK(span == ar1);
CHECK(span == ar2); CHECK(span == ar2);
#ifdef CONFIRM_COMPILATION_ERRORS
const char* ptr = "Hello";
CHECK(span == ptr); CHECK(span == ptr);
#endif
CHECK(span == str); CHECK(span == str);
CHECK(span == vec); CHECK(span == vec);
CHECK(span == sp);
CHECK("Hello" == span);
CHECK(ar == span);
CHECK(ar1 == span);
CHECK(ar2 == span);
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(ptr == span);
#endif
CHECK(str == span);
CHECK(vec == span);
CHECK(sp == span);
// const span, non-const other type
char _ar[] = { 'H', 'e', 'l', 'l', 'o' }; char _ar[] = { 'H', 'e', 'l', 'l', 'o' };
char _ar1[] = "Hello"; char _ar1[] = "Hello";
char _ar2[10] = "Hello"; char _ar2[10] = "Hello";
char* _ptr = _ar1; char* _ptr = _ar;
std::string _str = "Hello"; std::string _str = "Hello";
std::vector<char> _vec = { 'H', 'e', 'l', 'l', 'o' }; std::vector<char> _vec = { 'H', 'e', 'l', 'l', 'o' };
gsl::span<char> _sp{ _ar, 5 };
CHECK(span == _ar); CHECK(span == _ar);
CHECK(span == _ar1); CHECK(span == _ar1);
CHECK(span == _ar2); CHECK(span == _ar2);
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(span == _ptr); CHECK(span == _ptr);
#endif
CHECK(span == _str); CHECK(span == _str);
CHECK(span == _vec); CHECK(span == _vec);
CHECK(span == _sp);
string_span<> _span{ _ptr }; CHECK(_ar == span);
CHECK(_ar1 == span);
CHECK(_ar2 == span);
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(_ptr == span);
#endif
CHECK(_str == span);
CHECK(_vec == span);
CHECK(_sp == span);
string_span<> _span{ _ptr, 5 };
// non-const span, non-const other type
CHECK(_span == _ar); CHECK(_span == _ar);
CHECK(_span == _ar1); CHECK(_span == _ar1);
CHECK(_span == _ar2); CHECK(_span == _ar2);
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(_span == _ptr); CHECK(_span == _ptr);
#endif
CHECK(_span == _str); CHECK(_span == _str);
CHECK(_span == _vec); CHECK(_span == _vec);
CHECK(_span == _sp);
CHECK(_ar == _span);
CHECK(_ar1 == _span);
CHECK(_ar2 == _span);
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(_ptr == _span);
#endif
CHECK(_str == _span);
CHECK(_vec == _span);
CHECK(_sp == _span);
// non-const span, const other type
CHECK(_span == "Hello"); CHECK(_span == "Hello");
CHECK(_span == ar); CHECK(_span == ar);
CHECK(_span == ar1); CHECK(_span == ar1);
CHECK(_span == ar2); CHECK(_span == ar2);
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(_span == ptr); CHECK(_span == ptr);
#endif
CHECK(_span == str); CHECK(_span == str);
CHECK(_span == vec); CHECK(_span == vec);
} CHECK(_span == sp);
CHECK("Hello" == _span);
CHECK(ar == _span);
CHECK(ar1 == _span);
CHECK(ar2 == _span);
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(ptr == _span);
#endif #endif
CHECK(str == _span);
CHECK(vec == _span);
CHECK(sp == _span);
// two spans
CHECK(_span == span);
CHECK(span == _span);
}
{ {
std::vector<char> str1 = { 'H', 'e', 'l', 'l', 'o' }; std::vector<char> str1 = { 'H', 'e', 'l', 'l', 'o' };
@ -238,7 +326,6 @@ SUITE(string_span_tests)
} }
} }
TEST(ComparisonAndImplicitConstructors) TEST(ComparisonAndImplicitConstructors)
{ {
{ {
@ -310,7 +397,7 @@ SUITE(string_span_tests)
CHECK(span >= string_span<>(vec)); CHECK(span >= string_span<>(vec));
} }
} }
TEST(EnzureRemoveZ) TEST(ConstrutorsEnsureZ)
{ {
// remove z from literals // remove z from literals
{ {
@ -351,6 +438,18 @@ SUITE(string_span_tests)
} }
#endif #endif
// default
{
cstring_span<> span;
CHECK(span.length() == 0);
}
// from nullptr
{
cstring_span<> span(nullptr);
CHECK(span.length() == 0);
}
// from string literal // from string literal
{ {
cstring_span<> span = "Hello"; cstring_span<> span = "Hello";
@ -378,14 +477,34 @@ SUITE(string_span_tests)
CHECK(span.length() == 5); CHECK(span.length() == 5);
} }
// from non-const ptr and length // from const ptr and length, include 0
{ {
// does not compile with GCC (ISO standard does not allow converting string literals to char*) const char* ptr = "Hello";
#ifdef CONFIRM_COMPILATION_ERRORS cstring_span<> span{ ptr, 6 };
char* ptr = "Hello"; CHECK(span.length() == 6);
}
// from const ptr and length, 0 inside
{
const char* ptr = "He\0lo";
cstring_span<> span{ ptr, 5 };
CHECK(span.length() == 5);
}
// from non-const ptr and length
{
char ar[] = { 'H', 'e', 'l', 'l', 'o' };
char* ptr = ar;
cstring_span<> span{ ptr, 5 };
CHECK(span.length() == 5);
}
// from non-const ptr and length, 0 inside
{
char ar[] = { 'H', 'e', '\0', 'l', 'o' };
char* ptr = ar;
cstring_span<> span{ ptr, 5 }; cstring_span<> span{ ptr, 5 };
CHECK(span.length() == 5); CHECK(span.length() == 5);
#endif
} }
// from const string // from const string