From b953fecc242892e732c921110c50d2ac2b7a2a59 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Thu, 10 Jul 2025 11:53:00 -0400 Subject: [PATCH] Implement a `JSON::erase_if` method for arrays Fixes: https://github.com/sourcemeta/core/issues/1834 Signed-off-by: Juan Cruz Viotti --- .../json/include/sourcemeta/core/json_value.h | 17 ++++++++ src/core/json/json_value.cc | 6 +++ test/json/json_array_test.cc | 42 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/src/core/json/include/sourcemeta/core/json_value.h b/src/core/json/include/sourcemeta/core/json_value.h index 4fbb49c6a..71d50d26b 100644 --- a/src/core/json/include/sourcemeta/core/json_value.h +++ b/src/core/json/include/sourcemeta/core/json_value.h @@ -1443,6 +1443,23 @@ class SOURCEMETA_CORE_JSON_EXPORT JSON { auto erase(typename Array::const_iterator first, typename Array::const_iterator last) -> typename Array::iterator; + /// This method deletes a set of array elements given a predicate. For + /// example: + /// + /// ```cpp + /// #include + /// #include + /// + /// sourcemeta::core::JSON array = + /// sourcemeta::core::parse_json("[ 1, 2, 3 ]"); + /// array.erase_if(array, + /// [](const auto &item) { return item.to_integer() % 2 == 0; }); + /// assert(array.size(), 2); + /// assert(array.at(0), 1); + /// assert(array.at(1), 3); + /// ``` + auto erase_if(const std::function &predicate) -> void; + /// This method deletes all members of an object or all elements of an array, /// leaving them empty. For example: /// diff --git a/src/core/json/json_value.cc b/src/core/json/json_value.cc index bfab55ed9..991623d71 100644 --- a/src/core/json/json_value.cc +++ b/src/core/json/json_value.cc @@ -852,6 +852,12 @@ auto JSON::erase(typename JSON::Array::const_iterator first, return this->data_array.data.erase(first, last); } +auto JSON::erase_if(const std::function &predicate) + -> void { + assert(this->is_array()); + std::erase_if(this->data_array.data, predicate); +} + auto JSON::clear() -> void { if (this->is_object()) { this->data_object.data.clear(); diff --git a/test/json/json_array_test.cc b/test/json/json_array_test.cc index 1834aa2ab..477bd6ab7 100644 --- a/test/json/json_array_test.cc +++ b/test/json/json_array_test.cc @@ -534,3 +534,45 @@ TEST(JSON_array, sort_object_items) { EXPECT_EQ(document, expected); } + +TEST(JSON_array, erase_if_some) { + auto document = sourcemeta::core::parse_json(R"JSON([ + 1, 2, 3, 4, 5 + ])JSON"); + + document.erase_if([](const auto &item) { + return item.is_integer() && item.to_integer() % 2 == 0; + }); + + const auto expected = sourcemeta::core::parse_json(R"JSON([ + 1, 3, 5 + ])JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSON_array, erase_if_none) { + auto document = sourcemeta::core::parse_json(R"JSON([ + 1, 2, 3, 4, 5 + ])JSON"); + + document.erase_if([](const auto &item) { return item.is_boolean(); }); + + const auto expected = sourcemeta::core::parse_json(R"JSON([ + 1, 2, 3, 4, 5 + ])JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSON_array, erase_if_all) { + auto document = sourcemeta::core::parse_json(R"JSON([ + 1, 2, 3, 4, 5 + ])JSON"); + + document.erase_if([](const auto &item) { return item.is_integer(); }); + + const auto expected = sourcemeta::core::parse_json(R"JSON([])JSON"); + + EXPECT_EQ(document, expected); +}