xgboost
result.h
Go to the documentation of this file.
1 
4 #pragma once
5 
6 #include <cstdint> // for int32_t
7 #include <memory> // for unique_ptr
8 #include <string> // for string
9 #include <system_error> // for error_code
10 #include <utility> // for move
11 
13 namespace detail {
14 struct ResultImpl {
15  std::string message;
16  std::error_code errc{}; // optional for system error.
17 
18  std::unique_ptr<ResultImpl> prev{nullptr};
19 
20  ResultImpl() = delete; // must initialize.
21  ResultImpl(ResultImpl const& that) = delete;
22  ResultImpl(ResultImpl&& that) = default;
23  ResultImpl& operator=(ResultImpl const& that) = delete;
24  ResultImpl& operator=(ResultImpl&& that) = default;
25 
26  explicit ResultImpl(std::string msg) : message{std::move(msg)} {}
27  explicit ResultImpl(std::string msg, std::error_code errc)
28  : message{std::move(msg)}, errc{std::move(errc)} {}
29  explicit ResultImpl(std::string msg, std::unique_ptr<ResultImpl> prev)
30  : message{std::move(msg)}, prev{std::move(prev)} {}
31  explicit ResultImpl(std::string msg, std::error_code errc, std::unique_ptr<ResultImpl> prev)
32  : message{std::move(msg)}, errc{std::move(errc)}, prev{std::move(prev)} {}
33 
34  [[nodiscard]] bool operator==(ResultImpl const& that) const noexcept(true) {
35  if ((prev && !that.prev) || (!prev && that.prev)) {
36  // one of them doesn't have prev
37  return false;
38  }
39 
40  auto cur_eq = message == that.message && errc == that.errc;
41  if (prev && that.prev) {
42  // recursive comparison
43  auto prev_eq = *prev == *that.prev;
44  return cur_eq && prev_eq;
45  }
46  return cur_eq;
47  }
48 
49  [[nodiscard]] std::string Report() const;
50  [[nodiscard]] std::error_code Code() const;
51 
52  void Concat(std::unique_ptr<ResultImpl> rhs);
53 };
54 
55 #if (!defined(__GNUC__) && !defined(__clang__)) || defined(__MINGW32__)
56 #define __builtin_FILE() nullptr
57 #define __builtin_LINE() (-1)
58 std::string MakeMsg(std::string&& msg, char const*, std::int32_t);
59 #else
60 std::string MakeMsg(std::string&& msg, char const* file, std::int32_t line);
61 #endif
62 } // namespace detail
63 
68 struct Result {
69  private:
70  std::unique_ptr<detail::ResultImpl> impl_{nullptr};
71 
72  public:
73  Result() noexcept(true) = default;
74  explicit Result(std::string msg) : impl_{std::make_unique<detail::ResultImpl>(std::move(msg))} {}
75  explicit Result(std::string msg, std::error_code errc)
76  : impl_{std::make_unique<detail::ResultImpl>(std::move(msg), std::move(errc))} {}
77  Result(std::string msg, Result&& prev)
78  : impl_{std::make_unique<detail::ResultImpl>(std::move(msg), std::move(prev.impl_))} {}
79  Result(std::string msg, std::error_code errc, Result&& prev)
80  : impl_{std::make_unique<detail::ResultImpl>(std::move(msg), std::move(errc),
81  std::move(prev.impl_))} {}
82 
83  Result(Result const& that) = delete;
84  Result& operator=(Result const& that) = delete;
85  Result(Result&& that) = default;
86  Result& operator=(Result&& that) = default;
87 
88  [[nodiscard]] bool OK() const noexcept(true) { return !impl_; }
89  [[nodiscard]] std::string Report() const { return OK() ? "" : impl_->Report(); }
93  [[nodiscard]] auto Code() const { return OK() ? std::error_code{} : impl_->Code(); }
94  [[nodiscard]] bool operator==(Result const& that) const noexcept(true) {
95  if (OK() && that.OK()) {
96  return true;
97  }
98  if ((OK() && !that.OK()) || (!OK() && that.OK())) {
99  return false;
100  }
101  return *impl_ == *that.impl_;
102  }
103 
104  friend Result operator+(Result&& lhs, Result&& rhs);
105 };
106 
107 [[nodiscard]] inline Result operator+(Result&& lhs, Result&& rhs) {
108  if (lhs.OK()) {
109  return std::forward<Result>(rhs);
110  }
111  if (rhs.OK()) {
112  return std::forward<Result>(lhs);
113  }
114  lhs.impl_->Concat(std::move(rhs.impl_));
115  return std::forward<Result>(lhs);
116 }
117 
121 [[nodiscard]] inline auto Success() noexcept(true) { return Result{}; }
125 [[nodiscard]] inline auto Fail(std::string msg, char const* file = __builtin_FILE(),
126  std::int32_t line = __builtin_LINE()) {
127  return Result{detail::MakeMsg(std::move(msg), file, line)};
128 }
132 [[nodiscard]] inline auto Fail(std::string msg, std::error_code errc,
133  char const* file = __builtin_FILE(),
134  std::int32_t line = __builtin_LINE()) {
135  return Result{detail::MakeMsg(std::move(msg), file, line), std::move(errc)};
136 }
140 [[nodiscard]] inline auto Fail(std::string msg, Result&& prev, char const* file = __builtin_FILE(),
141  std::int32_t line = __builtin_LINE()) {
142  return Result{detail::MakeMsg(std::move(msg), file, line), std::forward<Result>(prev)};
143 }
147 [[nodiscard]] inline auto Fail(std::string msg, std::error_code errc, Result&& prev,
148  char const* file = __builtin_FILE(),
149  std::int32_t line = __builtin_LINE()) {
150  return Result{detail::MakeMsg(std::move(msg), file, line), std::move(errc),
151  std::forward<Result>(prev)};
152 }
153 
154 // We don't have monad, a simple helper would do.
155 template <typename Fn>
156 [[nodiscard]] std::enable_if_t<std::is_invocable_v<Fn>, Result> operator<<(Result&& r, Fn&& fn) {
157  if (!r.OK()) {
158  return std::forward<Result>(r);
159  }
160  return fn();
161 }
162 
163 void SafeColl(Result const& rc);
164 } // namespace xgboost::collective
Definition: intrusive_ptr.h:207
std::string MakeMsg(std::string &&msg, char const *, std::int32_t)
Definition: result.h:12
std::enable_if_t< std::is_invocable_v< Fn >, Result > operator<<(Result &&r, Fn &&fn)
Definition: result.h:156
auto Fail(std::string msg, char const *file=__builtin_FILE(), std::int32_t line=__builtin_LINE())
Return failure.
Definition: result.h:125
void SafeColl(Result const &rc)
auto Success() noexcept(true)
Return success.
Definition: result.h:121
Result operator+(Result &&lhs, Result &&rhs)
Definition: result.h:107
#define __builtin_LINE()
Definition: result.h:57
#define __builtin_FILE()
Definition: result.h:56
An error type that's easier to handle than throwing dmlc exception. We can record and propagate the s...
Definition: result.h:68
Result(std::string msg, std::error_code errc, Result &&prev)
Definition: result.h:79
std::string Report() const
Definition: result.h:89
Result(Result const &that)=delete
bool operator==(Result const &that) const noexcept(true)
Definition: result.h:94
friend Result operator+(Result &&lhs, Result &&rhs)
Definition: result.h:107
Result & operator=(Result &&that)=default
Result() noexcept(true)=default
auto Code() const
Return the root system error. This might return success if there's no system error.
Definition: result.h:93
Result(std::string msg, std::error_code errc)
Definition: result.h:75
Result & operator=(Result const &that)=delete
Result(Result &&that)=default
Result(std::string msg, Result &&prev)
Definition: result.h:77
bool OK() const noexcept(true)
Definition: result.h:88
void Concat(std::unique_ptr< ResultImpl > rhs)
std::string message
Definition: result.h:15
ResultImpl & operator=(ResultImpl const &that)=delete
ResultImpl(std::string msg)
Definition: result.h:26
ResultImpl(std::string msg, std::error_code errc)
Definition: result.h:27
ResultImpl & operator=(ResultImpl &&that)=default
ResultImpl(std::string msg, std::unique_ptr< ResultImpl > prev)
Definition: result.h:29
ResultImpl(ResultImpl &&that)=default
std::error_code errc
Definition: result.h:16
bool operator==(ResultImpl const &that) const noexcept(true)
Definition: result.h:34
ResultImpl(ResultImpl const &that)=delete
ResultImpl(std::string msg, std::error_code errc, std::unique_ptr< ResultImpl > prev)
Definition: result.h:31
std::unique_ptr< ResultImpl > prev
Definition: result.h:18