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  // This must return a copy to avoid returning a reference to a temporary.
127  T getOrElse(const T& _t) const { return isNone() ? _t : t; }
128 
129  bool operator==(const Option<T>& that) const
130  {
131  return (isNone() && that.isNone()) ||
132  (isSome() && that.isSome() && t == that.t);
133  }
134 
135  bool operator!=(const Option<T>& that) const
136  {
137  return !(*this == that);
138  }
139 
140  bool operator==(const T& that) const
141  {
142  return isSome() && t == that;
143  }
144 
145  bool operator!=(const T& that) const
146  {
147  return !(*this == that);
148  }
149 
150 private:
151  enum State
152  {
153  SOME,
154  NONE,
155  };
156 
157  State state;
158 
159  union {
160  // We remove the const qualifier (if there is one) from T so that
161  // we can initialize 't' from outside of the initializer list
162  // using placement new. This is necessary because sometimes we
163  // specialize 'Option' as such: 'Option<const T>'.
165  };
166 };
167 
168 
169 template <typename T>
170 Option<T> min(const Option<T>& left, const Option<T>& right)
171 {
172  if (left.isSome() && right.isSome()) {
173  return std::min(left.get(), right.get());
174  } else if (left.isSome()) {
175  return left.get();
176  } else if (right.isSome()) {
177  return right.get();
178  } else {
179  return Option<T>::none();
180  }
181 }
182 
183 
184 template <typename T>
185 Option<T> min(const Option<T>& left, const T& right)
186 {
187  return min(left, Option<T>(right));
188 }
189 
190 
191 template <typename T>
192 Option<T> min(const T& left, const Option<T>& right)
193 {
194  return min(Option<T>(left), right);
195 }
196 
197 
198 template <typename T>
199 Option<T> max(const Option<T>& left, const Option<T>& right)
200 {
201  if (left.isSome() && right.isSome()) {
202  return std::max(left.get(), right.get());
203  } else if (left.isSome()) {
204  return left.get();
205  } else if (right.isSome()) {
206  return right.get();
207  } else {
208  return Option<T>::none();
209  }
210 }
211 
212 
213 template <typename T>
214 Option<T> max(const Option<T>& left, const T& right)
215 {
216  return max(left, Option<T>(right));
217 }
218 
219 
220 template <typename T>
221 Option<T> max(const T& left, const Option<T>& right)
222 {
223  return max(Option<T>(left), right);
224 }
225 
226 namespace std {
227 
228 template <typename T>
229 struct hash<Option<T>>
230 {
231  typedef size_t result_type;
232 
234 
235  result_type operator()(const argument_type& option) const
236  {
237  size_t seed = 0;
238  if (option.isSome()) {
239  boost::hash_combine(seed, hash<T>()(option.get()));
240  }
241  return seed;
242  }
243 };
244 
245 } // namespace std {
246 
247 #endif // __STOUT_OPTION_HPP__
Definition: option.hpp:28
size_t result_type
Definition: option.hpp:231
std::remove_const< T >::type t
Definition: option.hpp:164
const T * operator->() const
Definition: option.hpp:123
bool operator!=(const T &that) const
Definition: option.hpp:145
bool operator==(const T &that) const
Definition: option.hpp:140
bool operator!=(const Option< T > &that) const
Definition: option.hpp:135
noexcept(std::is_nothrow_move_constructible< T >::value)
Definition: option.hpp:69
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:233
Definition: some.hpp:33
Option< T > max(const Option< T > &left, const Option< T > &right)
Definition: option.hpp:199
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:170
Option()
Definition: option.hpp:41
const T & get() const &
Definition: option.hpp:118
result_type operator()(const argument_type &option) const
Definition: option.hpp:235
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
T getOrElse(const T &_t) const
Definition: option.hpp:127
bool operator==(const Option< T > &that) const
Definition: option.hpp:129
Option(const None &)
Definition: option.hpp:53
Option(const T &_t)
Definition: option.hpp:43