From b9622c0ef0ac63a46404b2ead9c8ed2c804626ad Mon Sep 17 00:00:00 2001 From: Artyom Kolpakov Date: Sat, 25 Apr 2026 01:26:09 +0000 Subject: [PATCH 1/2] fix universal: fix initialization of default values in FindOrDefault --- universal/include/userver/utils/algo.hpp | 6 ++++-- universal/src/utils/algo_test.cpp | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/universal/include/userver/utils/algo.hpp b/universal/include/userver/utils/algo.hpp index 032fa3a54ec0..f4ad4000da3e 100644 --- a/universal/include/userver/utils/algo.hpp +++ b/universal/include/userver/utils/algo.hpp @@ -57,7 +57,8 @@ auto* FindOrNullptr(Container& container, const Key& key) { template auto FindOrDefault(Container& container, const Key& key, Default&& def) { const auto* ptr = USERVER_NAMESPACE::utils::FindOrNullptr(container, key); - return (ptr ? *ptr : decltype(*ptr){std::forward(def)}); + using R = std::remove_cvref_t; + return (ptr ? *ptr : R(std::forward(def))); } /// @brief Returns default value if no key in associative container, otherwise @@ -65,7 +66,8 @@ auto FindOrDefault(Container& container, const Key& key, Default&& def) { template auto FindOrDefault(Container& container, const Key& key) { const auto* ptr = USERVER_NAMESPACE::utils::FindOrNullptr(container, key); - return (ptr ? *ptr : decltype(*ptr){}); + using R = std::remove_cvref_t; + return (ptr ? *ptr : R()); } /// @brief Returns std::nullopt if no key in associative container, otherwise diff --git a/universal/src/utils/algo_test.cpp b/universal/src/utils/algo_test.cpp index 28d1005e9d33..ee5aee3ed516 100644 --- a/universal/src/utils/algo_test.cpp +++ b/universal/src/utils/algo_test.cpp @@ -48,21 +48,26 @@ TEST(UtilsAlgo, FindOrNullptrSets) { TEST(UtilsAlgo, FindOrDefaultMaps) { constexpr int kFallback = 42; + constexpr int kDefault = int(); std::map m = {{"1", 2}}; std::unordered_map um = {{"1", 2}}; EXPECT_EQ(utils::FindOrDefault(m, "2", kFallback), kFallback); EXPECT_EQ(utils::FindOrDefault(um, "2", kFallback), kFallback); - ASSERT_EQ(utils::FindOrDefault(m, "1", kFallback), 2); - ASSERT_EQ(utils::FindOrDefault(um, "1", kFallback), 2); - EXPECT_EQ(utils::FindOrDefault(m, "1", kFallback), 2); EXPECT_EQ(utils::FindOrDefault(um, "1", kFallback), 2); + + EXPECT_EQ(utils::FindOrDefault(m, "2"), kDefault); + EXPECT_EQ(utils::FindOrDefault(um, "2"), kDefault); + + EXPECT_EQ(utils::FindOrDefault(m, "1"), 2); + EXPECT_EQ(utils::FindOrDefault(um, "1"), 2); } TEST(UtilsAlgo, FindOrDefaultSets) { constexpr int kFallback = 42; + constexpr int kDefault = int(); std::set s = {1}; std::unordered_set us = {1}; @@ -71,6 +76,12 @@ TEST(UtilsAlgo, FindOrDefaultSets) { EXPECT_EQ(utils::FindOrDefault(s, 1, kFallback), 1); EXPECT_EQ(utils::FindOrDefault(us, 1, kFallback), 1); + + EXPECT_EQ(utils::FindOrDefault(s, 2), kDefault); + EXPECT_EQ(utils::FindOrDefault(us, 2), kDefault); + + EXPECT_EQ(utils::FindOrDefault(s, 1), 1); + EXPECT_EQ(utils::FindOrDefault(us, 1), 1); } TEST(UtilsAlgo, FindOptionalMaps) { From 14f9af8547f53e7708aabdc37e5e4ad906f52b43 Mon Sep 17 00:00:00 2001 From: Artyom Kolpakov Date: Sun, 26 Apr 2026 12:08:50 +0000 Subject: [PATCH 2/2] fix universal: add more tests for FindOrDefault --- universal/src/utils/algo_test.cpp | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/universal/src/utils/algo_test.cpp b/universal/src/utils/algo_test.cpp index ee5aee3ed516..e0ac26976154 100644 --- a/universal/src/utils/algo_test.cpp +++ b/universal/src/utils/algo_test.cpp @@ -1,6 +1,8 @@ #include +#include #include +#include #include #include #include @@ -84,6 +86,56 @@ TEST(UtilsAlgo, FindOrDefaultSets) { EXPECT_EQ(utils::FindOrDefault(us, 1), 1); } +TEST(UtilsAlgo, FindOrDefaultNoList) { + struct List { + int val = 0; + + List() = default; + List(const List&) = default; + explicit List(int v) : val(v) {} + List(std::initializer_list) : val(-1) {} + + auto operator<=>(const List&) const = default; + }; + + constexpr int kFallback = 42; + constexpr int kDefault = List().val; + + std::map m; + std::set s; + + EXPECT_TRUE(m.empty()); + EXPECT_EQ(utils::FindOrDefault(m, 0, kFallback).val, kFallback); + EXPECT_EQ(utils::FindOrDefault(m, 0).val, kDefault); + + EXPECT_TRUE(s.empty()); + EXPECT_EQ(utils::FindOrDefault(s, List(1), kFallback).val, kFallback); + EXPECT_EQ(utils::FindOrDefault(s, List(1)).val, kDefault); +} + +TEST(UtilsAlgo, FindOrDefaultNoExtraCopies) { + struct NoCopies { + bool copy = false; + + NoCopies() = default; + NoCopies(const NoCopies&) : copy(true) {} + NoCopies(NoCopies&& that) noexcept : copy(that.copy) {} + + auto operator<=>(const NoCopies&) const = default; + }; + + std::map m; + std::set s; + + EXPECT_TRUE(m.empty()); + EXPECT_FALSE(utils::FindOrDefault(m, 0, NoCopies()).copy); + EXPECT_FALSE(utils::FindOrDefault(m, 0).copy); + + EXPECT_TRUE(s.empty()); + EXPECT_FALSE(utils::FindOrDefault(s, NoCopies(), NoCopies()).copy); + EXPECT_FALSE(utils::FindOrDefault(s, NoCopies()).copy); +} + TEST(UtilsAlgo, FindOptionalMaps) { std::map m = {{"1", 2}}; std::unordered_map um = {{"1", 2}};