mirror of
https://github.com/transmission/transmission.git
synced 2025-12-12 20:35:49 +01:00
feat: add tr_variant::Map methods (#7910)
* feat: add tr_variant::Map::contains() * feat: add tr_variant::Map::replace_key() * fixup! feat: add tr_variant::Map::replace_key() fix readability-braces-around-statements * fixup! feat: add tr_variant::Map::contains() readability-container-contains
This commit is contained in:
@@ -99,6 +99,11 @@ public:
|
||||
return Vector::const_iterator{ const_cast<Map*>(this)->find(key) };
|
||||
}
|
||||
|
||||
[[nodiscard]] auto contains(tr_quark const key) const noexcept
|
||||
{
|
||||
return find(key) != end(); // NOLINT(readability-container-contains)
|
||||
}
|
||||
|
||||
[[nodiscard]] TR_CONSTEXPR20 auto find(std::initializer_list<tr_quark> keys) noexcept
|
||||
{
|
||||
auto constexpr Predicate = [](auto const& item, tr_quark key)
|
||||
@@ -139,6 +144,23 @@ public:
|
||||
return 0U;
|
||||
}
|
||||
|
||||
bool replace_key(tr_quark const old_key, tr_quark const new_key)
|
||||
{
|
||||
if (contains(new_key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iter = find(old_key);
|
||||
if (iter == end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->first = new_key;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_variant& operator[](tr_quark const& key)
|
||||
{
|
||||
if (auto const iter = find(key); iter != end())
|
||||
|
||||
@@ -556,6 +556,138 @@ TEST_F(VariantTest, dictFindType)
|
||||
EXPECT_EQ(ExpectedInt, *i);
|
||||
}
|
||||
|
||||
TEST_F(VariantTest, mapContains)
|
||||
{
|
||||
auto const key_bool = tr_quark_new("contains-bool"sv);
|
||||
auto const key_int = tr_quark_new("contains-int"sv);
|
||||
auto const key_double = tr_quark_new("contains-double"sv);
|
||||
auto const key_string = tr_quark_new("contains-string"sv);
|
||||
auto const key_vector = tr_quark_new("contains-vector"sv);
|
||||
auto const key_map = tr_quark_new("contains-map"sv);
|
||||
auto const key_missing = tr_quark_new("contains-missing"sv);
|
||||
auto const nested_key = tr_quark_new("contains-nested"sv);
|
||||
|
||||
// populate a test map
|
||||
|
||||
auto top = tr_variant::make_map(6U);
|
||||
auto* const map = top.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(map, nullptr);
|
||||
|
||||
map->try_emplace(key_bool, true);
|
||||
map->try_emplace(key_int, int64_t{ 42 });
|
||||
map->try_emplace(key_double, 4.2);
|
||||
map->try_emplace(key_string, "needle"sv);
|
||||
|
||||
auto vec = tr_variant::Vector{};
|
||||
vec.emplace_back(true);
|
||||
vec.emplace_back(int64_t{ 7 });
|
||||
map->try_emplace(key_vector, std::move(vec));
|
||||
|
||||
auto nested = tr_variant::make_map(1U);
|
||||
auto* nested_map = nested.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(nested_map, nullptr);
|
||||
nested_map->try_emplace(nested_key, "nested"sv);
|
||||
map->try_emplace(key_map, std::move(nested));
|
||||
|
||||
// ---
|
||||
|
||||
// test: returns true for entries that exist
|
||||
EXPECT_TRUE(map->contains(key_bool));
|
||||
EXPECT_TRUE(map->contains(key_double));
|
||||
EXPECT_TRUE(map->contains(key_int));
|
||||
EXPECT_TRUE(map->contains(key_map));
|
||||
EXPECT_TRUE(map->contains(key_string));
|
||||
EXPECT_TRUE(map->contains(key_vector));
|
||||
|
||||
// test: returns false for entries that never existed
|
||||
EXPECT_FALSE(map->contains(key_missing));
|
||||
|
||||
// test: returns false for entries that were removed
|
||||
EXPECT_EQ(1U, map->erase(key_vector));
|
||||
EXPECT_FALSE(map->contains(key_vector));
|
||||
}
|
||||
|
||||
TEST_F(VariantTest, mapReplaceKey)
|
||||
{
|
||||
auto constexpr IntVal = int64_t{ 73 };
|
||||
auto const key_bool = tr_quark_new("replace-bool"sv);
|
||||
auto const key_int = tr_quark_new("replace-int"sv);
|
||||
auto const key_double = tr_quark_new("replace-double"sv);
|
||||
auto const key_string = tr_quark_new("replace-string"sv);
|
||||
auto const key_vector = tr_quark_new("replace-vector"sv);
|
||||
auto const key_map = tr_quark_new("replace-map"sv);
|
||||
auto const key_duplicate = tr_quark_new("replace-duplicate"sv);
|
||||
auto const key_missing_src = tr_quark_new("replace-missing-src"sv);
|
||||
auto const key_missing_tgt = tr_quark_new("replace-missing-tgt"sv);
|
||||
auto const key_replacement = tr_quark_new("replace-string-new"sv);
|
||||
auto const key_nested = tr_quark_new("replace-nested"sv);
|
||||
|
||||
// populate a sample map
|
||||
|
||||
auto top = tr_variant::make_map(7U);
|
||||
auto* const map = top.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(map, nullptr);
|
||||
|
||||
map->try_emplace(key_bool, true);
|
||||
map->try_emplace(key_int, IntVal);
|
||||
map->try_emplace(key_double, 7.3);
|
||||
map->try_emplace(key_string, "string"sv);
|
||||
|
||||
auto vec = tr_variant::Vector{};
|
||||
vec.emplace_back(false);
|
||||
vec.emplace_back(int64_t{ 99 });
|
||||
map->try_emplace(key_vector, std::move(vec));
|
||||
|
||||
auto nested = tr_variant::make_map(1U);
|
||||
auto* nested_map = nested.get_if<tr_variant::Map>();
|
||||
ASSERT_NE(nested_map, nullptr);
|
||||
nested_map->try_emplace(key_nested, "nested"sv);
|
||||
map->try_emplace(key_map, std::move(nested));
|
||||
|
||||
map->try_emplace(key_duplicate, "occupied"sv);
|
||||
|
||||
// ---
|
||||
|
||||
// test: neither src nor tgt exist
|
||||
auto const serde = tr_variant_serde::json();
|
||||
auto expected = serde.to_string(top);
|
||||
EXPECT_FALSE(map->contains(key_missing_src));
|
||||
EXPECT_FALSE(map->contains(key_missing_tgt));
|
||||
EXPECT_FALSE(map->replace_key(key_missing_src, key_missing_tgt));
|
||||
EXPECT_FALSE(map->contains(key_missing_src));
|
||||
EXPECT_FALSE(map->contains(key_missing_tgt));
|
||||
auto actual = serde.to_string(top);
|
||||
EXPECT_EQ(expected, actual); // confirm variant is unchanged
|
||||
|
||||
// test: src doesn't exist
|
||||
expected = serde.to_string(top);
|
||||
EXPECT_FALSE(map->contains(key_missing_src));
|
||||
EXPECT_EQ(IntVal, map->value_if<int64_t>(key_int).value_or(!IntVal));
|
||||
EXPECT_FALSE(map->replace_key(key_missing_src, key_int));
|
||||
EXPECT_FALSE(map->contains(key_missing_src));
|
||||
EXPECT_EQ(IntVal, map->value_if<int64_t>(key_int).value_or(!IntVal));
|
||||
actual = serde.to_string(top);
|
||||
EXPECT_EQ(expected, actual); // confirm variant is unchanged
|
||||
|
||||
// test: tgt already exists
|
||||
expected = serde.to_string(top);
|
||||
EXPECT_TRUE(map->contains(key_int));
|
||||
EXPECT_TRUE(map->contains(key_string));
|
||||
EXPECT_FALSE(map->replace_key(key_int, key_string));
|
||||
EXPECT_TRUE(map->contains(key_int));
|
||||
EXPECT_TRUE(map->contains(key_string));
|
||||
actual = serde.to_string(top);
|
||||
EXPECT_EQ(expected, actual); // confirm variant is unchanged
|
||||
|
||||
// test: successful replacement
|
||||
EXPECT_TRUE(map->contains(key_int));
|
||||
EXPECT_FALSE(map->contains(key_replacement));
|
||||
EXPECT_TRUE(map->replace_key(key_int, key_replacement));
|
||||
EXPECT_FALSE(map->contains(key_int));
|
||||
EXPECT_TRUE(map->contains(key_replacement));
|
||||
EXPECT_EQ(IntVal, map->value_if<int64_t>(key_replacement).value_or(!IntVal));
|
||||
}
|
||||
|
||||
TEST_F(VariantTest, variantFromBufFuzz)
|
||||
{
|
||||
auto benc_serde = tr_variant_serde::json();
|
||||
|
||||
Reference in New Issue
Block a user