userver: userver/utils/optional_ref.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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