Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions include/bx/inline/string.inl
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ namespace bx
return m_0terminated;
}

inline constexpr bool operator==(const StringView& _lhs, const StringView& _rhs)
inline BX_CONSTEXPR_FUNC bool isEqual(const StringView& _lhs, const StringView& _rhs, bool _caseSensitive)
{
const int32_t len = _lhs.getLength();

Expand All @@ -214,14 +214,43 @@ namespace bx
}
}

for (int32_t ii = 0, num = len-1
; ii < num && *lhs == *rhs
; ++ii, ++lhs, ++rhs
)
if (_caseSensitive)
{
for (int32_t ii = 0; ii < len; ++ii)
{
if (lhs[ii] != rhs[ii])
{
return false;
}
}

return true;
}

for (int32_t ii = 0; ii < len; ++ii)
{
const char lch = lhs[ii];
const char rch = rhs[ii];
const char ll = 'A' <= lch && lch <= 'Z' ? char(lch + 0x20) : lch;
const char rl = 'A' <= rch && rch <= 'Z' ? char(rch + 0x20) : rch;

if (ll != rl)
{
return false;
}
}

return *lhs == *rhs;
return true;
}

inline constexpr bool operator==(const StringView& _lhs, const StringView& _rhs)
{
return isEqual(_lhs, _rhs);
}

inline constexpr bool operator!=(const StringView& _lhs, const StringView& _rhs)
{
return !(_lhs == _rhs);
}

inline constexpr bool overlap(const StringView& _a, const StringView& _b)
Expand Down
21 changes: 16 additions & 5 deletions include/bx/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,20 @@ namespace bx
bool m_0terminated;
};

/// Compare two string views.
/// Returns true if two string views are equal.
///
/// @param[in] _lhs Left-hand side string.
/// @param[in] _rhs Right-hand side string.
/// @param[in] _caseSensitive Use case sensitive comparison if true.
///
BX_CONSTEXPR_FUNC bool isEqual(const StringView& _lhs, const StringView& _rhs, bool _caseSensitive = true);

/// Compare two string views for equality.
constexpr bool operator==(const StringView& _lhs, const StringView& _rhs);

/// Compare two string views for inequality.
constexpr bool operator!=(const StringView& _lhs, const StringView& _rhs);

/// Returns true if two string views overlap.
constexpr bool overlap(const StringView& _a, const StringView& _b);

Expand Down Expand Up @@ -471,18 +482,18 @@ namespace bx
///
int32_t formatHumanNumber(char* _out, uint32_t _count, double _value, uint8_t _numFrac, const StringView& _unit = "", char _prefix = ' ');

///
///
int32_t formatHumanNumber(char* _out, uint32_t _count, double _value, uint8_t _numFrac, double _unitStep, const StringView& _unit, const StringView& _prefix, uint8_t _basePrefix = 0);

///
///
template<uint16_t MaxCapacityT = 32>
FixedStringT<MaxCapacityT> toHuman(uint64_t _value);

///
///
template<uint16_t MaxCapacityT = 32>
FixedStringT<MaxCapacityT> toHuman(uint64_t _value, Units::Enum _units, uint8_t _numFrac = 2);

///
///
template<uint16_t MaxCapacityT = 32>
FixedStringT<MaxCapacityT> toHuman(Ticks _value, uint8_t _numFrac = 4);

Expand Down
53 changes: 53 additions & 0 deletions tests/string_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,59 @@ TEST_CASE("strCmpI", "[string]")
REQUIRE(0 < bx::strCmpI(abvgd, empty) );
}

TEST_CASE("isEqual", "[string]")
{
// Case sensitive (default).
REQUIRE( bx::isEqual("test", "test") );
REQUIRE(!bx::isEqual("test", "Test") );
REQUIRE(!bx::isEqual("test", "testtest") );
REQUIRE(!bx::isEqual("testtest", "test") );
REQUIRE( bx::isEqual("", "") );
REQUIRE(!bx::isEqual("", "test") );
REQUIRE(!bx::isEqual("a", "A") );

// Case insensitive.
REQUIRE( bx::isEqual("test", "TEST", false) );
REQUIRE( bx::isEqual("TeSt", "tEsT", false) );
REQUIRE( bx::isEqual("a", "A", false) );
REQUIRE(!bx::isEqual("test", "testest", false) );
REQUIRE( bx::isEqual("", "", false) );

// Non-letters are unaffected by case folding.
REQUIRE( bx::isEqual("1389-[]", "1389-[]", false) );
REQUIRE(!bx::isEqual("1389-[]", "1389-{}", false) );

// Mixed string types (all implicitly convert to StringView).
const bx::StringView sv("RGBA");
const bx::StringLiteral sl("RGBA");
REQUIRE( bx::isEqual(sv, sl) );
REQUIRE( bx::isEqual(sv, "RGBA") );
REQUIRE( bx::isEqual("rgba", sl, false) );
}

TEST_CASE("operator==/operator!=", "[string]")
{
REQUIRE( bx::StringView("test") == bx::StringView("test") );
REQUIRE( bx::StringView("test") == "test" );
REQUIRE( "test" == bx::StringView("test") );
REQUIRE(!(bx::StringView("test") == "Test") );

REQUIRE( bx::StringView("test") != "Test" );
REQUIRE(!(bx::StringView("test") != "test") );
}

TEST_CASE("isEqual constexpr", "[string]")
{
STATIC_REQUIRE( bx::isEqual("1389", "1389") );
STATIC_REQUIRE(!bx::isEqual("1389", "1388") );
STATIC_REQUIRE( bx::isEqual("abvgd", "ABVGD", false) );
STATIC_REQUIRE(!bx::isEqual("abvgd", "ABVGD") );

STATIC_REQUIRE( bx::StringView("mac") == "mac" );
STATIC_REQUIRE( bx::StringView("mac") != "pod" );
STATIC_REQUIRE( bx::isEqual(bx::StringLiteral("pod"), bx::StringView("POD"), false) );
}

TEST_CASE("strCmpV", "[string]")
{
REQUIRE(0 == bx::strCmpV("test", "test") );
Expand Down
Loading