universal internal strlen for all char types
parent
375c014f7a
commit
a93ae710d0
|
@ -73,6 +73,13 @@ static_assert(
|
||||||
"wchar_t must correspond to either char, char16_t or char32_t"
|
"wchar_t must correspond to either char, char16_t or char32_t"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
std::size_t tstrlen(char const *p) noexcept;
|
||||||
|
std::size_t tstrlen(char16_t const *p) noexcept;
|
||||||
|
std::size_t tstrlen(char32_t const *p) noexcept;
|
||||||
|
std::size_t tstrlen(wchar_t const *p) noexcept;
|
||||||
|
}
|
||||||
|
|
||||||
/** @addtogroup Strings
|
/** @addtogroup Strings
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
@ -135,7 +142,7 @@ public:
|
||||||
std::size_t N = std::extent_v<std::remove_reference_t<U>>;
|
std::size_t N = std::extent_v<std::remove_reference_t<U>>;
|
||||||
p_end = beg + N - (beg[N - 1] == '\0');
|
p_end = beg + N - (beg[N - 1] == '\0');
|
||||||
} else {
|
} else {
|
||||||
p_end = beg + (beg ? std::strlen(beg) : 0);
|
p_end = beg + (beg ? detail::tstrlen(beg) : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +188,7 @@ public:
|
||||||
* The data pointed to by the argument must be zero terminated.
|
* The data pointed to by the argument must be zero terminated.
|
||||||
*/
|
*/
|
||||||
basic_char_range &operator=(value_type *s) noexcept {
|
basic_char_range &operator=(value_type *s) noexcept {
|
||||||
p_beg = s; p_end = s + (s ? std::strlen(s) : 0); return *this;
|
p_beg = s; p_end = s + (s ? detail::tstrlen(s) : 0); return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Checks if the slice is empty. */
|
/** @brief Checks if the slice is empty. */
|
||||||
|
|
|
@ -5,9 +5,57 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
#include "ostd/string.hh"
|
#include "ostd/string.hh"
|
||||||
#include "ostd/format.hh"
|
#include "ostd/format.hh"
|
||||||
|
|
||||||
|
namespace ostd {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
inline std::size_t tstrlen_impl(C const *p) noexcept {
|
||||||
|
using SL = std::numeric_limits<std::size_t>;
|
||||||
|
using UL = std::numeric_limits<std::make_unsigned_t<C>>;
|
||||||
|
constexpr std::size_t Lbits = SL::max() / UL::max();
|
||||||
|
constexpr std::size_t Hbits = Lbits << (UL::digits - 1);
|
||||||
|
|
||||||
|
C const *bp = p;
|
||||||
|
if constexpr(sizeof(C) >= sizeof(std::size_t)) {
|
||||||
|
goto sloop;
|
||||||
|
}
|
||||||
|
for (; std::uintptr_t(p) % sizeof(std::size_t); ++p) {
|
||||||
|
if (!*p) {
|
||||||
|
return (p - bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto *wp = reinterpret_cast<std::size_t const *>(p);
|
||||||
|
for (; !(((*wp - Lbits) & ~*wp) & Hbits); ++wp) {}
|
||||||
|
p = reinterpret_cast<C const *>(wp);
|
||||||
|
}
|
||||||
|
sloop:
|
||||||
|
for (; *p; ++p) {}
|
||||||
|
return (p - bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t tstrlen(char const *p) noexcept {
|
||||||
|
return tstrlen_impl(p);
|
||||||
|
}
|
||||||
|
std::size_t tstrlen(char16_t const *p) noexcept {
|
||||||
|
return tstrlen_impl(p);
|
||||||
|
}
|
||||||
|
std::size_t tstrlen(char32_t const *p) noexcept {
|
||||||
|
return tstrlen_impl(p);
|
||||||
|
}
|
||||||
|
std::size_t tstrlen(wchar_t const *p) noexcept {
|
||||||
|
return tstrlen_impl(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace detail */
|
||||||
|
} /* namespace ostd */
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
namespace utf {
|
namespace utf {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue