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>,
24 "SharedReadablePtr already adds `const` to `T`");
25 static_assert(!std::is_reference_v<T>,
26 "SharedReadablePtr does not work with references");
27
28 public:
29 using Base = std::shared_ptr<const T>;
30 using MutableBase = std::shared_ptr<T>;
31 using Weak = typename Base::weak_type;
32 using Unique = std::unique_ptr<const T>;
33 using element_type = T;
34
35 SharedReadablePtr(const SharedReadablePtr& ptr) noexcept = default;
36 SharedReadablePtr(SharedReadablePtr&& ptr) noexcept = default;
37
38 constexpr SharedReadablePtr(std::nullptr_t) noexcept : base_(nullptr) {}
39
40 SharedReadablePtr& operator=(const SharedReadablePtr& ptr) noexcept = default;
41 SharedReadablePtr& operator=(SharedReadablePtr&& ptr) noexcept = default;
42
43 SharedReadablePtr(const Base& ptr) noexcept : base_(ptr) {}
44
45 SharedReadablePtr(Base&& ptr) noexcept : base_(std::move(ptr)) {}
46
47 SharedReadablePtr(const MutableBase& ptr) noexcept : base_(ptr) {}
48
49 SharedReadablePtr(MutableBase&& ptr) noexcept : base_(std::move(ptr)) {}
50
51 SharedReadablePtr(Unique&& ptr) noexcept : base_(std::move(ptr)) {}
52
53 SharedReadablePtr& operator=(const Base& ptr) noexcept {
54 base_ = ptr;
55 return *this;
56 }
57
58 SharedReadablePtr& operator=(Base&& ptr) noexcept {
59 base_ = std::move(ptr);
60 return *this;
61 }
62
63 SharedReadablePtr& operator=(const MutableBase& ptr) noexcept {
64 base_ = ptr;
65 return *this;
66 }
67
68 SharedReadablePtr& operator=(MutableBase&& ptr) noexcept {
69 base_ = std::move(ptr);
70 return *this;
71 }
72
73 SharedReadablePtr& operator=(std::nullptr_t) noexcept {
74 Reset();
75 return *this;
76 }
77
78 const T* Get() const& noexcept { return base_.get(); }
79
80 const T& operator*() const& noexcept { return *base_; }
81
82 const T& operator*() && { ReportMisuse(); }
83
84 const T* operator->() const& noexcept { return base_.get(); }
85
86 const T* operator->() && { ReportMisuse(); }
87
88 operator const Base&() const& noexcept { return base_; }
89
90 operator const Base&() && { ReportMisuse(); }
91
92 operator Weak() const& noexcept { return base_; }
93
94 operator Weak() && { ReportMisuse(); }
95
96 explicit operator bool() const noexcept { return !!base_; }
97
98 bool operator==(const SharedReadablePtr<T>& other) const {
99 return base_ == other.base_;
100 }
101
102 bool operator!=(const SharedReadablePtr<T>& other) const {
103 return !(*this == other);
104 }
105
106 void Reset() noexcept { base_.reset(); }
107
108 private:
109 [[noreturn]] static void ReportMisuse() {
110 static_assert(!sizeof(T), "keep the pointer before using, please");
111 }
112
113 Base base_;
114};
115
116template <typename T>
117bool operator==(const SharedReadablePtr<T>& ptr, std::nullptr_t) {
118 return !ptr;
119}
120
121template <typename T>
122bool operator==(std::nullptr_t, const SharedReadablePtr<T>& ptr) {
123 return !ptr;
124}
125
126template <typename T>
127bool operator!=(const SharedReadablePtr<T>& ptr, std::nullptr_t) {
128 return !(ptr == nullptr);
129}
130
131template <typename T>
132bool operator!=(std::nullptr_t, const SharedReadablePtr<T>& ptr) {
133 return !(nullptr == ptr);
134}
135
136template <typename T, typename... Args>
137SharedReadablePtr<T> MakeSharedReadable(Args&&... args) {
138 return SharedReadablePtr<T>{std::make_shared<T>(std::forward<Args>(args)...)};
139}
140
141} // namespace utils
142
143USERVER_NAMESPACE_END