Skip to content

Commit 27a7f66

Browse files
author
ivsudarikov
committed
feat userver/universal: Improve OptionalRef compatibility with std::optional
commit_hash:4e715b5369960cf0008132503102304df9064f5c
1 parent 8283c2a commit 27a7f66

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

universal/include/userver/utils/optional_ref.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace utils {
2626
template <class T>
2727
class OptionalRef {
2828
public:
29+
using value_type = T;
30+
2931
static_assert(!std::is_reference<T>::value, "Do not use a reference for T");
3032

3133
constexpr OptionalRef() noexcept = default;
@@ -81,6 +83,15 @@ class OptionalRef {
8183
return *data_;
8284
}
8385

86+
template <typename U>
87+
constexpr T value_or(U&& default_value) const {
88+
if (!has_value()) {
89+
return std::forward<U>(default_value);
90+
}
91+
92+
return *data_;
93+
}
94+
8495
private:
8596
template <class Optional>
8697
static T* GetPointer(Optional& other) noexcept {

universal/src/utils/optional_ref_test.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ bool TestImplicitConversion(utils::OptionalRef<TestImplicit>) { return true; }
1313
TEST(OptionalRef, Constructions) {
1414
using utils::OptionalRef;
1515

16+
static_assert(std::is_same_v<typename OptionalRef<int>::value_type, int>);
17+
1618
static_assert(std::is_constructible_v<OptionalRef<int>, int&>);
1719
static_assert(std::is_constructible_v<OptionalRef<const int>, int&>);
1820
static_assert(std::is_constructible_v<OptionalRef<const int>, const int&>);
@@ -150,14 +152,38 @@ TEST(OptionalRef, Methods) {
150152
EXPECT_TRUE(a1.has_value());
151153

152154
EXPECT_EQ(*a1, a1_val);
155+
EXPECT_EQ(a1.value_or(a1_val + 1), a1_val);
153156
EXPECT_EQ(a1.value(), a1_val);
154157

155158
const utils::OptionalRef<int> def;
156159
EXPECT_FALSE(def);
157160
EXPECT_FALSE(def.has_value());
161+
EXPECT_EQ(def.value_or(1), 1);
158162
EXPECT_THROW(def.value(), std::bad_optional_access);
159163
}
160164

165+
TEST(OptionalRef, ValueOr) {
166+
struct TestMove {
167+
enum ObjectOrigin : std::uint8_t { kConstructed, kCopyConstructed, kMoveConstructed };
168+
ObjectOrigin origin{kConstructed};
169+
TestMove() = default;
170+
TestMove(const TestMove&)
171+
: origin(kCopyConstructed)
172+
{}
173+
TestMove(TestMove&&) noexcept
174+
: origin(kMoveConstructed)
175+
{}
176+
TestMove& operator=(const TestMove&) = delete;
177+
TestMove& operator=(TestMove&&) = delete;
178+
};
179+
180+
const utils::OptionalRef<TestMove> opt;
181+
EXPECT_FALSE(opt.has_value());
182+
const TestMove default_value = opt.value_or(TestMove{});
183+
EXPECT_EQ(default_value.origin, TestMove::kMoveConstructed);
184+
EXPECT_FALSE(opt.has_value());
185+
}
186+
161187
TEST(OptionalRef, ArrowOperator) {
162188
struct Object {
163189
const Object* GetThis() const noexcept { return this; }

0 commit comments

Comments
 (0)