diff --git a/Fleece/API_Impl/FLSlice.cc b/Fleece/API_Impl/FLSlice.cc index d6c1bc13..d94a3411 100644 --- a/Fleece/API_Impl/FLSlice.cc +++ b/Fleece/API_Impl/FLSlice.cc @@ -41,15 +41,28 @@ FL_ASSUME_NONNULL_BEGIN __hot bool FLSlice_Equal(FLSlice a, FLSlice b) noexcept { - return a.size == b.size && FLMemCmp(a.buf, b.buf, a.size) == 0; + if (a.size == b.size) { + if (a.size == 0) + // Check whether both slices are the nullslice or empty slices. + return (a.buf == nullptr) == (b.buf == nullptr); + else + return FLMemCmp(a.buf, b.buf, a.size) == 0; + } + return false; } - __hot int FLSlice_Compare(FLSlice a, FLSlice b) noexcept { // Optimized for speed, not simplicity! if (a.size == b.size) - return FLMemCmp(a.buf, b.buf, a.size); + if (a.size == 0) { + // Sort the nullslice before an empty slice. + if ((a.buf == nullptr) == (b.buf == nullptr)) + return 0; + else + return a.buf == nullptr ? -1 : 1; + } else + return FLMemCmp(a.buf, b.buf, a.size); else if (a.size < b.size) { int result = FLMemCmp(a.buf, b.buf, a.size); return result ? result : -1; diff --git a/Tests/API_ValueTests.cc b/Tests/API_ValueTests.cc index 8047e9ba..cc6c6b35 100644 --- a/Tests/API_ValueTests.cc +++ b/Tests/API_ValueTests.cc @@ -366,3 +366,16 @@ TEST_CASE("API MutableDict item bool conversion", "[API]") { } CHECK(dict.toJSONString() == "{\"a_key\":6}"); } + +TEST_CASE("API Mutable copy of Dict with empty string shared key", "[API]") { + auto sk = fleece::SharedKeys::create(); + auto enc = fleece::Encoder(sk); + enc.beginDict(); + enc.writeKey(""); + enc.writeNull(); + enc.endDict(); + auto doc = enc.finishDoc(); + auto copy = doc.root().asDict().mutableCopy(kFLCopyImmutables); + CHECK(copy.count() == 1); + CHECK(copy[""].type() == kFLNull); +}