From 462a5969c22a7294cc865805dcdcae5d37428537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Sun, 16 Jul 2017 19:30:39 -0700 Subject: [PATCH] Compare as strings holding indices/version numbers. --- include/bx/string.h | 6 ++++ src/string.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++ tests/string_test.cpp | 63 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/include/bx/string.h b/include/bx/string.h index c0fd76a13..c5f057e8d 100644 --- a/include/bx/string.h +++ b/include/bx/string.h @@ -156,6 +156,12 @@ namespace bx /// Case insensitive string compare. int32_t strCmpI(const char* _lhs, const StringView& _rhs); + // Compare as strings holding indices/version numbers. + int32_t strCmpV(const char* _lhs, const char* _rhs, int32_t _max = INT32_MAX); + + // Compare as strings holding indices/version numbers. + int32_t strCmpV(const char* _lhs, const StringView& _rhs); + /// Get string length. int32_t strLen(const char* _str, int32_t _max = INT32_MAX); diff --git a/src/string.cpp b/src/string.cpp index 2b959c3cb..a1d5445ed 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -149,6 +149,75 @@ namespace bx return strCmpI(_lhs, _rhs.getPtr(), _rhs.getLength() ); } + int32_t strCmpV(const char* _lhs, const char* _rhs, int32_t _max) + { + 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 0; + } + + 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 ? 0 : _lhs[ii] - _rhs[ii]; + } + + int32_t strCmpV(const char* _lhs, const StringView& _rhs) + { + return strCmpV(_lhs, _rhs.getPtr(), _rhs.getLength() ); + } + int32_t strLen(const char* _str, int32_t _max) { if (NULL == _str) diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 92d46f4a6..175fbf6d0 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -6,6 +6,7 @@ #include "test.h" #include #include +#include bx::AllocatorI* g_allocator; @@ -87,6 +88,68 @@ TEST_CASE("strCmpI", "") REQUIRE(0 < bx::strCmpI(abvgd, empty) ); } +TEST_CASE("strCmpV", "") +{ + REQUIRE(0 == bx::strCmpV("test", "test") ); + REQUIRE(0 == bx::strCmpV("test", "testestes", 4) ); + REQUIRE(0 == bx::strCmpV("testestes", "test", 4) ); + REQUIRE(0 != bx::strCmpV("preprocess", "platform") ); + + const char* abvgd = "abvgd"; + const char* abvgx = "abvgx"; + const char* empty = ""; + REQUIRE(0 == bx::strCmpV(abvgd, abvgd) ); + REQUIRE(0 == bx::strCmpV(abvgd, abvgx, 4) ); + + REQUIRE(0 > bx::strCmpV(abvgd, abvgx) ); + REQUIRE(0 > bx::strCmpV(empty, abvgd) ); + + REQUIRE(0 < bx::strCmpV(abvgx, abvgd) ); + REQUIRE(0 < bx::strCmpV(abvgd, empty) ); +} + +static int32_t strCmpV(const void* _lhs, const void* _rhs) +{ + const char* lhs = *(const char**)_lhs; + const char* rhs = *(const char**)_rhs; + int32_t result = bx::strCmpV(lhs, rhs); + return result; +} + +TEST_CASE("strCmpV sort", "") +{ + const char* test[] = + { + "test_1.txt", + "test_10.txt", + "test_100.txt", + "test_15.txt", + "test_11.txt", + "test_23.txt", + "test_3.txt", + }; + + const char* expected[] = + { + "test_1.txt", + "test_3.txt", + "test_10.txt", + "test_11.txt", + "test_15.txt", + "test_23.txt", + "test_100.txt", + }; + + BX_STATIC_ASSERT(BX_COUNTOF(test) == BX_COUNTOF(expected) ); + + bx::quickSort(test, BX_COUNTOF(test), sizeof(const char*), strCmpV); + + for (uint32_t ii = 0; ii < BX_COUNTOF(test); ++ii) + { + REQUIRE(0 == bx::strCmp(test[ii], expected[ii]) ); + } +} + TEST_CASE("strRFind", "") { const char* test = "test";