Apache Mesos
try.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_TRY_HPP__
14 #define __STOUT_TRY_HPP__
15 
16 #include <assert.h>
17 
18 #include <iostream>
19 #include <string>
20 
21 #include <stout/abort.hpp>
22 #include <stout/error.hpp>
23 #include <stout/option.hpp>
24 #include <stout/some.hpp>
25 
26 // This class can represent only one of these states at a time:
27 // 1) A value of T.
28 // 2) An error state, with a corresponding error string.
29 // Calling 'isSome' will return true if it stores a value, in which
30 // case calling 'get' will return a constant reference to the T
31 // stored. Calling 'isError' will return true if it stores an error,
32 // in which case calling 'error' will return the error string.
33 template <typename T, typename E = Error>
34 class Try
35 {
36 public:
37  static_assert(
38  std::is_base_of<Error, E>::value,
39  "An error type must be, or be inherited from 'Error'.");
40 
41  static Try some(const T& t) { return Try(t); }
42  static Try error(const E& e) { return Try(e); }
43 
44  Try(const T& t)
45  : data(Some(t)) {}
46 
47  template <
48  typename U,
49  typename = typename std::enable_if<
50  std::is_constructible<T, const U&>::value>::type>
51  Try(const U& u) : data(Some(u)) {}
52 
53  Try(const E& error) : error_(error) {}
54 
55  Try(T&& t)
56  : data(Some(std::move(t))) {}
57 
58  // We don't need to implement these because we are leveraging
59  // Option<T>.
60  Try(const Try& that) = default;
61  Try(Try&& that) = default;
62 
63  ~Try() = default;
64 
65  Try& operator=(const Try& that) = default;
66  Try& operator=(Try&& that) = default;
67 
68  // 'isSome' and 'isError' are mutually exclusive. They correspond
69  // to the underlying state of the Option.
70  bool isSome() const { return data.isSome(); }
71  bool isError() const { return data.isNone(); }
72 
73  T& get() & { return get(*this); }
74  const T& get() const & { return get(*this); }
75  T&& get() && { return get(std::move(*this)); }
76  const T&& get() const && { return get(std::move(*this)); }
77 
78  const T* operator->() const { return &get(); }
79  T* operator->() { return &get(); }
80 
81  // NOTE: This function is intended to return the error of type `E`.
82  // However, we return a `std::string` if `E` == `Error` since that's what it
83  // used to return, and it's the only data that `Error` holds anyway.
84  const typename std::conditional<
85  std::is_same<E, Error>::value, std::string, E>::type& error() const
86  {
87  assert(data.isNone());
88  assert(error_.isSome());
89  return error_impl(error_.get());
90  }
91 
92 private:
93  static const std::string& error_impl(const Error& err) { return err.message; }
94 
95  template <typename Self>
96  static auto get(Self&& self) -> decltype(std::forward<Self>(self).data.get())
97  {
98  if (!self.data.isSome()) {
99  assert(self.error_.isSome());
100  ABORT("Try::get() but state == ERROR: " + self.error_->message);
101  }
102  return std::forward<Self>(self).data.get();
103  }
104 
105  template <typename Err>
106  static const Err& error_impl(const Err& err) { return err; }
107 
108  // We leverage Option<T> to avoid dynamic allocation of T. This
109  // means that the storage for T will be included in this object
110  // (Try<T>). Since Option<T> keeps track of whether a value is
111  // stored, we just ask it when we want to know whether we are
112  // storing a value or an error. Another advantage of leveraging
113  // Option<T> is that it takes care of all the manual construction
114  // and destruction. This makes the code for Try<T> really simple!
115  Option<T> data;
116  Option<E> error_;
117 };
118 
119 
120 #endif // __STOUT_TRY_HPP__
Definition: errorbase.hpp:36
Definition: option.hpp:28
#define ABORT(...)
Definition: abort.hpp:40
const std::conditional< std::is_same< E, Error >::value, std::string, E >::type & error() const
Definition: try.hpp:85
Definition: check.hpp:33
T * operator->()
Definition: try.hpp:79
Definition: type_utils.hpp:550
bool isSome() const
Definition: option.hpp:115
Try(const E &error)
Definition: try.hpp:53
bool isSome() const
Definition: try.hpp:70
const T & get() const &
Definition: option.hpp:118
static Try error(const E &e)
Definition: try.hpp:42
Try(T &&t)
Definition: try.hpp:55
static Try some(const T &t)
Definition: try.hpp:41
const std::string message
Definition: errorbase.hpp:46
_Some< typename std::decay< T >::type > Some(T &&t)
Definition: some.hpp:42
bool isError() const
Definition: try.hpp:71
~Try()=default
Try(const T &t)
Definition: try.hpp:44
Try< uint32_t > type(const std::string &path)
Try(const U &u)
Definition: try.hpp:51
Try & operator=(const Try &that)=default
const T * operator->() const
Definition: try.hpp:78