Address review: handle empty keys explicitly in operator<
CI / pre-commit (pull_request) Successful in 2m9s
CI / release (arm64, ubuntu-latest-arm64) (pull_request) Successful in 3m27s
CI / test (-DCMAKE_BUILD_TYPE=Debug, debug) (pull_request) Successful in 3m38s
CI / test (-DCMAKE_CXX_FLAGS=-DUSE_64_BIT=1, 64-bit-versions) (pull_request) Successful in 3m29s
CI / test (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc) (pull_request) Successful in 3m42s
CI / test (-DUSE_SIMD_FALLBACK=ON, simd-fallback) (pull_request) Successful in 3m33s
CI / release (amd64, ubuntu-latest-amd64) (pull_request) Successful in 4m55s
CI / coverage (pull_request) Successful in 3m40s

Per review feedback on the i > 0 memcmp guard: handle empty keys up
front instead, so memcmp only runs when both keys are non-empty (and
therefore have valid data pointers). An empty key is a prefix of every
key, so it sorts before any non-empty key; when both are empty, fall
back to the extra ordering. This makes the empty-vs-non-empty case
explicit rather than relying on the length check after a defaulted c = 0.
This commit is contained in:
2026-07-13 16:28:47 -04:00
parent 2231c093df
commit 494e836aae
+9 -1
View File
@@ -99,8 +99,16 @@ force_inline bool getCharacter(const KeyInfo &ki, int character,
}
bool operator<(const KeyInfo &lhs, const KeyInfo &rhs) {
// An empty key is a prefix of every key, so it sorts before any non-empty
// key. Handle empty keys up front: an empty std::span may have
// data() == nullptr, which must never be passed to memcmp.
if (lhs.key.size() == 0 || rhs.key.size() == 0) {
if (lhs.key.size() != rhs.key.size())
return lhs.key.size() < rhs.key.size();
return extra_ordering(lhs) < extra_ordering(rhs);
}
int i = std::min(lhs.key.size(), rhs.key.size());
int c = i > 0 ? memcmp(lhs.key.data(), rhs.key.data(), i) : 0;
int c = memcmp(lhs.key.data(), rhs.key.data(), i);
if (c != 0)
return c < 0;