const_strlen to be aware of interior nul chars

Prior to this change, const_strlen would only look for trailing nul
chars. Teach it about interior nul chars and add some tests.
This commit is contained in:
ridiculousfish 2021-07-15 12:13:53 -07:00
parent ccd1b4e4f4
commit a638c4f01d
3 changed files with 36 additions and 23 deletions

View File

@ -1975,13 +1975,3 @@ bool is_console_session() {
return console_session;
}
static_assert(const_strcmp("", "a") < 0, "const_strcmp failure");
static_assert(const_strcmp("a", "a") == 0, "const_strcmp failure");
static_assert(const_strcmp("a", "") > 0, "const_strcmp failure");
static_assert(const_strcmp("aa", "a") > 0, "const_strcmp failure");
static_assert(const_strcmp("a", "aa") < 0, "const_strcmp failure");
static_assert(const_strcmp("b", "aa") > 0, "const_strcmp failure");
static_assert(const_strlen("") == 0, "const_strlen failure");
static_assert(const_strlen("a") == 1, "const_strlen failure");
static_assert(const_strlen("hello") == 5, "const_strlen failure");

View File

@ -701,19 +701,13 @@ constexpr ssize_t const_strcmp(const T *lhs, const T *rhs) {
/// Compile-time agnostic-size strlen/wcslen implementation. Unicode-unaware.
template <typename T, size_t N>
constexpr size_t const_strlen(const T (&val)[N], ssize_t index = -1) {
// N is the length of the character array, but that includes one **or more** trailing nuls.
static_assert(N > 0, "Invalid input to const_strlen");
return index == -1
?
// Assume a minimum of one trailing nul and do a quick check for the usual case
// (single trailing nul) before recursing:
N - 1 - (N <= 2 || val[N - 2] != static_cast<T>(0) ? 0 : const_strlen(val, N - 2))
// Prevent an underflow in case the string is comprised of all \0 bytes
: index == 0
? 0
// Keep back-tracking until a non-nul byte is found
: (val[index] != static_cast<T>(0) ? 0 : 1 + const_strlen(val, index - 1));
constexpr size_t const_strlen(const T (&val)[N], size_t last_checked_idx = N,
size_t first_nul_idx = N) {
// Assume there's a nul char at the end (index N) but there may be one before that that.
return last_checked_idx == 0
? first_nul_idx
: const_strlen(val, last_checked_idx - 1,
val[last_checked_idx - 1] ? first_nul_idx : last_checked_idx - 1);
}
/// Compile-time assertion of alphabetical sort of array `array`, by specified

View File

@ -1671,10 +1671,39 @@ static void test_wcsfilecmp() {
}
}
static void test_const_strlen() {
do_test(const_strlen("") == 0);
do_test(const_strlen(L"") == 0);
do_test(const_strlen("\0") == 0);
do_test(const_strlen(L"\0") == 0);
do_test(const_strlen("\0abc") == 0);
do_test(const_strlen(L"\0abc") == 0);
do_test(const_strlen("x") == 1);
do_test(const_strlen(L"x") == 1);
do_test(const_strlen("abc") == 3);
do_test(const_strlen(L"abc") == 3);
do_test(const_strlen("abc\0def") == 3);
do_test(const_strlen(L"abc\0def") == 3);
do_test(const_strlen("abcdef\0") == 6);
do_test(const_strlen(L"abcdef\0") == 6);
static_assert(const_strlen("hello") == 5, "const_strlen failure");
}
static void test_const_strcmp() {
static_assert(const_strcmp("", "a") < 0, "const_strcmp failure");
static_assert(const_strcmp("a", "a") == 0, "const_strcmp failure");
static_assert(const_strcmp("a", "") > 0, "const_strcmp failure");
static_assert(const_strcmp("aa", "a") > 0, "const_strcmp failure");
static_assert(const_strcmp("a", "aa") < 0, "const_strcmp failure");
static_assert(const_strcmp("b", "aa") > 0, "const_strcmp failure");
}
static void test_utility_functions() {
say(L"Testing utility functions");
test_wcsfilecmp();
test_parse_util_cmdsubst_extent();
test_const_strlen();
test_const_strcmp();
}
// UTF8 tests taken from Alexey Vatchenko's utf8 library. See http://www.bsdua.org/libbsdua.html.