Branch data Line data Source code
1 : : // Copyright (c) The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or https://opensource.org/license/mit/.
4 : :
5 : : #ifndef BITCOIN_UTIL_NOT_NULL_H
6 : : #define BITCOIN_UTIL_NOT_NULL_H
7 : :
8 : : #include <attributes.h>
9 : : #include <util/check.h>
10 : :
11 : : #include <compare>
12 : : #include <concepts>
13 : : #include <cstddef>
14 : : #include <functional>
15 : : #include <memory>
16 : : #include <type_traits>
17 : : #include <utility>
18 : :
19 : : namespace util {
20 : :
21 : : /// NotNull is intended to be used to denote that a smart pointer type can not
22 : : /// hold a nullptr value.
23 : : ///
24 : : /// The type is more useful, the earlier in the lifetime of a pointer it is
25 : : /// used. So instead of passing an existing pointer into NotNull, it is
26 : : /// recommended to use the type when creating the smart pointer. E.g.:
27 : : ///
28 : : /// util::NotNull p{std::make_shared<Thing>()};
29 : : ///
30 : : /// This makes it obvious that a pointer really is not null and that the
31 : : /// constructor will not fail.
32 : : ///
33 : : /// NotNull does *not* support raw pointers.
34 : : /// The C++ language provides raw references for this use case, and the C++
35 : : /// standard library provides std::reference_wrapper, where raw references can
36 : : /// not be used.
37 : : ///
38 : : /// This type is movable, meaning that the inner pointer *is* null after a
39 : : /// move. Clang-tidy static analysis is used to enforce use-after-move
40 : : /// violations, so that the null should never be observed. Moreover, the
41 : : /// runtime Assume check in the get() member function will ensure the same.
42 : : template <class T>
43 : : requires std::is_class_v<T> && requires(T t) { { t != nullptr } -> std::convertible_to<bool>; }
44 [ + + - + : 80785 : class NotNull
- + + + ]
[ + - + - ]
[ - + + -
- - - + +
- - - - +
- + - + -
+ - + - +
- + - - +
- ][ + - +
- + - - -
+ - - + +
- - + + -
+ - + - -
- - - - -
# # ][ + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - # # #
# ][ - + -
+ - + +
+ ]
45 : : {
46 : : public:
47 : : template <std::convertible_to<T> U>
48 : : requires(!std::same_as<std::remove_cvref_t<U>, NotNull>)
49 : 76475 : constexpr explicit NotNull(U&& u) noexcept(std::is_nothrow_constructible_v<T, U&&>)
50 [ + + ]: 76475 : : m_ptr(std::forward<U>(u))
51 : : {
52 [ + + ]: 76475 : Assert(m_ptr != nullptr);
53 [ - + ]: 76475 : }
54 : :
55 : : template <class U>
56 : : requires std::move_constructible<U> && std::constructible_from<T, U&&>
57 : : constexpr explicit(!std::convertible_to<U, T>)
58 : 1905 : NotNull(NotNull<U>&& other) noexcept(std::is_nothrow_move_constructible_v<U> && std::is_nothrow_constructible_v<T, U&&>)
59 : 1905 : : m_ptr(std::move(other).get())
60 : : {
61 : 1905 : Assume(m_ptr != nullptr);
62 : 1905 : }
63 : :
64 : : template <class U>
65 : : requires std::convertible_to<const U&, T>
66 : 1 : constexpr NotNull(const NotNull<U>& other) noexcept(std::is_nothrow_constructible_v<T, const U&>)
67 : 2 : : m_ptr(other.get())
68 : : {
69 : 1 : Assume(m_ptr != nullptr);
70 : 1 : }
71 : :
72 : : NotNull(std::nullptr_t) = delete;
73 : : NotNull& operator=(std::nullptr_t) = delete;
74 : :
75 [ + - + - ]: 1656 : constexpr NotNull(NotNull&&) = default;
76 [ - + ]: 3 : constexpr NotNull& operator=(NotNull&&) = default;
77 [ + - + - ]: 4 : constexpr NotNull(const NotNull&) = default;
78 : : constexpr NotNull& operator=(const NotNull&) = default;
79 : :
80 [ + - + - ]: 10800422 : constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); }
81 : 49246 : constexpr T get() && noexcept(std::is_nothrow_move_constructible_v<T>)
82 : : requires std::move_constructible<T>
83 : : {
84 : 49244 : return std::move(Assume(m_ptr));
85 : : }
86 : :
87 [ + - + - : 3480056 : constexpr decltype(auto) operator->() const LIFETIMEBOUND { return get(); }
+ - # # #
# ][ + - +
- + - + -
+ - ][ + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
[ + - # # ]
[ + - + - ]
88 [ + - + - : 7264003 : constexpr decltype(auto) operator*() const LIFETIMEBOUND { return *get(); }
+ - + + +
+ + - + +
+ - + - +
+ + - - +
- + - + +
- ][ + - +
- + - + -
+ - # # ]
[ + - + -
+ - - + +
+ + - + +
+ - + - +
+ + - - +
- + - + +
- ]
89 : :
90 : : constexpr operator T() const& noexcept(std::is_nothrow_copy_constructible_v<T>)
91 : : requires std::copy_constructible<T>
92 : : {
93 : : return get();
94 : : }
95 : 47340 : constexpr operator T() && noexcept(std::is_nothrow_move_constructible_v<T>)
96 : : requires std::move_constructible<T>
97 : : {
98 : 47340 : return std::move(*this).get();
99 : : }
100 : :
101 : : template <class U>
102 : 4 : constexpr auto operator<=>(const NotNull<U>& other) const
103 : : {
104 : 4 : return std::compare_three_way{}(get(), other.get());
105 : : }
106 : : template <class U>
107 : 2 : constexpr bool operator==(const NotNull<U>& other) const
108 : : {
109 : 2 : return get() == other.get();
110 : : }
111 : :
112 : : private:
113 : : T m_ptr;
114 : : };
115 : :
116 : : template <class T>
117 : : NotNull(T) -> NotNull<T>;
118 : :
119 : : template <typename T, typename Deleter = std::default_delete<T>>
120 : : using NotNullUniquePtr = NotNull<std::unique_ptr<T, Deleter>>;
121 : :
122 : : template <typename T>
123 : : using NotNullSharedPtr = NotNull<std::shared_ptr<T>>;
124 : :
125 : : } // namespace util
126 : :
127 : : template <class T>
128 : : struct std::hash<util::NotNull<T>> {
129 [ - - - - : 4 : std::size_t operator()(const util::NotNull<T>& v) const noexcept
+ + ]
130 : : {
131 [ - - - - : 4 : return std::hash<T>{}(v.get());
+ + ]
132 : : }
133 : : };
134 : :
135 : : #endif // BITCOIN_UTIL_NOT_NULL_H
|