ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Result.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file Result.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #pragma once
10 
11 #include <optional>
12 #include <system_error>
13 #include <type_traits>
14 #include <utility>
15 #include <variant>
16 
17 namespace Acts {
18 
24 template <typename T, typename E = std::error_code>
25 class Result {
31  Result(std::variant<T, E>&& var) : m_var(var) {}
32 
33  public:
37  Result() = delete;
38 
42  Result(const Result<T, E>& other) = delete;
43 
47  Result<T, E>& operator=(const Result<T, E>& other) = delete;
48 
52  Result(Result<T, E>&& other) : m_var(std::move(other.m_var)){};
53 
60  m_var = std::move(other.m_var);
61  return *this;
62  }
63 
78  template <
79  typename T2, typename _E = E, typename _T = T,
80  typename = std::enable_if_t<
81  (!std::is_same_v<_T, _E> && !std::is_constructible_v<_T, _E> &&
82  !std::is_convertible_v<_T, _E> && !std::is_constructible_v<_E, _T> &&
83  !std::is_convertible_v<_E, _T> &&
84  !(std::is_convertible_v<T2, _T> && std::is_convertible_v<T2, _E>))>>
85  Result(T2 value) noexcept
86  : m_var(std::conditional_t<std::is_convertible_v<T2, _T>, T, E>{
87  std::move(value)}) {}
88 
98  template <
99  typename T2, typename _E = E, typename _T = T,
100  typename = std::enable_if_t<
101  (!std::is_same_v<_T, _E> && !std::is_constructible_v<_T, _E> &&
102  !std::is_convertible_v<_T, _E> && !std::is_constructible_v<_E, _T> &&
103  !std::is_convertible_v<_E, _T> &&
104  !(std::is_convertible_v<T2, _T> && std::is_convertible_v<T2, _E>))>>
105  Result<T, E>& operator=(T2 value) noexcept {
106  m_var = std::move(std::conditional_t<std::is_convertible_v<T2, _T>, T, E>{
107  std::move(value)});
108  return *this;
109  }
110 
116  static Result<T, E> success(T value) {
117  return Result<T, E>(
118  std::variant<T, E>{std::in_place_index<0>, std::move(value)});
119  }
120 
126  static Result<T, E> failure(E error) {
127  return Result<T, E>(
128  std::variant<T, E>{std::in_place_index<1>, std::move(error)});
129  }
130 
135  bool ok() const noexcept { return m_var.index() == 0; }
136 
142  T& operator*() noexcept { return std::get<T>(m_var); }
143 
149  E& error() & noexcept { return std::get<E>(m_var); }
150 
156  E error() && noexcept { return std::move(std::get<E>(m_var)); }
157 
163  T& value() & {
164  if (m_var.index() != 0) {
165  if constexpr (std::is_same_v<E, std::error_code>) {
166  std::stringstream ss;
167  const auto& e = std::get<E>(m_var);
168  ss << "Value called on error value: " << e.category().name() << ": "
169  << e.message() << " [" << e.value() << "]";
170  throw std::runtime_error(ss.str());
171  } else {
172  throw std::runtime_error("Value called on error value");
173  }
174  }
175 
176  return std::get<T>(m_var);
177  }
178 
185  T value() && {
186  if (m_var.index() != 0) {
187  if constexpr (std::is_same_v<E, std::error_code>) {
188  std::stringstream ss;
189  const auto& e = std::get<E>(m_var);
190  ss << "Value called on error value: " << e.category().name() << ": "
191  << e.message() << " [" << e.value() << "]";
192  throw std::runtime_error(ss.str());
193  } else {
194  throw std::runtime_error("Value called on error value");
195  }
196  }
197 
198  return std::move(std::get<T>(m_var));
199  }
200 
201  private:
202  std::variant<T, E> m_var;
203 };
204 
218 template <typename E>
219 class Result<void, E> {
220  public:
224  Result() = default;
225 
229  Result(const Result<void, E>& other) = default;
230 
234  Result<void, E>& operator=(const Result<void, E>& other) = default;
235 
240  Result(Result<void, E>&& other) : m_opt(std::move(other.m_opt)){};
241 
247  m_opt = std::move(other.m_opt);
248  return *this;
249  }
250 
256  template <typename E2>
257  Result(E2 error) noexcept : m_opt(std::move(error)) {}
258 
265  template <typename E2>
267  m_opt = std::move(error);
268  return *this;
269  }
270 
275  static Result<void, E> success() { return Result<void, E>(); }
276 
283  return Result<void, E>(std::move(error));
284  }
285 
290  bool ok() const noexcept { return !m_opt; }
291 
297  E& error() & noexcept { return *m_opt; }
298 
304  E error() && noexcept { return std::move(*m_opt); }
305 
306  private:
307  std::optional<E> m_opt;
308 };
309 
310 } // namespace Acts