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>
28public:
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 : data_(GetPointer(other)) {}
43
44 template <typename U>
45 explicit constexpr OptionalRef(std::optional<U>& other) noexcept : data_(GetPointer(other)) {}
46
47 template <typename U>
48 explicit constexpr OptionalRef(const std::optional<U>&&) noexcept {
49 static_assert(!sizeof(U), "Forming a reference to a temporary");
50 }
51
52 template <typename U>
53 explicit constexpr OptionalRef(const boost::optional<U>& other) noexcept : data_(GetPointer(other)) {}
54
55 template <typename U>
56 explicit constexpr OptionalRef(boost::optional<U>& other) noexcept : data_(GetPointer(other)) {}
57
58 template <typename U>
59 explicit constexpr OptionalRef(const boost::optional<U>&&) noexcept {
60 static_assert(!sizeof(U), "Forming a reference to a temporary");
61 }
62
63 constexpr bool has_value() const noexcept { return !!data_; }
64 constexpr explicit operator bool() const noexcept { return has_value(); }
65
66 constexpr T* operator->() const {
67 UASSERT(data_);
68 return data_;
69 }
70
71 constexpr T& operator*() const {
72 UASSERT(data_);
73 return *data_;
74 }
75
76 constexpr T& value() const {
77 if (!has_value()) {
78 throw std::bad_optional_access();
79 }
80
81 return *data_;
82 }
83
84private:
85 template <class Optional>
86 static T* GetPointer(Optional& other) noexcept {
87 using ValueType = decltype(*other);
88 static_assert(
89 std::is_const<T>::value || !std::is_const<ValueType>::value,
90 "Attempt to initialize non-const T from a const optional value"
91 );
92
93 if (!other) {
94 return nullptr;
95 }
96
97 auto& value = *other;
98 return &value;
99 }
100
101 T* const data_ = nullptr;
102};
103
104template <class T, class U>
105constexpr bool operator==(OptionalRef<T> lhs, OptionalRef<U> rhs) noexcept {
106 if (!lhs || !rhs) return !lhs && !rhs;
107 return *lhs == *rhs;
108}
109
110template <class T, class U>
111constexpr bool operator!=(OptionalRef<T> lhs, OptionalRef<U> rhs) noexcept {
112 return !(lhs == rhs);
113}
114
115} // namespace utils
116
117USERVER_NAMESPACE_END