Silicium
optional.hpp
Go to the documentation of this file.
1 #ifndef SILICIUM_OPTIONAL_HPP
2 #define SILICIUM_OPTIONAL_HPP
3 
4 #include <silicium/config.hpp>
5 #include <silicium/is_handle.hpp>
7 #include <ostream>
8 #include <type_traits>
9 #include <boost/static_assert.hpp>
10 #include <boost/functional/hash.hpp>
11 
12 namespace Si
13 {
14  template <class T>
15  struct alignment_of : std::integral_constant<std::size_t,
16 #ifdef _MSC_VER
17  __alignof(T)
18 #else
19  alignof(T)
20 #endif
21  >
22  {
23  };
24 
25  struct none_t {};
26 
27  static none_t BOOST_CONSTEXPR_OR_CONST none;
28 
29  inline bool operator == (none_t, none_t)
30  {
31  return true;
32  }
33 
34  struct some_t {};
35 
36  static some_t BOOST_CONSTEXPR_OR_CONST some;
37 
38  template <class T>
39  struct optional
40  {
41  optional() BOOST_NOEXCEPT
42  : m_is_set(false)
43  {
44  }
45 
46  optional(none_t) BOOST_NOEXCEPT
47  : m_is_set(false)
48  {
49  }
50 
51  optional(optional &&other) BOOST_NOEXCEPT
52  : m_is_set(other.m_is_set)
53  {
54  if (m_is_set)
55  {
56  new (data())T(std::move(*other));
57  }
58  }
59 
60  optional(optional const &other)
61  : m_is_set(other.m_is_set)
62  {
63  if (m_is_set)
64  {
65  new (data())T(*other);
66  }
67  }
68 
69  optional(T &&value) BOOST_NOEXCEPT
70  : m_is_set(true)
71  {
72  new (data()) T(std::move(value));
73  }
74 
75  optional(T const &value)
76  : m_is_set(true)
77  {
78  new (data()) T(value);
79  }
80 
81  template <class ...Args>
82  explicit optional(some_t, Args &&...args)
83  : m_is_set(true)
84  {
85  new (data()) T(std::forward<Args>(args)...);
86  }
87 
88  ~optional() BOOST_NOEXCEPT
89  {
90  if (!m_is_set)
91  {
92  return;
93  }
94  data()->~T();
95  }
96 
97  optional &operator = (optional &&other) BOOST_NOEXCEPT
98  {
99  if (m_is_set)
100  {
101  if (other.m_is_set)
102  {
103  *data() = std::move(*other);
104  }
105  else
106  {
107  data()->~T();
108  m_is_set = false;
109  }
110  }
111  else
112  {
113  if (other.m_is_set)
114  {
115  new (data()) T(std::move(*other));
116  m_is_set = true;
117  }
118  else
119  {
120  //both are already empty
121  }
122  }
123  return *this;
124  }
125 
127  {
128  if (m_is_set)
129  {
130  if (other.m_is_set)
131  {
132  *data() = *other;
133  }
134  else
135  {
136  data()->~T();
137  m_is_set = false;
138  }
139  }
140  else
141  {
142  if (other.m_is_set)
143  {
144  new (data()) T(*other);
145  m_is_set = true;
146  }
147  else
148  {
149  //both are already empty
150  }
151  }
152  return *this;
153  }
154 
155  optional &operator = (T const &value)
156  {
157  if (m_is_set)
158  {
159  *data() = value;
160  }
161  else
162  {
163  new (data()) T(value);
164  m_is_set = true;
165  }
166  return *this;
167  }
168 
169  optional &operator = (T &&value) BOOST_NOEXCEPT
170  {
171  if (m_is_set)
172  {
173  *data() = std::move(value);
174  }
175  else
176  {
177  new (data()) T(std::move(value));
178  m_is_set = true;
179  }
180  return *this;
181  }
182 
183  optional &operator = (none_t const &) BOOST_NOEXCEPT
184  {
185  if (m_is_set)
186  {
187  data()->~T();
188  m_is_set = false;
189  }
190  return *this;
191  }
192 
193  explicit operator bool() const BOOST_NOEXCEPT
194  {
195  return m_is_set;
196  }
197 
199  bool operator !() const BOOST_NOEXCEPT
200  {
201  return !m_is_set;
202  }
203 
204 #if !SILICIUM_COMPILER_HAS_RVALUE_THIS_QUALIFIER
206  T &operator * () BOOST_NOEXCEPT
207  {
208  assert(*this);
209  return *data();
210  }
211 
213  T const &operator * () const BOOST_NOEXCEPT
214  {
215  assert(*this);
216  return *data();
217  }
218 #else
220  T &operator * () & BOOST_NOEXCEPT
221  {
222  assert(*this);
223  return *data();
224  }
225 
227  T &&operator * () && BOOST_NOEXCEPT
228  {
229  assert(*this);
230  return std::move(*data());
231  }
232 
234  T const &operator * () const & BOOST_NOEXCEPT
235  {
236  assert(*this);
237  return *data();
238  }
239 #endif
240 
241  T *operator -> () BOOST_NOEXCEPT
242  {
243  assert(*this);
244  return data();
245  }
246 
247  T const *operator -> () const BOOST_NOEXCEPT
248  {
249  assert(*this);
250  return data();
251  }
252 
253  template <class ...Args>
254  void emplace(Args &&...args)
255  {
256  *this = none;
257  new (data()) T{std::forward<Args>(args)...};
258  m_is_set = true;
259  }
260 
261  private:
262 
263  enum
264  {
265  alignment = alignment_of<T>::value
266  };
267 
268  typename std::aligned_storage<sizeof(T), alignment>::type m_storage;
269  bool m_is_set;
270 
271  T *data() BOOST_NOEXCEPT
272  {
273  return reinterpret_cast<T *>(&m_storage);
274  }
275 
276  T const *data() const BOOST_NOEXCEPT
277  {
278  return reinterpret_cast<T const *>(&m_storage);
279  }
280  };
281 
282  template <class T>
283  struct optional<T &>
284  {
285  optional() BOOST_NOEXCEPT
286  : m_data(nullptr)
287  {
288  }
289 
290  optional(T &data) BOOST_NOEXCEPT
291  : m_data(&data)
292  {
293  }
294 
295  optional(some_t, T &data) BOOST_NOEXCEPT
296  : m_data(&data)
297  {
298  }
299 
300  optional(none_t) BOOST_NOEXCEPT
301  : m_data(nullptr)
302  {
303  }
304 
305  void emplace(T &data) BOOST_NOEXCEPT
306  {
307  m_data = &data;
308  }
309 
311  bool operator !() const BOOST_NOEXCEPT
312  {
313  return m_data == nullptr;
314  }
315 
317 
319  T &operator * () BOOST_NOEXCEPT
320  {
321  assert(*this);
322  return *m_data;
323  }
324 
326  T const &operator * () const BOOST_NOEXCEPT
327  {
328  assert(*this);
329  return *m_data;
330  }
331 
332  T *operator -> () BOOST_NOEXCEPT
333  {
334  assert(*this);
335  return m_data;
336  }
337 
338  T const *operator -> () const BOOST_NOEXCEPT
339  {
340  assert(*this);
341  return m_data;
342  }
343 
344  private:
345 
346  T *m_data;
347  };
348 
349  BOOST_STATIC_ASSERT(is_handle<optional<int>>::value);
350  BOOST_STATIC_ASSERT(is_handle<optional<int *>>::value);
351  BOOST_STATIC_ASSERT(is_handle<optional<int const *>>::value);
352  BOOST_STATIC_ASSERT(is_handle<optional<int volatile>>::value);
353  BOOST_STATIC_ASSERT(is_handle<optional<nothing>>::value);
354  BOOST_STATIC_ASSERT(is_handle<optional<int &>>::value);
355  BOOST_STATIC_ASSERT(is_handle<optional<int const &>>::value);
356 
357  template <class T>
359  bool operator == (optional<T> const &left, optional<T> const &right)
360  {
361  if (left && right)
362  {
363  return (*left == *right);
364  }
365  return !left == !right;
366  }
367 
368  template <class T>
370  bool operator == (optional<T> const &left, T const &right)
371  {
372  if (left)
373  {
374  return (*left == right);
375  }
376  return false;
377  }
378 
379  template <class T>
381  bool operator == (T const &left, optional<T> const &right)
382  {
383  return (right == left);
384  }
385 
386  template <class T>
388  bool operator == (none_t const &, optional<T> const &right)
389  {
390  return !right;
391  }
392 
393  template <class T>
395  bool operator == (optional<T> const &left, none_t const &)
396  {
397  return !left;
398  }
399 
400  template <class T>
402  bool operator != (optional<T> const &left, optional<T> const &right)
403  {
404  return !(left == right);
405  }
406 
407  template <class T>
409  bool operator < (optional<T> const &left, optional<T> const &right)
410  {
411  if (left)
412  {
413  if (right)
414  {
415  return (*left < *right);
416  }
417  else
418  {
419  return false;
420  }
421  }
422  else
423  {
424  if (right)
425  {
426  return true;
427  }
428  else
429  {
430  return false;
431  }
432  }
433  }
434 
435  template <class T>
438  {
439  return Si::optional<typename std::decay<T>::type>(std::forward<T>(value));
440  }
441 
442  inline std::ostream &operator << (std::ostream &out, none_t const &)
443  {
444  out << "none";
445  return out;
446  }
447 
448  template <class T>
449  std::ostream &operator << (std::ostream &out, optional<T> const &value)
450  {
451  if (value)
452  {
453  out << *value;
454  }
455  else
456  {
457  out << "none";
458  }
459  return out;
460  }
461 
462  template <class T>
464  std::size_t hash_value(optional<T> const &value)
465  {
466  if (value)
467  {
468  using boost::hash_value;
469  return hash_value(*value);
470  }
471  return 0;
472  }
473 
474  BOOST_STATIC_ASSERT(sizeof(optional<boost::int8_t>) == 2);
475  BOOST_STATIC_ASSERT(sizeof(optional<boost::int16_t>) == 4);
476  BOOST_STATIC_ASSERT(sizeof(optional<boost::uint32_t>) == (2 * sizeof(boost::uint32_t)));
477  BOOST_STATIC_ASSERT(sizeof(optional<char *>) == (alignment_of<char *>::value + sizeof(char *)));
478  BOOST_STATIC_ASSERT(sizeof(optional<boost::int8_t &>) == sizeof(boost::int8_t *));
479 }
480 
481 namespace std
482 {
483  template <class T>
484  struct hash<Si::optional<T>>
485  {
487  std::size_t operator()(Si::optional<T> const &value) const
488  {
489  return hash_value(value);
490  }
491  };
492 }
493 
494 #endif
std::remove_reference< T >::type && move(T &&ref)
Definition: move.hpp:10
optional & operator=(optional &&other) BOOST_NOEXCEPT
Definition: optional.hpp:97
BOOST_STATIC_ASSERT(Si::is_handle< absolute_path >::value)
SILICIUM_USE_RESULT bool operator!() const BOOST_NOEXCEPT
Definition: optional.hpp:199
optional(T const &value)
Definition: optional.hpp:75
T * operator->() BOOST_NOEXCEPT
Definition: optional.hpp:241
std::ostream & operator<<(std::ostream &out, absolute_path const &p)
Definition: absolute_path.hpp:144
optional(T &data) BOOST_NOEXCEPT
Definition: optional.hpp:290
Definition: optional.hpp:25
Definition: absolute_path.hpp:352
#define SILICIUM_EXPLICIT_OPERATOR_BOOL()
Definition: explicit_operator_bool.hpp:17
Definition: absolute_path.hpp:19
SILICIUM_USE_RESULT T & operator*() BOOST_NOEXCEPT
Definition: optional.hpp:206
Definition: optional.hpp:39
Definition: optional.hpp:15
optional(optional &&other) BOOST_NOEXCEPT
Definition: optional.hpp:51
optional(none_t) BOOST_NOEXCEPT
Definition: optional.hpp:46
optional(T &&value) BOOST_NOEXCEPT
Definition: optional.hpp:69
optional() BOOST_NOEXCEPT
Definition: optional.hpp:285
optional(none_t) BOOST_NOEXCEPT
Definition: optional.hpp:300
~optional() BOOST_NOEXCEPT
Definition: optional.hpp:88
void emplace(Args &&...args)
Definition: optional.hpp:254
SILICIUM_USE_RESULT std::size_t operator()(Si::optional< T > const &value) const
Definition: optional.hpp:487
SILICIUM_USE_RESULT bool operator==(absolute_path const &left, ComparableToPath const &right)
Definition: absolute_path.hpp:169
void emplace(T &data) BOOST_NOEXCEPT
Definition: optional.hpp:305
optional() BOOST_NOEXCEPT
Definition: optional.hpp:41
SILICIUM_USE_RESULT Si::optional< typename std::decay< T >::type > make_optional(T &&value)
Definition: optional.hpp:437
optional(some_t, T &data) BOOST_NOEXCEPT
Definition: optional.hpp:295
optional(some_t, Args &&...args)
Definition: optional.hpp:82
SILICIUM_USE_RESULT std::size_t hash_value(absolute_path const &value)
Definition: absolute_path.hpp:220
SILICIUM_USE_RESULT bool operator!=(absolute_path const &left, ComparableToPath const &right)
Definition: absolute_path.hpp:201
SILICIUM_USE_RESULT std::size_t hash_value(optional< T > const &value)
Definition: optional.hpp:464
optional(optional const &other)
Definition: optional.hpp:60
#define SILICIUM_USE_RESULT
Definition: config.hpp:147
Definition: optional.hpp:34