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  const T& get() const
74  {
75  if (!data.isSome()) {
76  assert(error_.isSome());
77  ABORT("Try::get() but state == ERROR: " + error_.get().message);
78  }
79  return data.get();
80  }
81 
82  T& get()
83  {
84  return const_cast<T&>(static_cast<const Try&>(*this).get());
85  }
86 
87  const T* operator->() const { return &get(); }
88  T* operator->() { return &get(); }
89 
90  // NOTE: This function is intended to return the error of type `E`.
91  // However, we return a `std::string` if `E` == `Error` since that's what it
92  // used to return, and it's the only data that `Error` holds anyway.
93  const typename std::conditional<
94  std::is_same<E, Error>::value, std::string, E>::type& error() const
95  {
96  assert(data.isNone());
97  assert(error_.isSome());
98  return error_impl(error_.get());
99  }
100 
101 private:
102  static const std::string& error_impl(const Error& err) { return err.message; }
103 
104  template <typename Err>
105  static const Err& error_impl(const Err& err) { return err; }
106 
107  // We leverage Option<T> to avoid dynamic allocation of T. This
108  // means that the storage for T will be included in this object
109  // (Try<T>). Since Option<T> keeps track of whether a value is
110  // stored, we just ask it when we want to know whether we are
111  // storing a value or an error. Another advantage of leveraging
112  // Option<T> is that it takes care of all the manual construction
113  // and destruction. This makes the code for Try<T> really simple!
114  Option<T> data;
115  Option<E> error_;
116 };
117 
118 
119 #endif // __STOUT_TRY_HPP__
Definition: errorbase.hpp:35
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:94
Definition: try.hpp:34
T * operator->()
Definition: try.hpp:88
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:45
_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:87
const T & get() const
Definition: try.hpp:73