userver: userver/utils/optional_ref.hpp Source File
Loading...
Searching...
No Matches
optional_ref.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/optional_ref.hpp
4/// @brief @copybrief utils::OptionalRef
5
6#include <optional>
7#include <type_traits>
8
9#include <boost/optional/optional_fwd.hpp>
10
11#include <userver/utils/assert.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace utils {
16
17/// @ingroup userver_universal userver_containers
18///
19/// @brief Class that behaves as a nullable reference. Main difference from the
20/// pointer - value comparison of pointed values.
21///
22/// Initializes from reference to a T or from optional<T>.
23///
24/// Once the reference is constructed it can not be changed to point to
25/// different address.
26template <class T>
28 public:
29 static_assert(!std::is_reference<T>::value, "Do not use a reference for T");
30
31 constexpr OptionalRef() noexcept = default;
32 constexpr OptionalRef(std::nullopt_t) noexcept {}
33 constexpr OptionalRef(const OptionalRef&) noexcept = default;
34 constexpr OptionalRef& operator=(const OptionalRef&) noexcept = delete;
35
36 constexpr OptionalRef(T& other) noexcept : data_(&other) {}
37
38 // Forming a reference to a temporary is forbidden
39 explicit constexpr OptionalRef(const T&&) = delete;
40
41 template <typename U>
42 explicit constexpr OptionalRef(const std::optional<U>& other) noexcept
43 : data_(GetPointer(other)) {}
44
45 template <typename U>
46 explicit constexpr OptionalRef(std::optional<U>& other) noexcept
47 : data_(GetPointer(other)) {}
48
49 template <typename U>
50 explicit constexpr OptionalRef(const std::optional<U>&&) noexcept {
51 static_assert(!sizeof(U), "Forming a reference to a temporary");
52 }
53
54 template <typename U>
55 explicit constexpr OptionalRef(const boost::optional<U>& other) noexcept
56 : data_(GetPointer(other)) {}
57
58 template <typename U>
59 explicit constexpr OptionalRef(boost::optional<U>& other) noexcept
60 : data_(GetPointer(other)) {}
61
62 template <typename U>
63 explicit constexpr OptionalRef(const boost::optional<U>&&) noexcept {
64 static_assert(!sizeof(U), "Forming a reference to a temporary");
65 }
66
67 constexpr bool has_value() const noexcept { return !!data_; }
68 constexpr explicit operator bool() const noexcept { return has_value(); }
69
70 constexpr T* operator->() const {
71 UASSERT(data_);
72 return data_;
73 }
74
75 constexpr T& operator*() const {
76 UASSERT(data_);
77 return *data_;
78 }
79
80 constexpr T& value() const {
81 if (!has_value()) {
82 throw std::bad_optional_access();
83 }
84
85 return *data_;
86 }
87
88 private:
89 template <class Optional>
90 static T* GetPointer(Optional& other) noexcept {
91 using ValueType = decltype(*other);
92 static_assert(
93 std::is_const<T>::value || !std::is_const<ValueType>::value,
94 "Attempt to initialize non-const T from a const optional value");
95
96 if (!other) {
97 return nullptr;
98 }
99
100 auto& value = *other;
101 return &value;
102 }
103
104 T* const data_ = nullptr;
105};
106
107template <class T, class U>
108constexpr bool operator==(OptionalRef<T> lhs, OptionalRef<U> rhs) noexcept {
109 if (!lhs || !rhs) return !lhs && !rhs;
110 return *lhs == *rhs;
111}
112
113template <class T, class U>
114constexpr bool operator!=(OptionalRef<T> lhs, OptionalRef<U> rhs) noexcept {
115 return !(lhs == rhs);
116}
117
118} // namespace utils
119
120USERVER_NAMESPACE_END