Skip to content

Commit 0be5ca5

Browse files
authored
Don't change key ordering on FlatMap::erase (#1840)
Fixes: #1839 Signed-off-by: Juan Cruz Viotti <[email protected]>
1 parent 80de55d commit 0be5ca5

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

src/core/json/include/sourcemeta/core/json_object.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#ifndef SOURCEMETA_CORE_JSON_OBJECT_H_
22
#define SOURCEMETA_CORE_JSON_OBJECT_H_
33

4-
#include <algorithm> // std::swap
54
#include <cassert> // assert
65
#include <cstddef> // std::size_t
76
#include <initializer_list> // std::initializer_list
@@ -294,18 +293,18 @@ template <typename Key, typename Value, typename Hash> class FlatMap {
294293
const auto current_size{this->size()};
295294

296295
if (this->hasher.is_perfect(key_hash)) {
297-
for (auto &entry : this->data) {
298-
if (entry.hash == key_hash) {
299-
std::swap(entry, this->data.back());
300-
this->data.pop_back();
296+
for (auto iterator = this->data.begin(); iterator != this->data.end();
297+
++iterator) {
298+
if (iterator->hash == key_hash) {
299+
this->data.erase(iterator);
301300
return current_size - 1;
302301
}
303302
}
304303
} else {
305-
for (auto &entry : this->data) {
306-
if (entry.hash == key_hash && entry.first == key) {
307-
std::swap(entry, this->data.back());
308-
this->data.pop_back();
304+
for (auto iterator = this->data.begin(); iterator != this->data.end();
305+
++iterator) {
306+
if (iterator->hash == key_hash && iterator->first == key) {
307+
this->data.erase(iterator);
309308
return current_size - 1;
310309
}
311310
}

test/json/json_object_test.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,3 +940,23 @@ TEST(JSON_object, try_assign_before_empty) {
940940
EXPECT_EQ(properties.at(0), "baz");
941941
EXPECT_EQ(document.at("baz").to_integer(), 99);
942942
}
943+
944+
TEST(JSON_object, erase_must_not_affect_ordering) {
945+
sourcemeta::core::JSON document{{"x", sourcemeta::core::JSON{1}},
946+
{"y", sourcemeta::core::JSON{2}},
947+
{"z", sourcemeta::core::JSON{2}}};
948+
949+
auto before_iterator = document.as_object().begin();
950+
EXPECT_EQ(before_iterator->first, "x");
951+
std::advance(before_iterator, 1);
952+
EXPECT_EQ(before_iterator->first, "y");
953+
std::advance(before_iterator, 1);
954+
EXPECT_EQ(before_iterator->first, "z");
955+
956+
document.erase("x");
957+
958+
auto after_iterator = document.as_object().begin();
959+
EXPECT_EQ(after_iterator->first, "y");
960+
std::advance(after_iterator, 1);
961+
EXPECT_EQ(after_iterator->first, "z");
962+
}

0 commit comments

Comments
 (0)