File indexing completed on 2026-05-05 08:50:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef ROOT_RError
0015 #define ROOT_RError
0016
0017 #include <ROOT/RConfig.hxx> // for R__[un]likely
0018 #include <ROOT/RLogger.hxx> // for R__LOG_PRETTY_FUNCTION
0019
0020 #include <cstddef>
0021 #include <memory>
0022 #include <new>
0023 #include <optional>
0024 #include <stdexcept>
0025 #include <string>
0026 #include <string_view>
0027 #include <utility>
0028 #include <vector>
0029
0030 namespace ROOT {
0031
0032
0033
0034
0035
0036
0037
0038
0039 class RError {
0040 public:
0041 struct RLocation {
0042 RLocation() = default;
0043 RLocation(const char *func, const char *file, unsigned int line)
0044 : fFunction(func), fSourceFile(file), fSourceLine(line)
0045 {
0046 }
0047
0048
0049 const char *fFunction;
0050 const char *fSourceFile;
0051 unsigned int fSourceLine;
0052 };
0053
0054 private:
0055
0056 std::string fMessage;
0057
0058 std::vector<RLocation> fStackTrace;
0059
0060 public:
0061
0062 RError(std::string_view message, RLocation &&sourceLocation);
0063
0064 void AddFrame(RLocation &&sourceLocation);
0065
0066 void AppendToMessage(std::string_view info) { fMessage += info; }
0067
0068 std::string GetReport() const;
0069 const std::vector<RLocation> &GetStackTrace() const { return fStackTrace; }
0070 };
0071
0072
0073
0074
0075
0076
0077
0078
0079 class RException : public std::runtime_error {
0080 RError fError;
0081
0082 public:
0083 explicit RException(const RError &error) : std::runtime_error(error.GetReport()), fError(error) {}
0084 const RError &GetError() const { return fError; }
0085 };
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 class RResultBase {
0099 protected:
0100
0101 std::unique_ptr<RError> fError;
0102
0103 bool fIsChecked{false};
0104
0105 RResultBase() = default;
0106 explicit RResultBase(RError &&error) : fError(std::make_unique<RError>(std::move(error))) {}
0107
0108
0109 bool Check()
0110 {
0111 fIsChecked = true;
0112 return !fError;
0113 }
0114
0115 public:
0116 RResultBase(const RResultBase &other) = delete;
0117 RResultBase(RResultBase &&other) = default;
0118 RResultBase &operator=(const RResultBase &other) = delete;
0119 RResultBase &operator=(RResultBase &&other) = default;
0120
0121 ~RResultBase() noexcept(false);
0122
0123 std::optional<RError> GetError() const { return fError ? *fError : std::optional<RError>(); }
0124
0125 void Throw();
0126
0127
0128 [[nodiscard]]
0129 static RError ForwardError(RResultBase &&result, RError::RLocation &&sourceLocation)
0130 {
0131 if (!result.fError) {
0132 return RError("internal error: attempt to forward error of successful operation", std::move(sourceLocation));
0133 }
0134 result.fError->AddFrame(std::move(sourceLocation));
0135 return *result.fError;
0136 }
0137 };
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 template <typename T>
0198 class RResult : public RResultBase {
0199 private:
0200
0201 std::optional<T> fValue;
0202
0203
0204 inline void ThrowOnError()
0205 {
0206 if (R__unlikely(fError)) {
0207
0208
0209
0210
0211 fIsChecked = true;
0212
0213 fError->AppendToMessage(" (unchecked RResult access!)");
0214 throw RException(*fError);
0215 }
0216 }
0217
0218 public:
0219 RResult(const T &value) : fValue(value) {}
0220 RResult(T &&value) : fValue(std::move(value)) {}
0221 RResult(RError &&error) : RResultBase(std::move(error)) {}
0222
0223 RResult(const RResult &other) = delete;
0224 RResult(RResult &&other) = default;
0225 RResult &operator=(const RResult &other) = delete;
0226 RResult &operator=(RResult &&other) = default;
0227
0228 ~RResult() = default;
0229
0230
0231 RResult &Forward(RError::RLocation &&sourceLocation)
0232 {
0233 if (fError)
0234 fError->AddFrame(std::move(sourceLocation));
0235 return *this;
0236 }
0237
0238
0239
0240 const T &Inspect()
0241 {
0242 ThrowOnError();
0243 return *fValue;
0244 }
0245
0246
0247
0248
0249
0250
0251
0252
0253 T Unwrap()
0254 {
0255 ThrowOnError();
0256 return std::move(*fValue);
0257 }
0258
0259 explicit operator bool() { return Check(); }
0260 };
0261
0262
0263 template <>
0264 class RResult<void> : public RResultBase {
0265 private:
0266 RResult() = default;
0267
0268 public:
0269
0270 static RResult Success() { return RResult(); }
0271 RResult(RError &&error) : RResultBase(std::move(error)) {}
0272
0273 RResult(const RResult &other) = delete;
0274 RResult(RResult &&other) = default;
0275 RResult &operator=(const RResult &other) = delete;
0276 RResult &operator=(RResult &&other) = default;
0277
0278 ~RResult() = default;
0279
0280
0281 RResult &Forward(RError::RLocation &&sourceLocation)
0282 {
0283 if (fError)
0284 fError->AddFrame(std::move(sourceLocation));
0285 return *this;
0286 }
0287
0288
0289
0290 void ThrowOnError()
0291 {
0292 if (!Check())
0293 Throw();
0294 }
0295
0296 explicit operator bool() { return Check(); }
0297 };
0298
0299
0300 #define R__FAIL(msg) ROOT::RError(msg, {R__LOG_PRETTY_FUNCTION, __FILE__, __LINE__})
0301
0302 #define R__FORWARD_RESULT(res) std::move(res.Forward({R__LOG_PRETTY_FUNCTION, __FILE__, __LINE__}))
0303
0304 #define R__FORWARD_ERROR(res) res.ForwardError(std::move(res), {R__LOG_PRETTY_FUNCTION, __FILE__, __LINE__})
0305
0306 }
0307
0308 #endif