userver: userver/utils/not_null.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
not_null.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/not_null.hpp
4/// @brief @copybrief utils::NotNull
5
6#include <functional>
7#include <memory>
8#include <type_traits>
9#include <utility>
10
11#include <userver/utils/assert.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace utils {
16
17/// @ingroup userver_universal userver_containers
18///
19/// @brief Restricts a pointer or smart pointer to only hold non-null values.
20template <typename T>
21class NotNull {
22 static_assert(!std::is_reference_v<T>,
23 "NotNull does not work with references");
24 static_assert(!std::is_const_v<T>);
25
26 public:
27 constexpr explicit NotNull() = delete;
28
29 constexpr explicit NotNull(const T& u) : ptr_(u) {
30 UASSERT_MSG(ptr_, "Trying to construct NotNull from null");
31 }
32
33 constexpr explicit NotNull(T&& u) : ptr_(std::move(u)) {
34 UASSERT_MSG(ptr_, "Trying to construct NotNull from null");
35 }
36
37 template <typename U,
38 typename = std::enable_if_t<std::is_convertible_v<U, T>>>
39 constexpr explicit NotNull(U&& u) : ptr_(std::forward<U>(u)) {
40 UASSERT_MSG(ptr_, "Trying to construct NotNull from null");
41 }
42
43 template <typename U,
44 typename = std::enable_if_t<std::is_convertible_v<U*, T>>>
45 constexpr /*implicit*/ NotNull(U& u) : ptr_(std::addressof(u)) {}
46
47 template <typename U,
48 typename = std::enable_if_t<std::is_convertible_v<U, T>>>
49 constexpr NotNull(const NotNull<U>& other) : ptr_(other.GetBase()) {
50 UASSERT_MSG(ptr_,
51 "Trying to construct NotNull from null (moved-from) NotNull");
52 }
53
54 template <typename U,
55 typename = std::enable_if_t<std::is_convertible_v<U, T>>>
56 constexpr NotNull(NotNull<U>&& other) : ptr_(std::move(other).GetBase()) {
57 UASSERT_MSG(ptr_,
58 "Trying to construct NotNull from null (moved-from) NotNull");
59 }
60
61 constexpr NotNull(std::nullptr_t) = delete;
62
63 NotNull(const NotNull& other) noexcept = default;
64 NotNull(NotNull&& other) noexcept = default;
65
66 NotNull& operator=(const NotNull& other) noexcept = default;
67 NotNull& operator=(NotNull&& other) noexcept = default;
68
69 constexpr NotNull& operator=(std::nullptr_t) = delete;
70
71 constexpr const T& GetBase() const& {
72 UASSERT_MSG(ptr_, "Trying to access a null (moved-from) NotNull");
73 return ptr_;
74 }
75
76 constexpr T&& GetBase() && {
77 UASSERT_MSG(ptr_, "Trying to access a null (moved-from) NotNull");
78 return std::move(ptr_);
79 }
80
81 constexpr /*implicit*/ operator const T&() const& { return GetBase(); }
82
83 constexpr /*implicit*/ operator bool() = delete;
84
85 constexpr decltype(auto) operator->() const& { return GetBase(); }
86
87 constexpr decltype(auto) operator*() const& { return *GetBase(); }
88
89 template <typename U>
90 constexpr bool operator==(const NotNull<U>& other) const& {
91 return GetBase() == other.GetBase();
92 }
93
94 template <typename U>
95 constexpr bool operator!=(const NotNull<U>& other) const& {
96 return GetBase() != other.GetBase();
97 }
98
99 private:
100 T ptr_;
101};
102
103/// @ingroup userver_universal userver_containers
104///
105/// @brief A `std::shared_ptr` that is guaranteed to be not-null.
106/// @see MakeSharedRef
107template <typename U>
108using SharedRef = NotNull<std::shared_ptr<U>>;
109
110/// @ingroup userver_universal userver_containers
111///
112/// @brief A `std::unique_ptr` that is guaranteed to be not-null.
113/// @see MakeUniqueRef
114template <typename U>
116
117/// @brief An equivalent of `std::make_shared` for SharedRef.
118template <typename U, typename... Args>
120 return SharedRef<U>{std::make_shared<U>(std::forward<Args>(args)...)};
121}
122
123/// @brief An equivalent of `std::make_unique` for UniqueRef.
124template <typename U, typename... Args>
126 return UniqueRef<U>{std::make_unique<U>(std::forward<Args>(args)...)};
127}
128
129} // namespace utils
130
131USERVER_NAMESPACE_END
132
133template <typename T>
134// NOLINTNEXTLINE(cert-dcl58-cpp)
135struct std::hash<USERVER_NAMESPACE::utils::NotNull<T>> : public std::hash<T> {
136 using std::hash<T>::hash;
137
138 auto operator()(const USERVER_NAMESPACE::utils::NotNull<T>& value) const
139 noexcept(std::is_nothrow_invocable_v<const std::hash<T>&, const T&>) {
140 return this->std::hash<T>::operator()(value.GetBase());
141 }
142};