1 //===- CustomizableOptional.h - Optional with custom storage ----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H 10 #define CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H 11 12 #include "llvm/ADT/Hashing.h" 13 #include "llvm/Support/Compiler.h" 14 #include "llvm/Support/type_traits.h" 15 #include <cassert> 16 #include <new> 17 #include <optional> 18 #include <utility> 19 20 namespace clang { 21 22 namespace optional_detail { 23 template <typename> class OptionalStorage; 24 } // namespace optional_detail 25 26 // Optional type which internal storage can be specialized by providing 27 // OptionalStorage. The interface follows std::optional. 28 template <typename T> class CustomizableOptional { 29 optional_detail::OptionalStorage<T> Storage; 30 31 public: 32 using value_type = T; 33 34 constexpr CustomizableOptional() = default; 35 constexpr CustomizableOptional(std::nullopt_t) {} 36 37 constexpr CustomizableOptional(const T &y) : Storage(std::in_place, y) {} 38 constexpr CustomizableOptional(const CustomizableOptional &O) = default; 39 40 constexpr CustomizableOptional(T &&y) 41 : Storage(std::in_place, std::move(y)) {} 42 constexpr CustomizableOptional(CustomizableOptional &&O) = default; 43 44 template <typename... ArgTypes> 45 constexpr CustomizableOptional(std::in_place_t, ArgTypes &&...Args) 46 : Storage(std::in_place, std::forward<ArgTypes>(Args)...) {} 47 48 // Allow conversion from std::optional<T>. 49 constexpr CustomizableOptional(const std::optional<T> &y) 50 : CustomizableOptional(y ? *y : CustomizableOptional()) {} 51 constexpr CustomizableOptional(std::optional<T> &&y) 52 : CustomizableOptional(y ? std::move(*y) : CustomizableOptional()) {} 53 54 CustomizableOptional &operator=(T &&y) { 55 Storage = std::move(y); 56 return *this; 57 } 58 CustomizableOptional &operator=(CustomizableOptional &&O) = default; 59 60 /// Create a new object by constructing it in place with the given arguments. 61 template <typename... ArgTypes> void emplace(ArgTypes &&...Args) { 62 Storage.emplace(std::forward<ArgTypes>(Args)...); 63 } 64 65 CustomizableOptional &operator=(const T &y) { 66 Storage = y; 67 return *this; 68 } 69 CustomizableOptional &operator=(const CustomizableOptional &O) = default; 70 71 void reset() { Storage.reset(); } 72 73 LLVM_DEPRECATED("Use &*X instead.", "&*X") 74 constexpr const T *getPointer() const { return &Storage.value(); } 75 LLVM_DEPRECATED("Use &*X instead.", "&*X") 76 T *getPointer() { return &Storage.value(); } 77 LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X") 78 constexpr const T &value() const & { return Storage.value(); } 79 LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X") 80 T &value() & { return Storage.value(); } 81 82 constexpr explicit operator bool() const { return has_value(); } 83 constexpr bool has_value() const { return Storage.has_value(); } 84 constexpr const T *operator->() const { return &Storage.value(); } 85 T *operator->() { return &Storage.value(); } 86 constexpr const T &operator*() const & { return Storage.value(); } 87 T &operator*() & { return Storage.value(); } 88 89 template <typename U> constexpr T value_or(U &&alt) const & { 90 return has_value() ? operator*() : std::forward<U>(alt); 91 } 92 93 LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X") 94 T &&value() && { return std::move(Storage.value()); } 95 T &&operator*() && { return std::move(Storage.value()); } 96 97 template <typename U> T value_or(U &&alt) && { 98 return has_value() ? std::move(operator*()) : std::forward<U>(alt); 99 } 100 101 // Allow conversion to std::optional<T>. 102 explicit operator std::optional<T> &() const & { 103 return *this ? **this : std::optional<T>(); 104 } 105 explicit operator std::optional<T> &&() const && { 106 return *this ? std::move(**this) : std::optional<T>(); 107 } 108 }; 109 110 template <typename T> 111 CustomizableOptional(const T &) -> CustomizableOptional<T>; 112 113 template <class T> 114 llvm::hash_code hash_value(const CustomizableOptional<T> &O) { 115 return O ? llvm::hash_combine(true, *O) : llvm::hash_value(false); 116 } 117 118 template <typename T, typename U> 119 constexpr bool operator==(const CustomizableOptional<T> &X, 120 const CustomizableOptional<U> &Y) { 121 if (X && Y) 122 return *X == *Y; 123 return X.has_value() == Y.has_value(); 124 } 125 126 template <typename T, typename U> 127 constexpr bool operator!=(const CustomizableOptional<T> &X, 128 const CustomizableOptional<U> &Y) { 129 return !(X == Y); 130 } 131 132 template <typename T, typename U> 133 constexpr bool operator<(const CustomizableOptional<T> &X, 134 const CustomizableOptional<U> &Y) { 135 if (X && Y) 136 return *X < *Y; 137 return X.has_value() < Y.has_value(); 138 } 139 140 template <typename T, typename U> 141 constexpr bool operator<=(const CustomizableOptional<T> &X, 142 const CustomizableOptional<U> &Y) { 143 return !(Y < X); 144 } 145 146 template <typename T, typename U> 147 constexpr bool operator>(const CustomizableOptional<T> &X, 148 const CustomizableOptional<U> &Y) { 149 return Y < X; 150 } 151 152 template <typename T, typename U> 153 constexpr bool operator>=(const CustomizableOptional<T> &X, 154 const CustomizableOptional<U> &Y) { 155 return !(X < Y); 156 } 157 158 template <typename T> 159 constexpr bool operator==(const CustomizableOptional<T> &X, std::nullopt_t) { 160 return !X; 161 } 162 163 template <typename T> 164 constexpr bool operator==(std::nullopt_t, const CustomizableOptional<T> &X) { 165 return X == std::nullopt; 166 } 167 168 template <typename T> 169 constexpr bool operator!=(const CustomizableOptional<T> &X, std::nullopt_t) { 170 return !(X == std::nullopt); 171 } 172 173 template <typename T> 174 constexpr bool operator!=(std::nullopt_t, const CustomizableOptional<T> &X) { 175 return X != std::nullopt; 176 } 177 178 template <typename T> 179 constexpr bool operator<(const CustomizableOptional<T> &, std::nullopt_t) { 180 return false; 181 } 182 183 template <typename T> 184 constexpr bool operator<(std::nullopt_t, const CustomizableOptional<T> &X) { 185 return X.has_value(); 186 } 187 188 template <typename T> 189 constexpr bool operator<=(const CustomizableOptional<T> &X, std::nullopt_t) { 190 return !(std::nullopt < X); 191 } 192 193 template <typename T> 194 constexpr bool operator<=(std::nullopt_t, const CustomizableOptional<T> &X) { 195 return !(X < std::nullopt); 196 } 197 198 template <typename T> 199 constexpr bool operator>(const CustomizableOptional<T> &X, std::nullopt_t) { 200 return std::nullopt < X; 201 } 202 203 template <typename T> 204 constexpr bool operator>(std::nullopt_t, const CustomizableOptional<T> &X) { 205 return X < std::nullopt; 206 } 207 208 template <typename T> 209 constexpr bool operator>=(const CustomizableOptional<T> &X, std::nullopt_t) { 210 return std::nullopt <= X; 211 } 212 213 template <typename T> 214 constexpr bool operator>=(std::nullopt_t, const CustomizableOptional<T> &X) { 215 return X <= std::nullopt; 216 } 217 218 template <typename T> 219 constexpr bool operator==(const CustomizableOptional<T> &X, const T &Y) { 220 return X && *X == Y; 221 } 222 223 template <typename T> 224 constexpr bool operator==(const T &X, const CustomizableOptional<T> &Y) { 225 return Y && X == *Y; 226 } 227 228 template <typename T> 229 constexpr bool operator!=(const CustomizableOptional<T> &X, const T &Y) { 230 return !(X == Y); 231 } 232 233 template <typename T> 234 constexpr bool operator!=(const T &X, const CustomizableOptional<T> &Y) { 235 return !(X == Y); 236 } 237 238 template <typename T> 239 constexpr bool operator<(const CustomizableOptional<T> &X, const T &Y) { 240 return !X || *X < Y; 241 } 242 243 template <typename T> 244 constexpr bool operator<(const T &X, const CustomizableOptional<T> &Y) { 245 return Y && X < *Y; 246 } 247 248 template <typename T> 249 constexpr bool operator<=(const CustomizableOptional<T> &X, const T &Y) { 250 return !(Y < X); 251 } 252 253 template <typename T> 254 constexpr bool operator<=(const T &X, const CustomizableOptional<T> &Y) { 255 return !(Y < X); 256 } 257 258 template <typename T> 259 constexpr bool operator>(const CustomizableOptional<T> &X, const T &Y) { 260 return Y < X; 261 } 262 263 template <typename T> 264 constexpr bool operator>(const T &X, const CustomizableOptional<T> &Y) { 265 return Y < X; 266 } 267 268 template <typename T> 269 constexpr bool operator>=(const CustomizableOptional<T> &X, const T &Y) { 270 return !(X < Y); 271 } 272 273 template <typename T> 274 constexpr bool operator>=(const T &X, const CustomizableOptional<T> &Y) { 275 return !(X < Y); 276 } 277 278 } // namespace clang 279 280 #endif // CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H 281