xref: /aosp_15_r20/frameworks/native/include/ftl/non_null.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <cstdlib>
20*38e8c45fSAndroid Build Coastguard Worker #include <type_traits>
21*38e8c45fSAndroid Build Coastguard Worker #include <utility>
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker namespace android::ftl {
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker // Enforces and documents non-null pre/post-condition for (raw or smart) pointers.
26*38e8c45fSAndroid Build Coastguard Worker //
27*38e8c45fSAndroid Build Coastguard Worker //   void get_length(const ftl::NonNull<std::shared_ptr<std::string>>& string_ptr,
28*38e8c45fSAndroid Build Coastguard Worker //                   ftl::NonNull<std::size_t*> length_ptr) {
29*38e8c45fSAndroid Build Coastguard Worker //     // No need for `nullptr` checks.
30*38e8c45fSAndroid Build Coastguard Worker //     *length_ptr = string_ptr->length();
31*38e8c45fSAndroid Build Coastguard Worker //   }
32*38e8c45fSAndroid Build Coastguard Worker //
33*38e8c45fSAndroid Build Coastguard Worker //   const auto string_ptr = ftl::as_non_null(std::make_shared<std::string>("android"));
34*38e8c45fSAndroid Build Coastguard Worker //   std::size_t size;
35*38e8c45fSAndroid Build Coastguard Worker //   get_length(string_ptr, ftl::as_non_null(&size));
36*38e8c45fSAndroid Build Coastguard Worker //   assert(size == 7u);
37*38e8c45fSAndroid Build Coastguard Worker //
38*38e8c45fSAndroid Build Coastguard Worker // For compatibility with std::unique_ptr<T> and performance with std::shared_ptr<T>, move
39*38e8c45fSAndroid Build Coastguard Worker // operations are allowed despite breaking the invariant:
40*38e8c45fSAndroid Build Coastguard Worker //
41*38e8c45fSAndroid Build Coastguard Worker //   using Pair = std::pair<ftl::NonNull<std::shared_ptr<int>>, std::shared_ptr<int>>;
42*38e8c45fSAndroid Build Coastguard Worker //
43*38e8c45fSAndroid Build Coastguard Worker //   Pair dupe_if(ftl::NonNull<std::unique_ptr<int>> non_null_ptr, bool condition) {
44*38e8c45fSAndroid Build Coastguard Worker //     // Move the underlying pointer out, so `non_null_ptr` must not be accessed after this point.
45*38e8c45fSAndroid Build Coastguard Worker //     auto unique_ptr = std::move(non_null_ptr).take();
46*38e8c45fSAndroid Build Coastguard Worker //
47*38e8c45fSAndroid Build Coastguard Worker //     auto non_null_shared_ptr = ftl::as_non_null(std::shared_ptr<int>(std::move(unique_ptr)));
48*38e8c45fSAndroid Build Coastguard Worker //     auto nullable_shared_ptr = condition ? non_null_shared_ptr.get() : nullptr;
49*38e8c45fSAndroid Build Coastguard Worker //
50*38e8c45fSAndroid Build Coastguard Worker //     return {std::move(non_null_shared_ptr), std::move(nullable_shared_ptr)};
51*38e8c45fSAndroid Build Coastguard Worker //   }
52*38e8c45fSAndroid Build Coastguard Worker //
53*38e8c45fSAndroid Build Coastguard Worker //   auto ptr = ftl::as_non_null(std::make_unique<int>(42));
54*38e8c45fSAndroid Build Coastguard Worker //   const auto [ptr1, ptr2] = dupe_if(std::move(ptr), true);
55*38e8c45fSAndroid Build Coastguard Worker //   assert(ptr1.get() == ptr2);
56*38e8c45fSAndroid Build Coastguard Worker //
57*38e8c45fSAndroid Build Coastguard Worker template <typename Pointer>
58*38e8c45fSAndroid Build Coastguard Worker class NonNull final {
59*38e8c45fSAndroid Build Coastguard Worker   struct Passkey {};
60*38e8c45fSAndroid Build Coastguard Worker 
61*38e8c45fSAndroid Build Coastguard Worker  public:
62*38e8c45fSAndroid Build Coastguard Worker   // Disallow `nullptr` explicitly for clear compilation errors.
63*38e8c45fSAndroid Build Coastguard Worker   NonNull() = delete;
64*38e8c45fSAndroid Build Coastguard Worker   NonNull(std::nullptr_t) = delete;
65*38e8c45fSAndroid Build Coastguard Worker 
66*38e8c45fSAndroid Build Coastguard Worker   // Copy operations.
67*38e8c45fSAndroid Build Coastguard Worker 
68*38e8c45fSAndroid Build Coastguard Worker   constexpr NonNull(const NonNull&) = default;
69*38e8c45fSAndroid Build Coastguard Worker   constexpr NonNull& operator=(const NonNull&) = default;
70*38e8c45fSAndroid Build Coastguard Worker 
71*38e8c45fSAndroid Build Coastguard Worker   template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>>
NonNull(const NonNull<U> & other)72*38e8c45fSAndroid Build Coastguard Worker   constexpr NonNull(const NonNull<U>& other) : pointer_(other.get()) {}
73*38e8c45fSAndroid Build Coastguard Worker 
74*38e8c45fSAndroid Build Coastguard Worker   template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>>
75*38e8c45fSAndroid Build Coastguard Worker   constexpr NonNull& operator=(const NonNull<U>& other) {
76*38e8c45fSAndroid Build Coastguard Worker     pointer_ = other.get();
77*38e8c45fSAndroid Build Coastguard Worker     return *this;
78*38e8c45fSAndroid Build Coastguard Worker   }
79*38e8c45fSAndroid Build Coastguard Worker 
get()80*38e8c45fSAndroid Build Coastguard Worker   [[nodiscard]] constexpr const Pointer& get() const { return pointer_; }
81*38e8c45fSAndroid Build Coastguard Worker   [[nodiscard]] constexpr explicit operator const Pointer&() const { return get(); }
82*38e8c45fSAndroid Build Coastguard Worker 
83*38e8c45fSAndroid Build Coastguard Worker   // Move operations. These break the invariant, so care must be taken to avoid subsequent access.
84*38e8c45fSAndroid Build Coastguard Worker 
85*38e8c45fSAndroid Build Coastguard Worker   constexpr NonNull(NonNull&&) = default;
86*38e8c45fSAndroid Build Coastguard Worker   constexpr NonNull& operator=(NonNull&&) = default;
87*38e8c45fSAndroid Build Coastguard Worker 
take()88*38e8c45fSAndroid Build Coastguard Worker   [[nodiscard]] constexpr Pointer take() && { return std::move(pointer_); }
Pointer()89*38e8c45fSAndroid Build Coastguard Worker   [[nodiscard]] constexpr explicit operator Pointer() && { return take(); }
90*38e8c45fSAndroid Build Coastguard Worker 
91*38e8c45fSAndroid Build Coastguard Worker   // Dereferencing.
decltype(auto)92*38e8c45fSAndroid Build Coastguard Worker   [[nodiscard]] constexpr decltype(auto) operator*() const { return *get(); }
93*38e8c45fSAndroid Build Coastguard Worker   [[nodiscard]] constexpr decltype(auto) operator->() const { return get(); }
94*38e8c45fSAndroid Build Coastguard Worker 
95*38e8c45fSAndroid Build Coastguard Worker   [[nodiscard]] constexpr explicit operator bool() const { return !(pointer_ == nullptr); }
96*38e8c45fSAndroid Build Coastguard Worker 
97*38e8c45fSAndroid Build Coastguard Worker   // Private constructor for ftl::as_non_null. Excluded from candidate constructors for conversions
98*38e8c45fSAndroid Build Coastguard Worker   // through the passkey idiom, for clear compilation errors.
99*38e8c45fSAndroid Build Coastguard Worker   template <typename P>
NonNull(Passkey,P && pointer)100*38e8c45fSAndroid Build Coastguard Worker   constexpr NonNull(Passkey, P&& pointer) : pointer_(std::forward<P>(pointer)) {
101*38e8c45fSAndroid Build Coastguard Worker     if (pointer_ == nullptr) std::abort();
102*38e8c45fSAndroid Build Coastguard Worker   }
103*38e8c45fSAndroid Build Coastguard Worker 
104*38e8c45fSAndroid Build Coastguard Worker  private:
105*38e8c45fSAndroid Build Coastguard Worker   template <typename P>
106*38e8c45fSAndroid Build Coastguard Worker   friend constexpr auto as_non_null(P&&) -> NonNull<std::decay_t<P>>;
107*38e8c45fSAndroid Build Coastguard Worker 
108*38e8c45fSAndroid Build Coastguard Worker   Pointer pointer_;
109*38e8c45fSAndroid Build Coastguard Worker };
110*38e8c45fSAndroid Build Coastguard Worker 
111*38e8c45fSAndroid Build Coastguard Worker template <typename P>
112*38e8c45fSAndroid Build Coastguard Worker [[nodiscard]] constexpr auto as_non_null(P&& pointer) -> NonNull<std::decay_t<P>> {
113*38e8c45fSAndroid Build Coastguard Worker   using Passkey = typename NonNull<std::decay_t<P>>::Passkey;
114*38e8c45fSAndroid Build Coastguard Worker   return {Passkey{}, std::forward<P>(pointer)};
115*38e8c45fSAndroid Build Coastguard Worker }
116*38e8c45fSAndroid Build Coastguard Worker 
117*38e8c45fSAndroid Build Coastguard Worker // NonNull<P> <=> NonNull<Q>
118*38e8c45fSAndroid Build Coastguard Worker 
119*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
120*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator==(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
121*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() == rhs.get();
122*38e8c45fSAndroid Build Coastguard Worker }
123*38e8c45fSAndroid Build Coastguard Worker 
124*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
125*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator!=(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
126*38e8c45fSAndroid Build Coastguard Worker   return !operator==(lhs, rhs);
127*38e8c45fSAndroid Build Coastguard Worker }
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
130*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator<(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
131*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() < rhs.get();
132*38e8c45fSAndroid Build Coastguard Worker }
133*38e8c45fSAndroid Build Coastguard Worker 
134*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
135*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator<=(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
136*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() <= rhs.get();
137*38e8c45fSAndroid Build Coastguard Worker }
138*38e8c45fSAndroid Build Coastguard Worker 
139*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
140*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator>=(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
141*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() >= rhs.get();
142*38e8c45fSAndroid Build Coastguard Worker }
143*38e8c45fSAndroid Build Coastguard Worker 
144*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
145*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator>(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
146*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() > rhs.get();
147*38e8c45fSAndroid Build Coastguard Worker }
148*38e8c45fSAndroid Build Coastguard Worker 
149*38e8c45fSAndroid Build Coastguard Worker // NonNull<P> <=> Q
150*38e8c45fSAndroid Build Coastguard Worker 
151*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
152*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator==(const NonNull<P>& lhs, const Q& rhs) {
153*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() == rhs;
154*38e8c45fSAndroid Build Coastguard Worker }
155*38e8c45fSAndroid Build Coastguard Worker 
156*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
157*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator!=(const NonNull<P>& lhs, const Q& rhs) {
158*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() != rhs;
159*38e8c45fSAndroid Build Coastguard Worker }
160*38e8c45fSAndroid Build Coastguard Worker 
161*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
162*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator<(const NonNull<P>& lhs, const Q& rhs) {
163*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() < rhs;
164*38e8c45fSAndroid Build Coastguard Worker }
165*38e8c45fSAndroid Build Coastguard Worker 
166*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
167*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator<=(const NonNull<P>& lhs, const Q& rhs) {
168*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() <= rhs;
169*38e8c45fSAndroid Build Coastguard Worker }
170*38e8c45fSAndroid Build Coastguard Worker 
171*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
172*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator>=(const NonNull<P>& lhs, const Q& rhs) {
173*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() >= rhs;
174*38e8c45fSAndroid Build Coastguard Worker }
175*38e8c45fSAndroid Build Coastguard Worker 
176*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
177*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator>(const NonNull<P>& lhs, const Q& rhs) {
178*38e8c45fSAndroid Build Coastguard Worker   return lhs.get() > rhs;
179*38e8c45fSAndroid Build Coastguard Worker }
180*38e8c45fSAndroid Build Coastguard Worker 
181*38e8c45fSAndroid Build Coastguard Worker // P <=> NonNull<Q>
182*38e8c45fSAndroid Build Coastguard Worker 
183*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
184*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator==(const P& lhs, const NonNull<Q>& rhs) {
185*38e8c45fSAndroid Build Coastguard Worker   return lhs == rhs.get();
186*38e8c45fSAndroid Build Coastguard Worker }
187*38e8c45fSAndroid Build Coastguard Worker 
188*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
189*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator!=(const P& lhs, const NonNull<Q>& rhs) {
190*38e8c45fSAndroid Build Coastguard Worker   return lhs != rhs.get();
191*38e8c45fSAndroid Build Coastguard Worker }
192*38e8c45fSAndroid Build Coastguard Worker 
193*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
194*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator<(const P& lhs, const NonNull<Q>& rhs) {
195*38e8c45fSAndroid Build Coastguard Worker   return lhs < rhs.get();
196*38e8c45fSAndroid Build Coastguard Worker }
197*38e8c45fSAndroid Build Coastguard Worker 
198*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
199*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator<=(const P& lhs, const NonNull<Q>& rhs) {
200*38e8c45fSAndroid Build Coastguard Worker   return lhs <= rhs.get();
201*38e8c45fSAndroid Build Coastguard Worker }
202*38e8c45fSAndroid Build Coastguard Worker 
203*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
204*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator>=(const P& lhs, const NonNull<Q>& rhs) {
205*38e8c45fSAndroid Build Coastguard Worker   return lhs >= rhs.get();
206*38e8c45fSAndroid Build Coastguard Worker }
207*38e8c45fSAndroid Build Coastguard Worker 
208*38e8c45fSAndroid Build Coastguard Worker template <typename P, typename Q>
209*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator>(const P& lhs, const NonNull<Q>& rhs) {
210*38e8c45fSAndroid Build Coastguard Worker   return lhs > rhs.get();
211*38e8c45fSAndroid Build Coastguard Worker }
212*38e8c45fSAndroid Build Coastguard Worker 
213*38e8c45fSAndroid Build Coastguard Worker }  // namespace android::ftl
214*38e8c45fSAndroid Build Coastguard Worker 
215*38e8c45fSAndroid Build Coastguard Worker // Specialize std::hash for ftl::NonNull<T>
216*38e8c45fSAndroid Build Coastguard Worker template <typename P>
217*38e8c45fSAndroid Build Coastguard Worker struct std::hash<android::ftl::NonNull<P>> {
218*38e8c45fSAndroid Build Coastguard Worker   std::size_t operator()(const android::ftl::NonNull<P>& ptr) const {
219*38e8c45fSAndroid Build Coastguard Worker     return std::hash<P>()(ptr.get());
220*38e8c45fSAndroid Build Coastguard Worker   }
221*38e8c45fSAndroid Build Coastguard Worker };
222