File indexing completed on 2026-05-10 08:44:30
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_SUPPORT_ERROROR_H
0016 #define LLVM_SUPPORT_ERROROR_H
0017
0018 #include "llvm/Support/AlignOf.h"
0019 #include <cassert>
0020 #include <system_error>
0021 #include <type_traits>
0022 #include <utility>
0023
0024 namespace llvm {
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 template<class T>
0056 class ErrorOr {
0057 template <class OtherT> friend class ErrorOr;
0058
0059 static constexpr bool isRef = std::is_reference_v<T>;
0060
0061 using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
0062
0063 public:
0064 using storage_type = std::conditional_t<isRef, wrap, T>;
0065
0066 private:
0067 using reference = std::remove_reference_t<T> &;
0068 using const_reference = const std::remove_reference_t<T> &;
0069 using pointer = std::remove_reference_t<T> *;
0070 using const_pointer = const std::remove_reference_t<T> *;
0071
0072 public:
0073 template <class E>
0074 ErrorOr(E ErrorCode,
0075 std::enable_if_t<std::is_error_code_enum<E>::value ||
0076 std::is_error_condition_enum<E>::value,
0077 void *> = nullptr)
0078 : HasError(true) {
0079 new (getErrorStorage()) std::error_code(make_error_code(ErrorCode));
0080 }
0081
0082 ErrorOr(std::error_code EC) : HasError(true) {
0083 new (getErrorStorage()) std::error_code(EC);
0084 }
0085
0086 template <class OtherT>
0087 ErrorOr(OtherT &&Val,
0088 std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr)
0089 : HasError(false) {
0090 new (getStorage()) storage_type(std::forward<OtherT>(Val));
0091 }
0092
0093 ErrorOr(const ErrorOr &Other) {
0094 copyConstruct(Other);
0095 }
0096
0097 template <class OtherT>
0098 ErrorOr(const ErrorOr<OtherT> &Other,
0099 std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) {
0100 copyConstruct(Other);
0101 }
0102
0103 template <class OtherT>
0104 explicit ErrorOr(
0105 const ErrorOr<OtherT> &Other,
0106 std::enable_if_t<!std::is_convertible_v<OtherT, const T &>> * = nullptr) {
0107 copyConstruct(Other);
0108 }
0109
0110 ErrorOr(ErrorOr &&Other) {
0111 moveConstruct(std::move(Other));
0112 }
0113
0114 template <class OtherT>
0115 ErrorOr(ErrorOr<OtherT> &&Other,
0116 std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) {
0117 moveConstruct(std::move(Other));
0118 }
0119
0120
0121
0122 template <class OtherT>
0123 explicit ErrorOr(
0124 ErrorOr<OtherT> &&Other,
0125 std::enable_if_t<!std::is_convertible_v<OtherT, T>> * = nullptr) {
0126 moveConstruct(std::move(Other));
0127 }
0128
0129 ErrorOr &operator=(const ErrorOr &Other) {
0130 copyAssign(Other);
0131 return *this;
0132 }
0133
0134 ErrorOr &operator=(ErrorOr &&Other) {
0135 moveAssign(std::move(Other));
0136 return *this;
0137 }
0138
0139 ~ErrorOr() {
0140 if (!HasError)
0141 getStorage()->~storage_type();
0142 }
0143
0144
0145 explicit operator bool() const {
0146 return !HasError;
0147 }
0148
0149 reference get() { return *getStorage(); }
0150 const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
0151
0152 std::error_code getError() const {
0153 return HasError ? *getErrorStorage() : std::error_code();
0154 }
0155
0156 pointer operator ->() {
0157 return toPointer(getStorage());
0158 }
0159
0160 const_pointer operator->() const { return toPointer(getStorage()); }
0161
0162 reference operator *() {
0163 return *getStorage();
0164 }
0165
0166 const_reference operator*() const { return *getStorage(); }
0167
0168 private:
0169 template <class OtherT>
0170 void copyConstruct(const ErrorOr<OtherT> &Other) {
0171 if (!Other.HasError) {
0172
0173 HasError = false;
0174 new (getStorage()) storage_type(*Other.getStorage());
0175 } else {
0176
0177 HasError = true;
0178 new (getErrorStorage()) std::error_code(Other.getError());
0179 }
0180 }
0181
0182 template <class T1>
0183 static bool compareThisIfSameType(const T1 &a, const T1 &b) {
0184 return &a == &b;
0185 }
0186
0187 template <class T1, class T2>
0188 static bool compareThisIfSameType(const T1 &a, const T2 &b) {
0189 return false;
0190 }
0191
0192 template <class OtherT>
0193 void copyAssign(const ErrorOr<OtherT> &Other) {
0194 if (compareThisIfSameType(*this, Other))
0195 return;
0196
0197 this->~ErrorOr();
0198 new (this) ErrorOr(Other);
0199 }
0200
0201 template <class OtherT>
0202 void moveConstruct(ErrorOr<OtherT> &&Other) {
0203 if (!Other.HasError) {
0204
0205 HasError = false;
0206 new (getStorage()) storage_type(std::move(*Other.getStorage()));
0207 } else {
0208
0209 HasError = true;
0210 new (getErrorStorage()) std::error_code(Other.getError());
0211 }
0212 }
0213
0214 template <class OtherT>
0215 void moveAssign(ErrorOr<OtherT> &&Other) {
0216 if (compareThisIfSameType(*this, Other))
0217 return;
0218
0219 this->~ErrorOr();
0220 new (this) ErrorOr(std::move(Other));
0221 }
0222
0223 pointer toPointer(pointer Val) {
0224 return Val;
0225 }
0226
0227 const_pointer toPointer(const_pointer Val) const { return Val; }
0228
0229 pointer toPointer(wrap *Val) {
0230 return &Val->get();
0231 }
0232
0233 const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
0234
0235 storage_type *getStorage() {
0236 assert(!HasError && "Cannot get value when an error exists!");
0237 return reinterpret_cast<storage_type *>(&TStorage);
0238 }
0239
0240 const storage_type *getStorage() const {
0241 assert(!HasError && "Cannot get value when an error exists!");
0242 return reinterpret_cast<const storage_type *>(&TStorage);
0243 }
0244
0245 std::error_code *getErrorStorage() {
0246 assert(HasError && "Cannot get error when a value exists!");
0247 return reinterpret_cast<std::error_code *>(&ErrorStorage);
0248 }
0249
0250 const std::error_code *getErrorStorage() const {
0251 return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
0252 }
0253
0254 union {
0255 AlignedCharArrayUnion<storage_type> TStorage;
0256 AlignedCharArrayUnion<std::error_code> ErrorStorage;
0257 };
0258 bool HasError : 1;
0259 };
0260
0261 template <class T, class E>
0262 std::enable_if_t<std::is_error_code_enum<E>::value ||
0263 std::is_error_condition_enum<E>::value,
0264 bool>
0265 operator==(const ErrorOr<T> &Err, E Code) {
0266 return Err.getError() == Code;
0267 }
0268
0269 }
0270
0271 #endif