diff --git a/src/common.cpp b/src/common.cpp index 08b86b9c9..541d976bc 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -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"); diff --git a/src/common.h b/src/common.h index d5a2c9495..8bb92a3b0 100644 --- a/src/common.h +++ b/src/common.h @@ -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 -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(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(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 diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index f26f8abde..94ea9d56b 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -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.