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:
Brandon Kentel 2015-12-12 19:44:48 -05:00
parent de62e7b0ae
commit 4fc733f88c
2 changed files with 83 additions and 93 deletions

View File

@ -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>

View File

@ -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)