Apache Mesos
result.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_RESULT_HPP__
14 #define __STOUT_RESULT_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/none.hpp>
24 #include <stout/option.hpp>
25 #include <stout/some.hpp>
26 #include <stout/try.hpp>
27 
28 // This class is equivalent to Try<Option<T>> and can represent only
29 // one of these states at a time:
30 // 1) A value of T.
31 // 2) No value of T.
32 // 3) An error state, with a corresponding error string.
33 // Calling 'isSome' will return true if it stores a value, in which
34 // case calling 'get' will return a constant reference to the T
35 // stored. Calling 'isNone' returns true if no value is stored and
36 // there is no error. Calling 'isError' will return true if it stores
37 // an error, in which case calling 'error' will return the error
38 // string.
39 template <typename T>
40 class Result
41 {
42 public:
43  static Result<T> none()
44  {
45  return Result<T>(None());
46  }
47 
48  static Result<T> some(const T& t)
49  {
50  return Result<T>(t);
51  }
52 
53  static Result<T> error(const std::string& message)
54  {
55  return Result<T>(Error(message));
56  }
57 
58  Result(const T& _t)
59  : data(Some(_t)) {}
60 
61  Result(T&& _t)
62  : data(Some(std::move(_t))) {}
63 
64  template <
65  typename U,
66  typename = typename std::enable_if<
67  std::is_constructible<T, const U&>::value>::type>
68  Result(const U& u)
69  : data(Some(u)) {}
70 
71  Result(const Option<T>& option)
72  : data(option.isSome() ?
73  Try<Option<T>>(Some(option.get())) :
74  Try<Option<T>>(None())) {}
75 
76  Result(const Try<T>& _t)
77  : data(_t.isSome() ?
78  Try<Option<T>>(Some(_t.get())) :
79  Try<Option<T>>(Error(_t.error()))) {}
80 
81  Result(const None& none)
82  : data(none) {}
83 
84  template <typename U>
86  : data(some) {}
87 
88  Result(const Error& error)
89  : data(error) {}
90 
92  : data(error) {}
93 
94 #ifdef __WINDOWS__
95  Result(const WindowsError& error)
96  : data(error) {}
97 #endif // __WINDOWS__
98 
99  // We don't need to implement these because we are leveraging
100  // Try<Option<T>>.
101  Result(const Result<T>& that) = default;
102  Result(Result&& that) = default;
103 
104  ~Result() = default;
105 
106  Result<T>& operator=(const Result<T>& that) = default;
107  Result<T>& operator=(Result<T>&& that) = default;
108 
109  // 'isSome', 'isNone', and 'isError' are mutually exclusive. They
110  // correspond to the underlying unioned state of the Option and Try.
111  bool isSome() const { return data.isSome() && data->isSome(); }
112  bool isNone() const { return data.isSome() && data->isNone(); }
113  bool isError() const { return data.isError(); }
114 
115  const T& get() const
116  {
117  if (!isSome()) {
118  std::string errorMessage = "Result::get() but state == ";
119  if (isError()) {
120  errorMessage += "ERROR: " + data.error();
121  } else if (isNone()) {
122  errorMessage += "NONE";
123  }
124  ABORT(errorMessage);
125  }
126  return data->get();
127  }
128 
129  T& get()
130  {
131  return const_cast<T&>(static_cast<const Result&>(*this).get());
132  }
133 
134  const T* operator->() const { return &get(); }
135  T* operator->() { return &get(); }
136 
137  const std::string& error() const { assert(isError()); return data.error(); }
138 
139 private:
140  // We leverage Try<Option<T>> to avoid dynamic allocation of T. This
141  // means we can take advantage of all the RAII features of 'Try' and
142  // makes the implementation of this class much simpler!
143  Try<Option<T>> data;
144 };
145 
146 #endif // __STOUT_RESULT_HPP__
bool isNone() const
Definition: result.hpp:112
Definition: errorbase.hpp:35
Result(const _Some< U > &some)
Definition: result.hpp:85
Definition: option.hpp:28
#define ABORT(...)
Definition: abort.hpp:40
Result(const Try< T > &_t)
Definition: result.hpp:76
T & get()&
Definition: try.hpp:73
~Result()=default
Definition: check.hpp:33
Result(const U &u)
Definition: result.hpp:68
static Result< T > error(const std::string &message)
Definition: result.hpp:53
Definition: error.hpp:106
Result< T > & operator=(const Result< T > &that)=default
Definition: type_utils.hpp:510
Definition: errorbase.hpp:49
const T * operator->() const
Definition: result.hpp:134
Definition: check.hpp:30
Result(const None &none)
Definition: result.hpp:81
Result(const T &_t)
Definition: result.hpp:58
Result(const Error &error)
Definition: result.hpp:88
Result(T &&_t)
Definition: result.hpp:61
Definition: some.hpp:33
static Result< T > some(const T &t)
Definition: result.hpp:48
bool isSome() const
Definition: try.hpp:70
const T & get() const
Definition: result.hpp:115
static Try error(const E &e)
Definition: try.hpp:42
T * operator->()
Definition: result.hpp:135
_Some< typename std::decay< T >::type > Some(T &&t)
Definition: some.hpp:42
Definition: none.hpp:27
bool isError() const
Definition: try.hpp:71
Try< uint32_t > type(const std::string &path)
bool isSome() const
Definition: result.hpp:111
bool isError() const
Definition: result.hpp:113
Result(const ErrnoError &error)
Definition: result.hpp:91
const std::string & error() const
Definition: result.hpp:137
static Result< T > none()
Definition: result.hpp:43
Result(const Option< T > &option)
Definition: result.hpp:71