Lumiera  0.pre.03
»edit your freedom«
result.hpp
Go to the documentation of this file.
1 /*
2  RESULT.hpp - intermediary token representing the result of an operation
3 
4  Copyright (C)
5  2010, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
37 #ifndef LIB_RESULT_H
38 #define LIB_RESULT_H
39 
40 #include "lib/error.hpp"
41 #include "lib/wrapper.hpp"
42 #include "lib/meta/util.hpp"
43 #include "lib/null-value.hpp"
44 
45 #include <type_traits>
46 #include <exception>
47 #include <utility>
48 
49 
50 
51 namespace lib {
52 
53  namespace error = lumiera::error;
54 
63  template<class FUN, typename...ARGS>
64  inline auto
65  failsafeInvoke (std::exception_ptr& capturedFailure
66  ,FUN&& callable
67  ,ARGS&& ...args) noexcept
68  {
69  using Res = std::invoke_result_t<FUN,ARGS...>;
70  try {
71  capturedFailure = nullptr;
72  if constexpr (std::is_void_v<Res>)
73  std::invoke (std::forward<FUN>(callable), std::forward<ARGS>(args)...);
74  else
75  return std::invoke (std::forward<FUN>(callable), std::forward<ARGS>(args)...);
76  }
77  catch(...)
78  {
79  capturedFailure = std::current_exception();
80  if constexpr (not std::is_void_v<Res>)
81  return lib::NullValue<Res>::get();
82  }
83  }
84 
85 
86 
96  template<typename RES>
97  class Result;
98 
99 
104  template<>
105  class Result<void>
106  {
107  protected:
108  std::exception_ptr failure_;
109 
110  public:
112  Result (bool success =false)
113  : failure_{success? nullptr: std::make_exception_ptr (error::State{"operation failed"})}
114  { }
115 
117  Result (lumiera::Error const& reason)
118  : failure_{std::make_exception_ptr (reason)}
119  { }
120 
122  template<class FUN, typename...ARGS, typename=lib::meta::enable_if<std::is_invocable<FUN,ARGS...>>>
123  Result (FUN&& callable, ARGS&& ...args) noexcept
124  : failure_{}
125  {
126  failsafeInvoke (failure_
127  ,std::forward<FUN> (callable)
128  ,std::forward<ARGS>(args)...);
129  }
130 
131  explicit
132  operator bool() const { return isValid(); }
133  bool isValid() const { return not failure_; }
134 
135  void
136  maybeThrow() const
137  {
138  if (failure_)
139  std::rethrow_exception(failure_);
140  }
141  };
142 
143 
153  template<typename RES>
154  class Result
155  : public Result<void>
156  {
158 
159  public:
161  Result (lumiera::Error const& reason)
162  : Result<void>{reason}
163  { }
164 
166  template< typename=lib::meta::disable_if<std::is_invocable<RES>>>
167  Result (RES&& value)
168  : Result<void>{true}
169  , value_{std::forward<RES> (value)}
170  { }
171 
173  template<class FUN, typename...ARGS, typename=lib::meta::enable_if<std::is_invocable<FUN,ARGS...>>>
174  Result (FUN&& callable, ARGS&& ...args) noexcept
175  : Result<void>{true}
176  , value_{failsafeInvoke (failure_
177  ,std::forward<FUN> (callable)
178  ,std::forward<ARGS>(args)...)}
179  { }
180 
181  // is or is not copyable depending on RES
182 
183 
184  operator RES() const
185  {
186  maybeThrow();
187  return *value_;
188  }
189 
190  template<typename TY =RES>
191  TY
192  get() const
193  {
194  maybeThrow();
195  return static_cast<TY> (*value_);
196  }
197 
198  template<typename O>
199  RES
200  value_or (O&& defaultVal)
201  {
202  return isValid()? *value_ : std::forward<O> (defaultVal);
203  }
204 
205  template<typename MAKE, typename...ARGS>
206  RES
207  or_else (MAKE&& producer, ARGS ...args)
208  {
209  if (isValid())
210  return *value_;
211  else
212  return std::invoke(std::forward<MAKE> (producer), std::forward<ARGS> (args)...);
213  }
214  };
215 
217  template<typename VAL, typename=lib::meta::disable_if<std::is_invocable<VAL>>>
218  Result (VAL&&) -> Result<VAL>;
219 
221  template<typename FUN, typename...ARGS>
222  Result (FUN&&, ARGS&&...) -> Result<std::invoke_result_t<FUN,ARGS...>>;
223 
224 
225 
226 } // namespace lib
227 #endif
The base case is just to capture success or failure, without returning any value result.
Definition: result.hpp:105
Representation of the result of some operation, EITHER a value or a failure.
Definition: result.hpp:97
Result(lumiera::Error const &reason)
mark failed result, with reason given.
Definition: result.hpp:161
Simple and lightweight helpers for metaprogramming and type detection.
Singleton holder for NIL or default value objects.
Definition: null-value.hpp:62
Result(lumiera::Error const &reason)
failed result, with reason given.
Definition: result.hpp:117
Singleton-style holder for NIL or default values.
Implementation namespace for support and library code.
typename enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition: meta/util.hpp:83
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
void maybeThrow(string description="")
Check the lumiera error state and throw a specific exception in case a non-cleared errorflag is detec...
Definition: error.hpp:249
Lumiera error handling (C++ interface).
Result(bool success=false)
mark either failure (default) or success
Definition: result.hpp:112
auto failsafeInvoke(std::exception_ptr &capturedFailure, FUN &&callable, ARGS &&...args) noexcept
Helper to invoke an arbitrary callable in a failsafe way.
Definition: result.hpp:65
Result(FUN &&callable, ARGS &&...args) noexcept
invoke a callable and mark success or failure
Definition: result.hpp:123
Library implementation: smart-pointer variations, wrappers and managing holders.
Interface and Base definition for all Lumiera Exceptions.
Definition: error.hpp:62