/tmp/bitcoin/src/util/not_null.h
Line | Count | Source |
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 | | class NotNull |
45 | | { |
46 | | public: |
47 | | template <std::convertible_to<T> U> |
48 | | requires(!std::same_as<std::remove_cvref_t<U>, NotNull>) |
49 | | constexpr explicit NotNull(U&& u) noexcept(std::is_nothrow_constructible_v<T, U&&>) |
50 | 75.4k | : m_ptr(std::forward<U>(u)) |
51 | 75.4k | { |
52 | 75.4k | Assert(m_ptr != nullptr); |
53 | 75.4k | } util::NotNull<std::shared_ptr<ThreadPool>>::NotNull<std::shared_ptr<ThreadPool>>(T&&) Line | Count | Source | 50 | 1.37k | : m_ptr(std::forward<U>(u)) | 51 | 1.37k | { | 52 | 1.37k | Assert(m_ptr != nullptr); | 53 | 1.37k | } |
util::NotNull<std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>>::NotNull<std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>>(T&&) Line | Count | Source | 50 | 69.1k | : m_ptr(std::forward<U>(u)) | 51 | 69.1k | { | 52 | 69.1k | Assert(m_ptr != nullptr); | 53 | 69.1k | } |
util::NotNull<std::shared_ptr<int>>::NotNull<std::unique_ptr<int, std::default_delete<int>>>(T&&) Line | Count | Source | 50 | 1 | : m_ptr(std::forward<U>(u)) | 51 | 1 | { | 52 | 1 | Assert(m_ptr != nullptr); | 53 | 1 | } |
util::NotNull<std::unique_ptr<int, std::default_delete<int>>>::NotNull<std::unique_ptr<int, std::default_delete<int>>>(T&&) Line | Count | Source | 50 | 6 | : m_ptr(std::forward<U>(u)) | 51 | 6 | { | 52 | 6 | Assert(m_ptr != nullptr); | 53 | 6 | } |
util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyDerived>>::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyDerived>>(T&&) Line | Count | Source | 50 | 1 | : m_ptr(std::forward<U>(u)) | 51 | 1 | { | 52 | 1 | Assert(m_ptr != nullptr); | 53 | 1 | } |
util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyBase>>::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyBase>>(T&&) Line | Count | Source | 50 | 1 | : m_ptr(std::forward<U>(u)) | 51 | 1 | { | 52 | 1 | Assert(m_ptr != nullptr); | 53 | 1 | } |
util_not_null_tests.cpp:util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyDerived, std::default_delete<util_not_null_tests::check_derived::test_method()::MyDerived>>>::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyDerived, std::default_delete<util_not_null_tests::check_derived::test_method()::MyDerived>>>(T&&) Line | Count | Source | 50 | 1 | : m_ptr(std::forward<U>(u)) | 51 | 1 | { | 52 | 1 | Assert(m_ptr != nullptr); | 53 | 1 | } |
util_not_null_tests.cpp:util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>>::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>>(T&&) Line | Count | Source | 50 | 1 | : m_ptr(std::forward<U>(u)) | 51 | 1 | { | 52 | 1 | Assert(m_ptr != nullptr); | 53 | 1 | } |
util::NotNull<std::shared_ptr<int>>::NotNull<std::shared_ptr<int>&>(T&&) Line | Count | Source | 50 | 7 | : m_ptr(std::forward<U>(u)) | 51 | 7 | { | 52 | 7 | Assert(m_ptr != nullptr); | 53 | 7 | } |
util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_tsa::test_method()::Thing>>::NotNull<std::shared_ptr<util_not_null_tests::check_tsa::test_method()::Thing>>(T&&) Line | Count | Source | 50 | 1 | : m_ptr(std::forward<U>(u)) | 51 | 1 | { | 52 | 1 | Assert(m_ptr != nullptr); | 53 | 1 | } |
util::NotNull<std::unique_ptr<LevelDBContext, std::default_delete<LevelDBContext>>>::NotNull<std::unique_ptr<LevelDBContext, std::default_delete<LevelDBContext>>>(T&&) Line | Count | Source | 50 | 3.04k | : m_ptr(std::forward<U>(u)) | 51 | 3.04k | { | 52 | 3.04k | Assert(m_ptr != nullptr); | 53 | 3.04k | } |
util::NotNull<std::unique_ptr<V2Transport, std::default_delete<V2Transport>>>::NotNull<std::unique_ptr<V2Transport, std::default_delete<V2Transport>>>(T&&) Line | Count | Source | 50 | 207 | : m_ptr(std::forward<U>(u)) | 51 | 207 | { | 52 | 207 | Assert(m_ptr != nullptr); | 53 | 207 | } |
util::NotNull<std::unique_ptr<V1Transport, std::default_delete<V1Transport>>>::NotNull<std::unique_ptr<V1Transport, std::default_delete<V1Transport>>>(T&&) Line | Count | Source | 50 | 1.61k | : m_ptr(std::forward<U>(u)) | 51 | 1.61k | { | 52 | 1.61k | Assert(m_ptr != nullptr); | 53 | 1.61k | } |
|
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 | | NotNull(NotNull<U>&& other) noexcept(std::is_nothrow_move_constructible_v<U> && std::is_nothrow_constructible_v<T, U&&>) |
59 | 1.82k | : m_ptr(std::move(other).get()) |
60 | 1.82k | { |
61 | 1.82k | Assume(m_ptr != nullptr); |
62 | 1.82k | } util_not_null_tests.cpp:util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>>::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyDerived, std::default_delete<util_not_null_tests::check_derived::test_method()::MyDerived>>>(util::NotNull<T>&&) Line | Count | Source | 59 | 1 | : m_ptr(std::move(other).get()) | 60 | 1 | { | 61 | 1 | Assume(m_ptr != nullptr); | 62 | 1 | } |
util::NotNull<std::unique_ptr<Transport, std::default_delete<Transport>>>::NotNull<std::unique_ptr<V2Transport, std::default_delete<V2Transport>>>(util::NotNull<T>&&) Line | Count | Source | 59 | 207 | : m_ptr(std::move(other).get()) | 60 | 207 | { | 61 | 207 | Assume(m_ptr != nullptr); | 62 | 207 | } |
util::NotNull<std::unique_ptr<Transport, std::default_delete<Transport>>>::NotNull<std::unique_ptr<V1Transport, std::default_delete<V1Transport>>>(util::NotNull<T>&&) Line | Count | Source | 59 | 1.61k | : m_ptr(std::move(other).get()) | 60 | 1.61k | { | 61 | 1.61k | Assume(m_ptr != nullptr); | 62 | 1.61k | } |
|
63 | | |
64 | | template <class U> |
65 | | requires std::convertible_to<const U&, T> |
66 | | constexpr NotNull(const NotNull<U>& other) noexcept(std::is_nothrow_constructible_v<T, const U&>) |
67 | 1 | : m_ptr(other.get()) |
68 | 1 | { |
69 | 1 | Assume(m_ptr != nullptr); |
70 | 1 | } |
71 | | |
72 | | NotNull(std::nullptr_t) = delete; |
73 | | NotNull& operator=(std::nullptr_t) = delete; |
74 | | |
75 | 2.74k | constexpr NotNull(NotNull&&) = default; util::NotNull<std::shared_ptr<ThreadPool>>::NotNull(util::NotNull<std::shared_ptr<ThreadPool>>&&) Line | Count | Source | 75 | 2.74k | constexpr NotNull(NotNull&&) = default; |
util::NotNull<std::unique_ptr<int, std::default_delete<int>>>::NotNull(util::NotNull<std::unique_ptr<int, std::default_delete<int>>>&&) Line | Count | Source | 75 | 2 | constexpr NotNull(NotNull&&) = default; |
util::NotNull<std::shared_ptr<int>>::NotNull(util::NotNull<std::shared_ptr<int>>&&) Line | Count | Source | 75 | 1 | constexpr NotNull(NotNull&&) = default; |
|
76 | 4 | constexpr NotNull& operator=(NotNull&&) = default; util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyBase>>::operator=(util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyBase>>&&) Line | Count | Source | 76 | 1 | constexpr NotNull& operator=(NotNull&&) = default; |
util_not_null_tests.cpp:util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>>::operator=(util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>>&&) Line | Count | Source | 76 | 1 | constexpr NotNull& operator=(NotNull&&) = default; |
util::NotNull<std::unique_ptr<int, std::default_delete<int>>>::operator=(util::NotNull<std::unique_ptr<int, std::default_delete<int>>>&&) Line | Count | Source | 76 | 2 | constexpr NotNull& operator=(NotNull&&) = default; |
|
77 | 2 | constexpr NotNull(const NotNull&) = default; |
78 | | constexpr NotNull& operator=(const NotNull&) = default; |
79 | | |
80 | 13.7M | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); }util::NotNull<std::unique_ptr<LevelDBContext, std::default_delete<LevelDBContext>>>::get() const & Line | Count | Source | 80 | 11.0M | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util::NotNull<std::shared_ptr<ThreadPool>>::get() const & Line | Count | Source | 80 | 119k | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util::NotNull<std::unique_ptr<Transport, std::default_delete<Transport>>>::get() const & Line | Count | Source | 80 | 2.49M | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util::NotNull<std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>>::get() const & Line | Count | Source | 80 | 64.1k | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyDerived>>::get() const & Line | Count | Source | 80 | 2 | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyBase>>::get() const & Line | Count | Source | 80 | 1 | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util::NotNull<std::unique_ptr<int, std::default_delete<int>>>::get() const & Line | Count | Source | 80 | 8 | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_tsa::test_method()::Thing>>::get() const & Line | Count | Source | 80 | 1 | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
util::NotNull<std::shared_ptr<int>>::get() const & Line | Count | Source | 80 | 14 | constexpr const T& get() const& noexcept LIFETIMEBOUND { return Assume(m_ptr); } |
Unexecuted instantiation: util_not_null_tests.cpp:util::NotNull<util_not_null_tests::check_cross_type_conversion::test_method()::SomePtr>::get() const & |
81 | | constexpr T get() && noexcept(std::is_nothrow_move_constructible_v<T>) |
82 | | requires std::move_constructible<T> |
83 | 48.3k | { |
84 | 48.3k | return std::move(Assume(m_ptr)); |
85 | 48.3k | } util::NotNull<std::unique_ptr<int, std::default_delete<int>>>::get() && requires std::move_constructible<T> Line | Count | Source | 83 | 2 | { | 84 | 2 | return std::move(Assume(m_ptr)); | 85 | 2 | } |
util_not_null_tests.cpp:util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyDerived, std::default_delete<util_not_null_tests::check_derived::test_method()::MyDerived>>>::get() && requires std::move_constructible<T> Line | Count | Source | 83 | 1 | { | 84 | 1 | return std::move(Assume(m_ptr)); | 85 | 1 | } |
util_not_null_tests.cpp:util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>>::get() && requires std::move_constructible<T> Line | Count | Source | 83 | 1 | { | 84 | 1 | return std::move(Assume(m_ptr)); | 85 | 1 | } |
Unexecuted instantiation: util_not_null_tests.cpp:util::NotNull<util_not_null_tests::check_cross_type_conversion::test_method()::SomePtr>::get() && requires std::move_constructible<T> util::NotNull<std::unique_ptr<V2Transport, std::default_delete<V2Transport>>>::get() && requires std::move_constructible<T> Line | Count | Source | 83 | 207 | { | 84 | 207 | return std::move(Assume(m_ptr)); | 85 | 207 | } |
util::NotNull<std::unique_ptr<V1Transport, std::default_delete<V1Transport>>>::get() && requires std::move_constructible<T> Line | Count | Source | 83 | 1.61k | { | 84 | 1.61k | return std::move(Assume(m_ptr)); | 85 | 1.61k | } |
util::NotNull<std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>>::get() && requires std::move_constructible<T> Line | Count | Source | 83 | 46.5k | { | 84 | 46.5k | return std::move(Assume(m_ptr)); | 85 | 46.5k | } |
|
86 | | |
87 | 2.68M | constexpr decltype(auto) operator->() const LIFETIMEBOUND { return get(); }util::NotNull<std::shared_ptr<ThreadPool>>::operator->() const Line | Count | Source | 87 | 119k | constexpr decltype(auto) operator->() const LIFETIMEBOUND { return get(); } |
util::NotNull<std::unique_ptr<Transport, std::default_delete<Transport>>>::operator->() const Line | Count | Source | 87 | 2.49M | constexpr decltype(auto) operator->() const LIFETIMEBOUND { return get(); } |
util::NotNull<std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>>::operator->() const Line | Count | Source | 87 | 64.1k | constexpr decltype(auto) operator->() const LIFETIMEBOUND { return get(); } |
|
88 | 11.0M | constexpr decltype(auto) operator*() const LIFETIMEBOUND { return *get(); }util::NotNull<std::unique_ptr<LevelDBContext, std::default_delete<LevelDBContext>>>::operator*() const Line | Count | Source | 88 | 11.0M | constexpr decltype(auto) operator*() const LIFETIMEBOUND { return *get(); } |
util::NotNull<std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>>::operator*() const Line | Count | Source | 88 | 5 | constexpr decltype(auto) operator*() const LIFETIMEBOUND { return *get(); } |
util::NotNull<std::unique_ptr<int, std::default_delete<int>>>::operator*() const Line | Count | Source | 88 | 7 | constexpr decltype(auto) operator*() const LIFETIMEBOUND { return *get(); } |
util_not_null_tests.cpp:util::NotNull<std::shared_ptr<util_not_null_tests::check_tsa::test_method()::Thing>>::operator*() const Line | Count | Source | 88 | 1 | 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 | | constexpr operator T() && noexcept(std::is_nothrow_move_constructible_v<T>) |
96 | | requires std::move_constructible<T> |
97 | 46.5k | { |
98 | 46.5k | return std::move(*this).get(); |
99 | 46.5k | } util::NotNull<std::unique_ptr<int, std::default_delete<int>>>::operator std::unique_ptr<int, std::default_delete<int>>() && requires std::move_constructible<T> Line | Count | Source | 97 | 1 | { | 98 | 1 | return std::move(*this).get(); | 99 | 1 | } |
util_not_null_tests.cpp:util::NotNull<std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>>::operator std::unique_ptr<util_not_null_tests::check_derived::test_method()::MyBase, std::default_delete<util_not_null_tests::check_derived::test_method()::MyBase>>() && requires std::move_constructible<T> Line | Count | Source | 97 | 1 | { | 98 | 1 | return std::move(*this).get(); | 99 | 1 | } |
util::NotNull<std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>>::operator std::unique_ptr<CTxMemPool::ChangeSet, std::default_delete<CTxMemPool::ChangeSet>>() && requires std::move_constructible<T> Line | Count | Source | 97 | 46.5k | { | 98 | 46.5k | return std::move(*this).get(); | 99 | 46.5k | } |
|
100 | | |
101 | | template <class U> |
102 | | constexpr auto operator<=>(const NotNull<U>& other) const |
103 | 4 | { |
104 | 4 | return std::compare_three_way{}(get(), other.get()); |
105 | 4 | } |
106 | | template <class U> |
107 | | constexpr bool operator==(const NotNull<U>& other) const |
108 | 2 | { |
109 | 2 | return get() == other.get(); |
110 | 2 | } util_not_null_tests.cpp:bool util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyBase>>::operator==<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyDerived>>(util::NotNull<std::shared_ptr<util_not_null_tests::check_derived::test_method()::MyDerived>> const&) const Line | Count | Source | 108 | 1 | { | 109 | 1 | return get() == other.get(); | 110 | 1 | } |
bool util::NotNull<std::shared_ptr<int>>::operator==<std::shared_ptr<int>>(util::NotNull<std::shared_ptr<int>> const&) const Line | Count | Source | 108 | 1 | { | 109 | 1 | return get() == other.get(); | 110 | 1 | } |
|
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 | | std::size_t operator()(const util::NotNull<T>& v) const noexcept |
130 | 4 | { |
131 | 4 | return std::hash<T>{}(v.get()); |
132 | 4 | } |
133 | | }; |
134 | | |
135 | | #endif // BITCOIN_UTIL_NOT_NULL_H |