diff --git a/include/bx/inline/string.inl b/include/bx/inline/string.inl index cf5a811..31baa07 100644 --- a/include/bx/inline/string.inl +++ b/include/bx/inline/string.inl @@ -577,6 +577,133 @@ namespace bx return int32_t(ptr - _str); } + typedef char (*CharFn)(char _ch); + + inline BX_CONSTEXPR_FUNC char toNoop(char _ch) + { + return _ch; + } + + template + inline constexpr int32_t strCmp(const char* _lhs, int32_t _lhsMax, const char* _rhs, int32_t _rhsMax) + { + int32_t max = min(_lhsMax, _rhsMax); + + for ( + ; 0 < max && fn(*_lhs) == fn(*_rhs) + ; ++_lhs, ++_rhs, --max + ) + { + if (*_lhs == '\0' + || *_rhs == '\0') + { + break; + } + } + + if (0 == max) + { + return _lhsMax == _rhsMax ? 0 : _lhsMax > _rhsMax ? 1 : -1; + } + + return fn(*_lhs) - fn(*_rhs); + } + + inline constexpr int32_t strCmp(const StringView& _lhs, const StringView& _rhs, int32_t _max) + { + return strCmp( + _lhs.getPtr() + , min(_lhs.getLength(), _max) + , _rhs.getPtr() + , min(_rhs.getLength(), _max) + ); + } + + inline constexpr int32_t strCmpI(const StringView& _lhs, const StringView& _rhs, int32_t _max) + { + return strCmp( + _lhs.getPtr() + , min(_lhs.getLength(), _max) + , _rhs.getPtr() + , min(_rhs.getLength(), _max) + ); + } + + inline constexpr int32_t strCmpV(const char* _lhs, int32_t _lhsMax, const char* _rhs, int32_t _rhsMax) + { + int32_t max = min(_lhsMax, _rhsMax); + int32_t ii = 0; + int32_t idx = 0; + bool zero = true; + + for ( + ; 0 < max && _lhs[ii] == _rhs[ii] + ; ++ii, --max + ) + { + const uint8_t ch = _lhs[ii]; + if ('\0' == ch + || '\0' == _rhs[ii]) + { + break; + } + + if (!isNumeric(ch) ) + { + idx = ii+1; + zero = true; + } + else if ('0' != ch) + { + zero = false; + } + } + + if (0 == max) + { + return _lhsMax == _rhsMax ? 0 : _lhs[ii] - _rhs[ii]; + } + + if ('0' != _lhs[idx] + && '0' != _rhs[idx]) + { + int32_t jj = 0; + for (jj = ii + ; 0 < max && isNumeric(_lhs[jj]) + ; ++jj, --max + ) + { + if (!isNumeric(_rhs[jj]) ) + { + return 1; + } + } + + if (isNumeric(_rhs[jj])) + { + return -1; + } + } + else if (zero + && idx < ii + && (isNumeric(_lhs[ii]) || isNumeric(_rhs[ii]) ) ) + { + return (_lhs[ii] - '0') - (_rhs[ii] - '0'); + } + + return 0 == max && _lhsMax == _rhsMax ? 0 : _lhs[ii] - _rhs[ii]; + } + + inline constexpr int32_t strCmpV(const StringView& _lhs, const StringView& _rhs, int32_t _max) + { + return strCmpV( + _lhs.getPtr() + , min(_lhs.getLength(), _max) + , _rhs.getPtr() + , min(_rhs.getLength(), _max) + ); + } + inline bool hasPrefix(const StringView& _str, const StringView& _prefix) { const int32_t len = _prefix.getLength(); diff --git a/include/bx/string.h b/include/bx/string.h index e4facd9..dc947cc 100644 --- a/include/bx/string.h +++ b/include/bx/string.h @@ -375,13 +375,13 @@ namespace bx void toUpper(char* _inOutStr, int32_t _max = INT32_MAX); /// String compare. - int32_t strCmp(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX); + constexpr int32_t strCmp(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX); /// Case insensitive string compare. - int32_t strCmpI(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX); + constexpr int32_t strCmpI(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX); // Compare as strings holding indices/version numbers. - int32_t strCmpV(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX); + constexpr int32_t strCmpV(const StringView& _lhs, const StringView& _rhs, int32_t _max = INT32_MAX); /// Get string length. constexpr int32_t strLen(const char* _str, int32_t _max = INT32_MAX); diff --git a/src/string.cpp b/src/string.cpp index a21ebac..bdf9a2b 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -94,133 +94,6 @@ namespace bx toUpperUnsafe(_inOutStr, len); } - typedef char (*CharFn)(char _ch); - - inline BX_CONSTEXPR_FUNC char toNoop(char _ch) - { - return _ch; - } - - template - inline int32_t strCmp(const char* _lhs, int32_t _lhsMax, const char* _rhs, int32_t _rhsMax) - { - int32_t max = min(_lhsMax, _rhsMax); - - for ( - ; 0 < max && fn(*_lhs) == fn(*_rhs) - ; ++_lhs, ++_rhs, --max - ) - { - if (*_lhs == '\0' - || *_rhs == '\0') - { - break; - } - } - - if (0 == max) - { - return _lhsMax == _rhsMax ? 0 : _lhsMax > _rhsMax ? 1 : -1; - } - - return fn(*_lhs) - fn(*_rhs); - } - - int32_t strCmp(const StringView& _lhs, const StringView& _rhs, int32_t _max) - { - return strCmp( - _lhs.getPtr() - , min(_lhs.getLength(), _max) - , _rhs.getPtr() - , min(_rhs.getLength(), _max) - ); - } - - int32_t strCmpI(const StringView& _lhs, const StringView& _rhs, int32_t _max) - { - return strCmp( - _lhs.getPtr() - , min(_lhs.getLength(), _max) - , _rhs.getPtr() - , min(_rhs.getLength(), _max) - ); - } - - inline int32_t strCmpV(const char* _lhs, int32_t _lhsMax, const char* _rhs, int32_t _rhsMax) - { - int32_t max = min(_lhsMax, _rhsMax); - int32_t ii = 0; - int32_t idx = 0; - bool zero = true; - - for ( - ; 0 < max && _lhs[ii] == _rhs[ii] - ; ++ii, --max - ) - { - const uint8_t ch = _lhs[ii]; - if ('\0' == ch - || '\0' == _rhs[ii]) - { - break; - } - - if (!isNumeric(ch) ) - { - idx = ii+1; - zero = true; - } - else if ('0' != ch) - { - zero = false; - } - } - - if (0 == max) - { - return _lhsMax == _rhsMax ? 0 : _lhs[ii] - _rhs[ii]; - } - - if ('0' != _lhs[idx] - && '0' != _rhs[idx]) - { - int32_t jj = 0; - for (jj = ii - ; 0 < max && isNumeric(_lhs[jj]) - ; ++jj, --max - ) - { - if (!isNumeric(_rhs[jj]) ) - { - return 1; - } - } - - if (isNumeric(_rhs[jj])) - { - return -1; - } - } - else if (zero - && idx < ii - && (isNumeric(_lhs[ii]) || isNumeric(_rhs[ii]) ) ) - { - return (_lhs[ii] - '0') - (_rhs[ii] - '0'); - } - - return 0 == max && _lhsMax == _rhsMax ? 0 : _lhs[ii] - _rhs[ii]; - } - - int32_t strCmpV(const StringView& _lhs, const StringView& _rhs, int32_t _max) - { - return strCmpV( - _lhs.getPtr() - , min(_lhs.getLength(), _max) - , _rhs.getPtr() - , min(_rhs.getLength(), _max) - ); - } - inline int32_t strCopy(char* _dst, int32_t _dstSize, const char* _src, int32_t _num) { BX_ASSERT(NULL != _dst, "_dst can't be NULL!"); diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 31f19dd..ad6b561 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -174,6 +174,23 @@ TEST_CASE("isEqual constexpr", "[string]") STATIC_REQUIRE( bx::isEqual(bx::StringLiteral("pod"), bx::StringView("POD"), false) ); } +TEST_CASE("strCmp constexpr", "[string]") +{ + STATIC_REQUIRE(0 == bx::strCmp("abvgd", "abvgd") ); + STATIC_REQUIRE(0 < bx::strCmp("abvgd", "abv") ); + STATIC_REQUIRE(0 > bx::strCmp("", "abvgd") ); + STATIC_REQUIRE(0 == bx::strCmp("abvgd", "abvgx", 4) ); + + STATIC_REQUIRE(0 == bx::strCmpI("abvgd", "ABVGD") ); + STATIC_REQUIRE(0 > bx::strCmpI("abvgd", "ABVGX") ); + + STATIC_REQUIRE(0 > bx::strCmpV("test_2.txt", "test_10.txt") ); + + constexpr bx::StringLiteral sorted[] = { "dds", "exr", "ktx", "ktx2", "png" }; + STATIC_REQUIRE( bx::isSorted(sorted, BX_COUNTOF(sorted), [](const bx::StringLiteral& _lhs, const bx::StringLiteral& _rhs) { return 0 > bx::strCmp(_lhs, _rhs); }) ); + STATIC_REQUIRE(!bx::isSorted(sorted, BX_COUNTOF(sorted), [](const bx::StringLiteral& _lhs, const bx::StringLiteral& _rhs) { return 0 < bx::strCmp(_lhs, _rhs); }) ); +} + TEST_CASE("strCmpV", "[string]") { REQUIRE(0 == bx::strCmpV("test", "test") );