Skip to content

Conversation

@slurmlord
Copy link

This PR adds the string functions startsWith, startsWithNoCase, endsWith and endsWithNoCase to WWLib/stringex.h. Supports both char* and wchar_t*.

Replaced existing functions in AsciiString with calls to the corresponding new implementations:
AsciiString::startsWith
AsciiString::startsWithNoCase
AsciiString::endsWith
AsciiString::endsWithNoCase

Also added the same functions for UnicodeString.
This was split out from #1594 where the need for a endsWithNoCase for wchar_t surfaced.

@slurmlord slurmlord changed the title feat(string): Add generic string startWith/endsWith implementations feat(string): Add generic string startsWith/endsWith implementations Nov 23, 2025
@slurmlord slurmlord marked this pull request as ready for review November 23, 2025 20:17

const size_t strlen = strlen_t(str);
const size_t smallen = strlen_t(smaller);
if (strlen < smallen)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<=

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the comment (originally from the AsciiString implementation). The check needs to be < so that startsWith("hello", "hello) == true which is the current behavior.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I read that wrong and original code is also like that. It is good to preserve the original implementation as much as possible because any discrepancy here could potentially cause mismatching in logic.

}

inline int strncmp_t(const char *str1, const char *str2, size_t maxcount) { return ::strncmp(str1, str2, maxcount); };
inline int strncmp_t(const wchar_t *str1, const wchar_t *str2, size_t maxcount) { return ::wcsncmp(str1, str2, maxcount); };
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you measure if this is really faster?

Generally I prefer to have same code paths on all platforms, so that there are less potential discrepancies in behavior.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with comparing 50 char strings.
When both strings were random, the strnicmp_t in this file was about 1/3 faster. Typically ~2100 vs ~3200 microseconds for 100000 iterations.
When testing the worst case, comparing one string with itself, the built-in strnicmp was about 2x faster. In the area of ~8500 vs ~13600 microseconds.
I guess it comes down to if we expect strings to match or not :) But I'll remove these specializations for consistency's sake .

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the original impls use simd to load multiple bytes in one go.

Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good

@xezon xezon added Minor Severity: Minor < Major < Critical < Blocker Refactor Edits the code with insignificant behavior changes, is never user facing labels Nov 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Minor Severity: Minor < Major < Critical < Blocker Refactor Edits the code with insignificant behavior changes, is never user facing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants