userver: userver/utils/shared_readable_ptr.hpp Source File
Loading...
Searching...
No Matches
shared_readable_ptr.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/shared_readable_ptr.hpp
4/// @brief @copybrief utils::SharedReadablePtr
5
6#include <memory>
7#include <type_traits>
8
9USERVER_NAMESPACE_BEGIN
10
11namespace utils {
12
13/// @ingroup userver_universal userver_containers
14///
15/// @brief `std::shared_ptr<const T>` wrapper that makes sure that the pointer
16/// is stored before dereferencing. Protects from dangling references:
17/// @code
18/// // BAD! Result of `cache.Get()` may be destroyed after the invocation.
19/// const auto& snapshot = *cache.Get();
20/// @endcode
21template <typename T>
22class SharedReadablePtr final {
23 static_assert(!std::is_const_v<T>, "SharedReadablePtr already adds `const` to `T`");
24 static_assert(!std::is_reference_v<T>, "SharedReadablePtr does not work with references");
25
26public:
27 using Base = std::shared_ptr<const T>;
28 using MutableBase = std::shared_ptr<T>;
29 using Weak = typename Base::weak_type;
30 using Unique = std::unique_ptr<const T>;
31 using element_type = T;
32
33 SharedReadablePtr(const SharedReadablePtr& ptr) noexcept = default;
34 SharedReadablePtr(SharedReadablePtr&& ptr) noexcept = default;
35
36 constexpr SharedReadablePtr(std::nullptr_t) noexcept : base_(nullptr) {}
37
38 SharedReadablePtr& operator=(const SharedReadablePtr& ptr) noexcept = default;
39 SharedReadablePtr& operator=(SharedReadablePtr&& ptr) noexcept = default;
40
41 SharedReadablePtr(const Base& ptr) noexcept : base_(ptr) {}
42
43 SharedReadablePtr(Base&& ptr) noexcept : base_(std::move(ptr)) {}
44
45 SharedReadablePtr(const MutableBase& ptr) noexcept : base_(ptr) {}
46
47 SharedReadablePtr(MutableBase&& ptr) noexcept : base_(std::move(ptr)) {}
48
49 SharedReadablePtr(Unique&& ptr) noexcept : base_(std::move(ptr)) {}
50
51 SharedReadablePtr& operator=(const Base& ptr) noexcept {
52 base_ = ptr;
53 return *this;
54 }
55
56 SharedReadablePtr& operator=(Base&& ptr) noexcept {
57 base_ = std::move(ptr);
58 return *this;
59 }
60
61 SharedReadablePtr& operator=(const MutableBase& ptr) noexcept {
62 base_ = ptr;
63 return *this;
64 }
65
66 SharedReadablePtr& operator=(MutableBase&& ptr) noexcept {
67 base_ = std::move(ptr);
68 return *this;
69 }
70
71 SharedReadablePtr& operator=(std::nullptr_t) noexcept {
72 Reset();
73 return *this;
74 }
75
76 const T* Get() const& noexcept { return base_.get(); }
77
78 const T& operator*() const& noexcept { return *base_; }
79
80 const T& operator*() && { ReportMisuse(); }
81
82 const T* operator->() const& noexcept { return base_.get(); }
83
84 const T* operator->() && { ReportMisuse(); }
85
86 operator const Base&() const& noexcept { return base_; }
87
88 operator const Base&() && { ReportMisuse(); }
89
90 operator Weak() const& noexcept { return base_; }
91
92 operator Weak() && { ReportMisuse(); }
93
94 explicit operator bool() const noexcept { return !!base_; }
95
96 bool operator==(const SharedReadablePtr<T>& other) const { return base_ == other.base_; }
97
98 bool operator!=(const SharedReadablePtr<T>& other) const { return !(*this == other); }
99
100 void Reset() noexcept { base_.reset(); }
101
102private:
103 [[noreturn]] static void ReportMisuse() { static_assert(!sizeof(T), "keep the pointer before using, please"); }
104
105 Base base_;
106};
107
108template <typename T>
109bool operator==(const SharedReadablePtr<T>& ptr, std::nullptr_t) {
110 return !ptr;
111}
112
113template <typename T>
114bool operator==(std::nullptr_t, const SharedReadablePtr<T>& ptr) {
115 return !ptr;
116}
117
118template <typename T>
119bool operator!=(const SharedReadablePtr<T>& ptr, std::nullptr_t) {
120 return !(ptr == nullptr);
121}
122
123template <typename T>
124bool operator!=(std::nullptr_t, const SharedReadablePtr<T>& ptr) {
125 return !(nullptr == ptr);
126}
127
128template <typename T, typename... Args>
129SharedReadablePtr<T> MakeSharedReadable(Args&&... args) {
130 return SharedReadablePtr<T>{std::make_shared<T>(std::forward<Args>(args)...)};
131}
132
133} // namespace utils
134
135USERVER_NAMESPACE_END