mirror of
https://github.com/microsoft/GSL.git
synced 2024-11-03 17:56:43 -05:00
Combine a few rendunant functions per TODO
+ Per TODO (neilmac), merged the ensure_z implementations. + Simplified details::length_func. + Removed a few instances of trailing whitespace. + Added a few new tests
This commit is contained in:
parent
de62e7b0ae
commit
4fc733f88c
@ -87,64 +87,70 @@ using wzstring = wchar_t*;
|
|||||||
//
|
//
|
||||||
// Will fail-fast if sentinel cannot be found before max elements are examined.
|
// Will fail-fast if sentinel cannot be found before max elements are examined.
|
||||||
//
|
//
|
||||||
template<typename T, const T Sentinel>
|
template <typename T, T Sentinel>
|
||||||
span<T, dynamic_range> ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX)
|
span<T, dynamic_range> ensure_sentinel(T const* const seq, ptrdiff_t const max = PTRDIFF_MAX)
|
||||||
{
|
{
|
||||||
auto cur = seq;
|
auto const it = std::find(seq, seq + max, Sentinal);
|
||||||
while ((cur - seq) < max && *cur != Sentinel) ++cur;
|
Ensures(*it == Sentinel);
|
||||||
Ensures(*cur == Sentinel);
|
return{ seq, it - seq };
|
||||||
return{ seq, cur - seq };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace details
|
||||||
//
|
|
||||||
// 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_range> ensure_z(T* const & sz, std::ptrdiff_t max = PTRDIFF_MAX)
|
|
||||||
{
|
{
|
||||||
return ensure_sentinel<T, 0>(sz, max);
|
inline ptrdiff_t length_func(char const* const sz, ptrdiff_t const len) noexcept
|
||||||
|
{
|
||||||
|
return narrow_cast<ptrdiff_t>(strnlen(sz, narrow_cast<size_t>(len)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ptrdiff_t length_func(wchar_t const* const sz, ptrdiff_t const len) noexcept
|
||||||
|
{
|
||||||
|
return narrow_cast<ptrdiff_t>(wcsnlen(sz, narrow_cast<size_t>(len)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U = std::remove_cv_t<T>>
|
||||||
|
using is_char_t = std::bool_constant<
|
||||||
|
std::is_same<char, U>::value || std::is_same<wchar_t, U>::value>;
|
||||||
|
|
||||||
|
template <typename T, typename U = std::remove_pointer_t<T>>
|
||||||
|
inline span<U> ensure_z(T const sz, ptrdiff_t const max, std::true_type)
|
||||||
|
{
|
||||||
|
auto const len = length_func(sz, max);
|
||||||
|
Ensures(sz[len] == 0);
|
||||||
|
return{ sz, narrow_cast<ptrdiff_t>(len) };
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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, typename U = std::remove_pointer_t<T>>
|
||||||
|
inline span<U> ensure_z(T const sz, ptrdiff_t const max, std::false_type)
|
||||||
|
{
|
||||||
|
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
|
template <typename T>
|
||||||
inline span<char, dynamic_range> ensure_z(char* const& sz, std::ptrdiff_t max)
|
inline span<T> ensure_z(T* const& sz, ptrdiff_t const max = PTRDIFF_MAX)
|
||||||
{
|
{
|
||||||
auto len = strnlen(sz, narrow_cast<size_t>(max));
|
return details::ensure_z(sz, max, details::is_char_t<T> {});
|
||||||
Ensures(sz[len] == 0);
|
|
||||||
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline span<const char, dynamic_range> ensure_z(const char* const& sz, std::ptrdiff_t max)
|
template <typename T, size_t N>
|
||||||
|
inline span<T> ensure_z(T (&sz)[N])
|
||||||
{
|
{
|
||||||
auto len = strnlen(sz, narrow_cast<size_t>(max));
|
return details::ensure_z(sz, narrow_cast<ptrdiff_t>(N), details::is_char_t<T> {});
|
||||||
Ensures(sz[len] == 0);
|
|
||||||
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline span<wchar_t, dynamic_range> ensure_z(wchar_t* const& sz, std::ptrdiff_t max)
|
template <typename Cont>
|
||||||
|
inline auto ensure_z(Cont& cont) -> span<std::remove_pointer_t<decltype(cont.data())>>
|
||||||
{
|
{
|
||||||
auto len = wcsnlen(sz, narrow_cast<size_t>(max));
|
return ensure_z(cont.data(), static_cast<ptrdiff_t>(cont.size()));
|
||||||
Ensures(sz[len] == 0);
|
|
||||||
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline span<const wchar_t, dynamic_range> ensure_z(const wchar_t* const& sz, std::ptrdiff_t max)
|
template <typename Cont, typename T = typename Cont::value_type>
|
||||||
{
|
span<T> ensure_z(Cont&& cont) = delete;
|
||||||
auto len = wcsnlen(sz, narrow_cast<size_t>(max));
|
|
||||||
Ensures(sz[len] == 0);
|
|
||||||
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, size_t N>
|
|
||||||
span<T, dynamic_range> 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_range> ensure_z(Cont& cont)
|
|
||||||
{
|
|
||||||
return ensure_z(cont.data(), static_cast<std::ptrdiff_t>(cont.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, std::ptrdiff_t>
|
template<typename CharT, std::ptrdiff_t>
|
||||||
class basic_string_span;
|
class basic_string_span;
|
||||||
@ -162,46 +168,6 @@ namespace details
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_basic_string_span : is_basic_string_span_oracle<std::remove_cv_t<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 narrow_cast<std::ptrdiff_t>(strnlen(ptr, narrow_cast<size_t>(length)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct length_func<wchar_t>
|
|
||||||
{
|
|
||||||
std::ptrdiff_t operator()(wchar_t* const ptr, std::ptrdiff_t length) noexcept
|
|
||||||
{
|
|
||||||
return narrow_cast<std::ptrdiff_t>(wcsnlen(ptr, narrow_cast<size_t>(length)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct length_func<const char>
|
|
||||||
{
|
|
||||||
std::ptrdiff_t operator()(const char* const ptr, std::ptrdiff_t length) noexcept
|
|
||||||
{
|
|
||||||
return narrow_cast<std::ptrdiff_t>(strnlen(ptr, narrow_cast<size_t>(length)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct length_func<const wchar_t>
|
|
||||||
{
|
|
||||||
std::ptrdiff_t operator()(const wchar_t* const ptr, std::ptrdiff_t length) noexcept
|
|
||||||
{
|
|
||||||
return narrow_cast<std::ptrdiff_t>(wcsnlen(ptr, narrow_cast<size_t>(length)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -431,7 +397,7 @@ private:
|
|||||||
|
|
||||||
static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) noexcept
|
static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) noexcept
|
||||||
{
|
{
|
||||||
return{ sz, details::length_func<value_type>()(sz, max)};
|
return{ sz, details::length_func(sz, max)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
@ -550,7 +516,7 @@ bool operator==(const T& one, gsl::basic_string_span<CharT, Extent> other) noexc
|
|||||||
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
|
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
// VS treats temp and const containers as convertible to basic_string_span,
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
// so the cases below are already covered by the previous operators
|
// so the cases below are already covered by the previous operators
|
||||||
@ -604,7 +570,7 @@ bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexc
|
|||||||
return !(one == other);
|
return !(one == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
// VS treats temp and const containers as convertible to basic_string_span,
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
// so the cases below are already covered by the previous operators
|
// so the cases below are already covered by the previous operators
|
||||||
@ -658,7 +624,7 @@ bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) noexce
|
|||||||
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
// VS treats temp and const containers as convertible to basic_string_span,
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
// so the cases below are already covered by the previous operators
|
// so the cases below are already covered by the previous operators
|
||||||
@ -712,7 +678,7 @@ bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexc
|
|||||||
return !(other < one);
|
return !(other < one);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
// VS treats temp and const containers as convertible to basic_string_span,
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
// so the cases below are already covered by the previous operators
|
// so the cases below are already covered by the previous operators
|
||||||
@ -764,7 +730,7 @@ bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) noexce
|
|||||||
return other < one;
|
return other < one;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
// VS treats temp and const containers as convertible to basic_string_span,
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
// so the cases below are already covered by the previous operators
|
// so the cases below are already covered by the previous operators
|
||||||
@ -816,7 +782,7 @@ bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexc
|
|||||||
return !(one < other);
|
return !(one < other);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
// VS treats temp and const containers as convertible to basic_string_span,
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
// so the cases below are already covered by the previous operators
|
// so the cases below are already covered by the previous operators
|
||||||
|
@ -40,15 +40,39 @@ SUITE(string_span_tests)
|
|||||||
TEST(TestConstructFromStdString)
|
TEST(TestConstructFromStdString)
|
||||||
{
|
{
|
||||||
std::string s = "Hello there world";
|
std::string s = "Hello there world";
|
||||||
|
auto const len = static_cast<cstring_span<>::size_type>(s.length());
|
||||||
|
|
||||||
cstring_span<> v = s;
|
cstring_span<> v = s;
|
||||||
CHECK(v.length() == static_cast<cstring_span<>::size_type>(s.length()));
|
CHECK(v.length() == len);
|
||||||
|
|
||||||
|
s.back() = 0;
|
||||||
|
v = ensure_z(s);
|
||||||
|
CHECK(v.length() == len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestConstructFromStdVector)
|
TEST(TestConstructFromStdVector)
|
||||||
{
|
{
|
||||||
std::vector<char> vec(5, 'h');
|
std::vector<char> vec(5, 'h');
|
||||||
|
auto const size = static_cast<cstring_span<>::size_type>(vec.size());
|
||||||
|
|
||||||
string_span<> v = vec;
|
string_span<> v = vec;
|
||||||
CHECK(v.length() == static_cast<string_span<>::size_type>(vec.size()));
|
CHECK(v.length() == size);
|
||||||
|
|
||||||
|
vec.back() = 0;
|
||||||
|
v = ensure_z(vec);
|
||||||
|
CHECK(v.length() == size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestConstructFromStdArray)
|
||||||
|
{
|
||||||
|
std::array<char, 5> arr {"1234"};
|
||||||
|
auto const size = static_cast<cstring_span<>::size_type>(arr.size());
|
||||||
|
|
||||||
|
string_span<> v = arr;
|
||||||
|
CHECK(v.length() == 5);
|
||||||
|
|
||||||
|
v = ensure_z(arr);
|
||||||
|
CHECK(v.length() == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TestStackArrayConstruction)
|
TEST(TestStackArrayConstruction)
|
||||||
@ -264,7 +288,7 @@ SUITE(string_span_tests)
|
|||||||
string_span<> _span{ _ptr, 5 };
|
string_span<> _span{ _ptr, 5 };
|
||||||
|
|
||||||
// non-const span, non-const other type
|
// 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);
|
||||||
|
Loading…
Reference in New Issue
Block a user