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