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