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 #endif
59 
60 std::string MakeMsg(std::string&& msg, char const* file, std::int32_t line);
61 } // namespace detail
62 
67 struct Result {
68  private:
69  std::unique_ptr<detail::ResultImpl> impl_{nullptr};
70 
71  public:
72  Result() noexcept(true) = default;
73  explicit Result(std::string msg) : impl_{std::make_unique<detail::ResultImpl>(std::move(msg))} {}
74  explicit Result(std::string msg, std::error_code errc)
75  : impl_{std::make_unique<detail::ResultImpl>(std::move(msg), std::move(errc))} {}
76  Result(std::string msg, Result&& prev)
77  : impl_{std::make_unique<detail::ResultImpl>(std::move(msg), std::move(prev.impl_))} {}
78  Result(std::string msg, std::error_code errc, Result&& prev)
79  : impl_{std::make_unique<detail::ResultImpl>(std::move(msg), std::move(errc),
80  std::move(prev.impl_))} {}
81 
82  Result(Result const& that) = delete;
83  Result& operator=(Result const& that) = delete;
84  Result(Result&& that) = default;
85  Result& operator=(Result&& that) = default;
86 
87  [[nodiscard]] bool OK() const noexcept(true) { return !impl_; }
88  [[nodiscard]] std::string Report() const { return OK() ? "" : impl_->Report(); }
92  [[nodiscard]] auto Code() const { return OK() ? std::error_code{} : impl_->Code(); }
93  [[nodiscard]] bool operator==(Result const& that) const noexcept(true) {
94  if (OK() && that.OK()) {
95  return true;
96  }
97  if ((OK() && !that.OK()) || (!OK() && that.OK())) {
98  return false;
99  }
100  return *impl_ == *that.impl_;
101  }
102 
103  friend Result operator+(Result&& lhs, Result&& rhs);
104 };
105 
106 [[nodiscard]] inline Result operator+(Result&& lhs, Result&& rhs) {
107  if (lhs.OK()) {
108  return std::forward<Result>(rhs);
109  }
110  if (rhs.OK()) {
111  return std::forward<Result>(lhs);
112  }
113  lhs.impl_->Concat(std::move(rhs.impl_));
114  return std::forward<Result>(lhs);
115 }
116 
120 [[nodiscard]] inline auto Success() noexcept(true) { return Result{}; }
124 [[nodiscard]] inline auto Fail(std::string msg, char const* file = __builtin_FILE(),
125  std::int32_t line = __builtin_LINE()) {
126  return Result{detail::MakeMsg(std::move(msg), file, line)};
127 }
131 [[nodiscard]] inline auto Fail(std::string msg, std::error_code errc,
132  char const* file = __builtin_FILE(),
133  std::int32_t line = __builtin_LINE()) {
134  return Result{detail::MakeMsg(std::move(msg), file, line), std::move(errc)};
135 }
139 [[nodiscard]] inline auto Fail(std::string msg, Result&& prev, char const* file = __builtin_FILE(),
140  std::int32_t line = __builtin_LINE()) {
141  return Result{detail::MakeMsg(std::move(msg), file, line), std::forward<Result>(prev)};
142 }
146 [[nodiscard]] inline auto Fail(std::string msg, std::error_code errc, Result&& prev,
147  char const* file = __builtin_FILE(),
148  std::int32_t line = __builtin_LINE()) {
149  return Result{detail::MakeMsg(std::move(msg), file, line), std::move(errc),
150  std::forward<Result>(prev)};
151 }
152 
153 // We don't have monad, a simple helper would do.
154 template <typename Fn>
155 [[nodiscard]] std::enable_if_t<std::is_invocable_v<Fn>, Result> operator<<(Result&& r, Fn&& fn) {
156  if (!r.OK()) {
157  return std::forward<Result>(r);
158  }
159  return fn();
160 }
161 
162 void SafeColl(Result const& rc);
163 } // namespace xgboost::collective
Definition: intrusive_ptr.h:207
std::string MakeMsg(std::string &&msg, char const *file, std::int32_t line)
Definition: result.h:12
std::enable_if_t< std::is_invocable_v< Fn >, Result > operator<<(Result &&r, Fn &&fn)
Definition: result.h:155
auto Fail(std::string msg, char const *file=__builtin_FILE(), std::int32_t line=__builtin_LINE())
Return failure.
Definition: result.h:124
void SafeColl(Result const &rc)
auto Success() noexcept(true)
Return success.
Definition: result.h:120
Result operator+(Result &&lhs, Result &&rhs)
Definition: result.h:106
#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:67
Result(std::string msg, std::error_code errc, Result &&prev)
Definition: result.h:78
std::string Report() const
Definition: result.h:88
Result(Result const &that)=delete
bool operator==(Result const &that) const noexcept(true)
Definition: result.h:93
friend Result operator+(Result &&lhs, Result &&rhs)
Definition: result.h:106
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:92
Result(std::string msg, std::error_code errc)
Definition: result.h:74
Result & operator=(Result const &that)=delete
Result(Result &&that)=default
Result(std::string msg, Result &&prev)
Definition: result.h:76
bool OK() const noexcept(true)
Definition: result.h:87
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