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 <sstream>
13 #include <system_error>
14 #include <type_traits>
15 #include <utility>
16 #include <variant>
17 
18 namespace Acts {
19 
25 template <typename T, typename E = std::error_code>
26 class Result {
32  Result(std::variant<T, E>&& var) : m_var(std::move(var)) {}
33 
34  public:
38  Result() = delete;
39 
43  Result(const Result<T, E>& other) = delete;
44 
48  Result<T, E>& operator=(const Result<T, E>& other) = delete;
49 
53  Result(Result<T, E>&& other) : m_var(std::move(other.m_var)){};
54 
61  m_var = std::move(other.m_var);
62  return *this;
63  }
64 
79  template <
80  typename T2, typename _E = E, typename _T = T,
81  typename = std::enable_if_t<
82  (!std::is_same_v<_T, _E> && !std::is_constructible_v<_T, _E> &&
83  !std::is_convertible_v<_T, _E> && !std::is_constructible_v<_E, _T> &&
84  !std::is_convertible_v<_E, _T> &&
85  !(std::is_convertible_v<T2, _T> && std::is_convertible_v<T2, _E>))>>
86  Result(T2 value) noexcept
87  : m_var(std::conditional_t<std::is_convertible_v<T2, _T>, T, E>{
88  std::move(value)}) {}
89 
99  template <
100  typename T2, typename _E = E, typename _T = T,
101  typename = std::enable_if_t<
102  (!std::is_same_v<_T, _E> && !std::is_constructible_v<_T, _E> &&
103  !std::is_convertible_v<_T, _E> && !std::is_constructible_v<_E, _T> &&
104  !std::is_convertible_v<_E, _T> &&
105  !(std::is_convertible_v<T2, _T> && std::is_convertible_v<T2, _E>))>>
106  Result<T, E>& operator=(T2 value) noexcept {
107  m_var = std::move(std::conditional_t<std::is_convertible_v<T2, _T>, T, E>{
108  std::move(value)});
109  return *this;
110  }
111 
117  static Result<T, E> success(T value) {
118  return Result<T, E>(
119  std::variant<T, E>{std::in_place_index<0>, std::move(value)});
120  }
121 
127  static Result<T, E> failure(E error) {
128  return Result<T, E>(
129  std::variant<T, E>{std::in_place_index<1>, std::move(error)});
130  }
131 
136  bool ok() const noexcept { return m_var.index() == 0; }
137 
143  T& operator*() noexcept { return std::get<T>(m_var); }
144 
150  E& error() & noexcept { return std::get<E>(m_var); }
151 
157  E error() && noexcept { return std::move(std::get<E>(m_var)); }
158 
164  T& value() & {
165  if (m_var.index() != 0) {
166  if constexpr (std::is_same_v<E, std::error_code>) {
167  std::stringstream ss;
168  const auto& e = std::get<E>(m_var);
169  ss << "Value called on error value: " << e.category().name() << ": "
170  << e.message() << " [" << e.value() << "]";
171  throw std::runtime_error(ss.str());
172  } else {
173  throw std::runtime_error("Value called on error value");
174  }
175  }
176 
177  return std::get<T>(m_var);
178  }
179 
186  T value() && {
187  if (m_var.index() != 0) {
188  if constexpr (std::is_same_v<E, std::error_code>) {
189  std::stringstream ss;
190  const auto& e = std::get<E>(m_var);
191  ss << "Value called on error value: " << e.category().name() << ": "
192  << e.message() << " [" << e.value() << "]";
193  throw std::runtime_error(ss.str());
194  } else {
195  throw std::runtime_error("Value called on error value");
196  }
197  }
198 
199  return std::move(std::get<T>(m_var));
200  }
201 
202  private:
203  std::variant<T, E> m_var;
204 };
205 
219 template <typename E>
220 class Result<void, E> {
221  public:
225  Result() = default;
226 
230  Result(const Result<void, E>& other) = default;
231 
235  Result<void, E>& operator=(const Result<void, E>& other) = default;
236 
241  Result(Result<void, E>&& other) : m_opt(std::move(other.m_opt)){};
242 
248  m_opt = std::move(other.m_opt);
249  return *this;
250  }
251 
257  template <typename E2>
258  Result(E2 error) noexcept : m_opt(std::move(error)) {}
259 
266  template <typename E2>
268  m_opt = std::move(error);
269  return *this;
270  }
271 
276  static Result<void, E> success() { return Result<void, E>(); }
277 
283  static Result<void, E> failure(E error) {
284  return Result<void, E>(std::move(error));
285  }
286 
291  bool ok() const noexcept { return !m_opt; }
292 
298  E& error() & noexcept { return *m_opt; }
299 
305  E error() && noexcept { return std::move(*m_opt); }
306 
307  private:
308  std::optional<E> m_opt;
309 };
310 
311 } // namespace Acts