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 71 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>> NonNull(const NonNull<U> & other)72 constexpr NonNull(const NonNull<U>& other) : pointer_(other.get()) {} 73 74 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, Pointer>>> 75 constexpr NonNull& operator=(const NonNull<U>& other) { 76 pointer_ = other.get(); 77 return *this; 78 } 79 get()80 [[nodiscard]] constexpr const Pointer& get() const { return pointer_; } 81 [[nodiscard]] constexpr explicit operator const Pointer&() const { return get(); } 82 83 // Move operations. These break the invariant, so care must be taken to avoid subsequent access. 84 85 constexpr NonNull(NonNull&&) = default; 86 constexpr NonNull& operator=(NonNull&&) = default; 87 take()88 [[nodiscard]] constexpr Pointer take() && { return std::move(pointer_); } Pointer()89 [[nodiscard]] constexpr explicit operator Pointer() && { return take(); } 90 91 // Dereferencing. decltype(auto)92 [[nodiscard]] constexpr decltype(auto) operator*() const { return *get(); } 93 [[nodiscard]] constexpr decltype(auto) operator->() const { return get(); } 94 95 [[nodiscard]] constexpr explicit operator bool() const { return !(pointer_ == nullptr); } 96 97 // Private constructor for ftl::as_non_null. Excluded from candidate constructors for conversions 98 // through the passkey idiom, for clear compilation errors. 99 template <typename P> NonNull(Passkey,P && pointer)100 constexpr NonNull(Passkey, P&& pointer) : pointer_(std::forward<P>(pointer)) { 101 if (pointer_ == nullptr) std::abort(); 102 } 103 104 private: 105 template <typename P> 106 friend constexpr auto as_non_null(P&&) -> NonNull<std::decay_t<P>>; 107 108 Pointer pointer_; 109 }; 110 111 template <typename P> 112 [[nodiscard]] constexpr auto as_non_null(P&& pointer) -> NonNull<std::decay_t<P>> { 113 using Passkey = typename NonNull<std::decay_t<P>>::Passkey; 114 return {Passkey{}, std::forward<P>(pointer)}; 115 } 116 117 // NonNull<P> <=> NonNull<Q> 118 119 template <typename P, typename Q> 120 constexpr bool operator==(const NonNull<P>& lhs, const NonNull<Q>& rhs) { 121 return lhs.get() == rhs.get(); 122 } 123 124 template <typename P, typename Q> 125 constexpr bool operator!=(const NonNull<P>& lhs, const NonNull<Q>& rhs) { 126 return !operator==(lhs, rhs); 127 } 128 129 template <typename P, typename Q> 130 constexpr bool operator<(const NonNull<P>& lhs, const NonNull<Q>& rhs) { 131 return lhs.get() < rhs.get(); 132 } 133 134 template <typename P, typename Q> 135 constexpr bool operator<=(const NonNull<P>& lhs, const NonNull<Q>& rhs) { 136 return lhs.get() <= rhs.get(); 137 } 138 139 template <typename P, typename Q> 140 constexpr bool operator>=(const NonNull<P>& lhs, const NonNull<Q>& rhs) { 141 return lhs.get() >= rhs.get(); 142 } 143 144 template <typename P, typename Q> 145 constexpr bool operator>(const NonNull<P>& lhs, const NonNull<Q>& rhs) { 146 return lhs.get() > rhs.get(); 147 } 148 149 // NonNull<P> <=> Q 150 151 template <typename P, typename Q> 152 constexpr bool operator==(const NonNull<P>& lhs, const Q& rhs) { 153 return lhs.get() == rhs; 154 } 155 156 template <typename P, typename Q> 157 constexpr bool operator!=(const NonNull<P>& lhs, const Q& rhs) { 158 return lhs.get() != rhs; 159 } 160 161 template <typename P, typename Q> 162 constexpr bool operator<(const NonNull<P>& lhs, const Q& rhs) { 163 return lhs.get() < rhs; 164 } 165 166 template <typename P, typename Q> 167 constexpr bool operator<=(const NonNull<P>& lhs, const Q& rhs) { 168 return lhs.get() <= rhs; 169 } 170 171 template <typename P, typename Q> 172 constexpr bool operator>=(const NonNull<P>& lhs, const Q& rhs) { 173 return lhs.get() >= rhs; 174 } 175 176 template <typename P, typename Q> 177 constexpr bool operator>(const NonNull<P>& lhs, const Q& rhs) { 178 return lhs.get() > rhs; 179 } 180 181 // P <=> NonNull<Q> 182 183 template <typename P, typename Q> 184 constexpr bool operator==(const P& lhs, const NonNull<Q>& rhs) { 185 return lhs == rhs.get(); 186 } 187 188 template <typename P, typename Q> 189 constexpr bool operator!=(const P& lhs, const NonNull<Q>& rhs) { 190 return lhs != rhs.get(); 191 } 192 193 template <typename P, typename Q> 194 constexpr bool operator<(const P& lhs, const NonNull<Q>& rhs) { 195 return lhs < rhs.get(); 196 } 197 198 template <typename P, typename Q> 199 constexpr bool operator<=(const P& lhs, const NonNull<Q>& rhs) { 200 return lhs <= rhs.get(); 201 } 202 203 template <typename P, typename Q> 204 constexpr bool operator>=(const P& lhs, const NonNull<Q>& rhs) { 205 return lhs >= rhs.get(); 206 } 207 208 template <typename P, typename Q> 209 constexpr bool operator>(const P& lhs, const NonNull<Q>& rhs) { 210 return lhs > rhs.get(); 211 } 212 213 } // namespace android::ftl 214 215 // Specialize std::hash for ftl::NonNull<T> 216 template <typename P> 217 struct std::hash<android::ftl::NonNull<P>> { 218 std::size_t operator()(const android::ftl::NonNull<P>& ptr) const { 219 return std::hash<P>()(ptr.get()); 220 } 221 }; 222