Apache Mesos
option.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_OPTION_HPP__
14 #define __STOUT_OPTION_HPP__
15 
16 #include <assert.h>
17 
18 #include <algorithm>
19 #include <functional>
20 #include <type_traits>
21 #include <utility>
22 
23 #include <boost/functional/hash.hpp>
24 
25 #include <stout/none.hpp>
26 #include <stout/some.hpp>
27 
28 template <typename T>
29 class Option
30 {
31 public:
32  static Option<T> none()
33  {
34  return Option<T>();
35  }
36 
37  static Option<T> some(const T& t)
38  {
39  return Option<T>(t);
40  }
41 
42  Option() : state(NONE) {}
43 
44  Option(const T& _t) : state(SOME), t(_t) {}
45 
46  Option(T&& _t) : state(SOME), t(std::move(_t)) {}
47 
48  template <
49  typename U,
50  typename = typename std::enable_if<
51  std::is_constructible<T, const U&>::value>::type>
52  Option(const U& u) : state(SOME), t(u) {}
53 
54  Option(const None&) : state(NONE) {}
55 
56  template <typename U>
57  Option(const _Some<U>& some) : state(SOME), t(some.t) {}
58 
59  template <typename U>
60  Option(_Some<U>&& some) : state(SOME), t(std::move(some.t)) {}
61 
62  Option(const Option<T>& that) : state(that.state)
63  {
64  if (that.isSome()) {
65  new (&t) T(that.t);
66  }
67  }
68 
69  Option(Option<T>&& that)
70  noexcept(std::is_nothrow_move_constructible<T>::value)
71  : state(std::move(that.state))
72  {
73  if (that.isSome()) {
74  new (&t) T(std::move(that.t));
75  }
76  }
77 
79  {
80  if (isSome()) {
81  t.~T();
82  }
83  }
84 
86  {
87  if (this != &that) {
88  if (isSome()) {
89  t.~T();
90  }
91  state = that.state;
92  if (that.isSome()) {
93  new (&t) T(that.t);
94  }
95  }
96 
97  return *this;
98  }
99 
101  noexcept(std::is_nothrow_move_constructible<T>::value)
102  {
103  if (this != &that) {
104  if (isSome()) {
105  t.~T();
106  }
107  state = std::move(that.state);
108  if (that.isSome()) {
109  new (&t) T(std::move(that.t));
110  }
111  }
112 
113  return *this;
114  }
115 
116  bool isSome() const { return state == SOME; }
117  bool isNone() const { return state == NONE; }
118 
119  const T& get() const & { assert(isSome()); return t; }
120  T& get() & { assert(isSome()); return t; }
121  T&& get() && { assert(isSome()); return std::move(t); }
122  const T&& get() const && { assert(isSome()); return std::move(t); }
123 
124  const T* operator->() const { return &get(); }
125  T* operator->() { return &get(); }
126 
127  const T& operator*() const& { return get(); }
128  T& operator*() & { return get(); }
129  const T&& operator*() const&& { return std::move(*this).get(); }
130  T&& operator*() && { return std::move(*this).get(); }
131 
132  template <typename U>
133  T getOrElse(U&& u) const &
134  {
135  return isNone() ? static_cast<T>(std::forward<U>(u)) : t;
136  }
137 
138  template <typename U>
139  T getOrElse(U&& u) &&
140  {
141  return isNone() ? static_cast<T>(std::forward<U>(u)) : std::move(t);
142  }
143 
144  bool operator==(const Option<T>& that) const
145  {
146  return (isNone() && that.isNone()) ||
147  (isSome() && that.isSome() && t == that.t);
148  }
149 
150  bool operator!=(const Option<T>& that) const
151  {
152  return !(*this == that);
153  }
154 
155  bool operator==(const T& that) const
156  {
157  return isSome() && t == that;
158  }
159 
160  bool operator!=(const T& that) const
161  {
162  return !(*this == that);
163  }
164 
165 private:
166  enum State
167  {
168  SOME,
169  NONE,
170  };
171 
172  State state;
173 
174  union {
175  // We remove the const qualifier (if there is one) from T so that
176  // we can initialize 't' from outside of the initializer list
177  // using placement new. This is necessary because sometimes we
178  // specialize 'Option' as such: 'Option<const T>'.
180  };
181 };
182 
183 
184 template <typename T>
185 Option<T> min(const Option<T>& left, const Option<T>& right)
186 {
187  if (left.isSome() && right.isSome()) {
188  return std::min(left.get(), right.get());
189  } else if (left.isSome()) {
190  return left.get();
191  } else if (right.isSome()) {
192  return right.get();
193  } else {
194  return Option<T>::none();
195  }
196 }
197 
198 
199 template <typename T>
200 Option<T> min(const Option<T>& left, const T& right)
201 {
202  return min(left, Option<T>(right));
203 }
204 
205 
206 template <typename T>
207 Option<T> min(const T& left, const Option<T>& right)
208 {
209  return min(Option<T>(left), right);
210 }
211 
212 
213 template <typename T>
214 Option<T> max(const Option<T>& left, const Option<T>& right)
215 {
216  if (left.isSome() && right.isSome()) {
217  return std::max(left.get(), right.get());
218  } else if (left.isSome()) {
219  return left.get();
220  } else if (right.isSome()) {
221  return right.get();
222  } else {
223  return Option<T>::none();
224  }
225 }
226 
227 
228 template <typename T>
229 Option<T> max(const Option<T>& left, const T& right)
230 {
231  return max(left, Option<T>(right));
232 }
233 
234 
235 template <typename T>
236 Option<T> max(const T& left, const Option<T>& right)
237 {
238  return max(Option<T>(left), right);
239 }
240 
241 namespace std {
242 
243 template <typename T>
244 struct hash<Option<T>>
245 {
246  typedef size_t result_type;
247 
249 
250  result_type operator()(const argument_type& option) const
251  {
252  size_t seed = 0;
253  if (option.isSome()) {
254  boost::hash_combine(seed, hash<T>()(option.get()));
255  }
256  return seed;
257  }
258 };
259 
260 } // namespace std {
261 
262 #endif // __STOUT_OPTION_HPP__
Definition: option.hpp:29
T getOrElse(U &&u) const &
Definition: option.hpp:133
const T && operator*() const &&
Definition: option.hpp:129
Option(Option< T > &&that) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition: option.hpp:69
T getOrElse(U &&u)&&
Definition: option.hpp:139
size_t result_type
Definition: option.hpp:246
std::remove_const< T >::type t
Definition: option.hpp:179
const T * operator->() const
Definition: option.hpp:124
Definition: type_utils.hpp:598
bool operator!=(const T &that) const
Definition: option.hpp:160
bool operator==(const T &that) const
Definition: option.hpp:155
bool operator!=(const Option< T > &that) const
Definition: option.hpp:150
bool isSome() const
Definition: option.hpp:116
static Option< T > some(const T &t)
Definition: option.hpp:37
Option(const U &u)
Definition: option.hpp:52
~Option()
Definition: option.hpp:78
Option< T > argument_type
Definition: option.hpp:248
Definition: some.hpp:33
Option< T > max(const Option< T > &left, const Option< T > &right)
Definition: option.hpp:214
Option< T > & operator=(const Option< T > &that)
Definition: option.hpp:85
Option(const _Some< U > &some)
Definition: option.hpp:57
static Option< T > none()
Definition: option.hpp:32
Option< T > min(const Option< T > &left, const Option< T > &right)
Definition: option.hpp:185
Option()
Definition: option.hpp:42
const T & get() const &
Definition: option.hpp:119
result_type operator()(const argument_type &option) const
Definition: option.hpp:250
Definition: none.hpp:27
T && operator*()&&
Definition: option.hpp:130
Option(const Option< T > &that)
Definition: option.hpp:62
Option(T &&_t)
Definition: option.hpp:46
Try< uint32_t > type(const std::string &path)
bool isNone() const
Definition: option.hpp:117
T * operator->()
Definition: option.hpp:125
T & operator*()&
Definition: option.hpp:128
Option< T > & operator=(Option< T > &&that) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition: option.hpp:100
Option(_Some< U > &&some)
Definition: option.hpp:60
bool operator==(const Option< T > &that) const
Definition: option.hpp:144
const T & operator*() const &
Definition: option.hpp:127
Option(const None &)
Definition: option.hpp:54
Option(const T &_t)
Definition: option.hpp:44