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 102 template <typename T> 103 CustomizableOptional(const T &) -> CustomizableOptional<T>; 104 105 template <class T> 106 llvm::hash_code hash_value(const CustomizableOptional<T> &O) { 107 return O ? llvm::hash_combine(true, *O) : llvm::hash_value(false); 108 } 109 110 template <typename T, typename U> 111 constexpr bool operator==(const CustomizableOptional<T> &X, 112 const CustomizableOptional<U> &Y) { 113 if (X && Y) 114 return *X == *Y; 115 return X.has_value() == Y.has_value(); 116 } 117 118 template <typename T, typename U> 119 constexpr bool operator!=(const CustomizableOptional<T> &X, 120 const CustomizableOptional<U> &Y) { 121 return !(X == Y); 122 } 123 124 template <typename T, typename U> 125 constexpr bool operator<(const CustomizableOptional<T> &X, 126 const CustomizableOptional<U> &Y) { 127 if (X && Y) 128 return *X < *Y; 129 return X.has_value() < Y.has_value(); 130 } 131 132 template <typename T, typename U> 133 constexpr bool operator<=(const CustomizableOptional<T> &X, 134 const CustomizableOptional<U> &Y) { 135 return !(Y < X); 136 } 137 138 template <typename T, typename U> 139 constexpr bool operator>(const CustomizableOptional<T> &X, 140 const CustomizableOptional<U> &Y) { 141 return Y < X; 142 } 143 144 template <typename T, typename U> 145 constexpr bool operator>=(const CustomizableOptional<T> &X, 146 const CustomizableOptional<U> &Y) { 147 return !(X < Y); 148 } 149 150 template <typename T> 151 constexpr bool operator==(const CustomizableOptional<T> &X, std::nullopt_t) { 152 return !X; 153 } 154 155 template <typename T> 156 constexpr bool operator==(std::nullopt_t, const CustomizableOptional<T> &X) { 157 return X == std::nullopt; 158 } 159 160 template <typename T> 161 constexpr bool operator!=(const CustomizableOptional<T> &X, std::nullopt_t) { 162 return !(X == std::nullopt); 163 } 164 165 template <typename T> 166 constexpr bool operator!=(std::nullopt_t, const CustomizableOptional<T> &X) { 167 return X != std::nullopt; 168 } 169 170 template <typename T> 171 constexpr bool operator<(const CustomizableOptional<T> &, std::nullopt_t) { 172 return false; 173 } 174 175 template <typename T> 176 constexpr bool operator<(std::nullopt_t, const CustomizableOptional<T> &X) { 177 return X.has_value(); 178 } 179 180 template <typename T> 181 constexpr bool operator<=(const CustomizableOptional<T> &X, std::nullopt_t) { 182 return !(std::nullopt < X); 183 } 184 185 template <typename T> 186 constexpr bool operator<=(std::nullopt_t, const CustomizableOptional<T> &X) { 187 return !(X < std::nullopt); 188 } 189 190 template <typename T> 191 constexpr bool operator>(const CustomizableOptional<T> &X, std::nullopt_t) { 192 return std::nullopt < X; 193 } 194 195 template <typename T> 196 constexpr bool operator>(std::nullopt_t, const CustomizableOptional<T> &X) { 197 return X < std::nullopt; 198 } 199 200 template <typename T> 201 constexpr bool operator>=(const CustomizableOptional<T> &X, std::nullopt_t) { 202 return std::nullopt <= X; 203 } 204 205 template <typename T> 206 constexpr bool operator>=(std::nullopt_t, const CustomizableOptional<T> &X) { 207 return X <= std::nullopt; 208 } 209 210 template <typename T> 211 constexpr bool operator==(const CustomizableOptional<T> &X, const T &Y) { 212 return X && *X == Y; 213 } 214 215 template <typename T> 216 constexpr bool operator==(const T &X, const CustomizableOptional<T> &Y) { 217 return Y && X == *Y; 218 } 219 220 template <typename T> 221 constexpr bool operator!=(const CustomizableOptional<T> &X, const T &Y) { 222 return !(X == Y); 223 } 224 225 template <typename T> 226 constexpr bool operator!=(const T &X, const CustomizableOptional<T> &Y) { 227 return !(X == Y); 228 } 229 230 template <typename T> 231 constexpr bool operator<(const CustomizableOptional<T> &X, const T &Y) { 232 return !X || *X < Y; 233 } 234 235 template <typename T> 236 constexpr bool operator<(const T &X, const CustomizableOptional<T> &Y) { 237 return Y && X < *Y; 238 } 239 240 template <typename T> 241 constexpr bool operator<=(const CustomizableOptional<T> &X, const T &Y) { 242 return !(Y < X); 243 } 244 245 template <typename T> 246 constexpr bool operator<=(const T &X, const CustomizableOptional<T> &Y) { 247 return !(Y < X); 248 } 249 250 template <typename T> 251 constexpr bool operator>(const CustomizableOptional<T> &X, const T &Y) { 252 return Y < X; 253 } 254 255 template <typename T> 256 constexpr bool operator>(const T &X, const CustomizableOptional<T> &Y) { 257 return Y < X; 258 } 259 260 template <typename T> 261 constexpr bool operator>=(const CustomizableOptional<T> &X, const T &Y) { 262 return !(X < Y); 263 } 264 265 template <typename T> 266 constexpr bool operator>=(const T &X, const CustomizableOptional<T> &Y) { 267 return !(X < Y); 268 } 269 270 } // namespace clang 271 272 #endif // CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H 273