All Classes Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
maybe.hpp
1 // The MIT License (MIT)
2 
3 // Copyright (c) 2012-2014 Danny Y., Rapptz
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef GEARS_UTILITY_MAYBE_HPP
23 #define GEARS_UTILITY_MAYBE_HPP
24 
25 #include "maybe/traits.hpp"
26 #include "maybe/base.hpp"
27 #include <exception>
28 
29 namespace gears {
30 namespace utility {
31 namespace detail {
32 struct bad_maybe_access : std::exception {
33  virtual const char* what() const noexcept {
34  return "bad maybe access";
35  }
36 };
37 } // detail
38 
39 template<typename T>
40 using MaybeBase = meta::If<std::is_trivially_destructible<T>, detail::cmaybe_base<T>, detail::maybe_base<T>>;
41 
97 template<typename T>
98 class maybe : private MaybeBase<T> {
99 private:
100  static_assert(!std::is_same<meta::Decay<T>, nothing_t>(), "Invalid type. Must not be nothing");
101  static_assert(!std::is_same<meta::Decay<T>, in_place_t>(), "Invalid type. Must not be in_place tag");
102  static_assert(!std::is_reference<T>(), "Invalid type. Must not be a reference type");
103  static_assert(!is_maybe<T>(), "Invalid type. Must not be a maybe type");
104 
105  constexpr bool is_valid() const noexcept {
106  return MaybeBase<T>::valid;
107  }
108 
109  T* data() {
110  return std::addressof(MaybeBase<T>::storage.value);
111  }
112 
113  constexpr const T* data() const {
114  return detail::address_of(MaybeBase<T>::storage.value);
115  }
116 
117  constexpr const T& internal() const {
118  return MaybeBase<T>::storage.value;
119  }
120 
121  T& internal() {
122  return MaybeBase<T>::storage.value;
123  }
124 
125  void clear() noexcept {
126  if(is_valid()) {
127  data()->T::~T();
128  }
129  MaybeBase<T>::valid = false;
130  }
131 
132  template<typename... Args>
133  void initialise(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
134  new(data()) T(std::forward<Args>(args)...);
135  MaybeBase<T>::valid = true;
136  }
137 
138 public:
139  using value_type = T;
140 
144  constexpr maybe() noexcept: MaybeBase<T>() {}
145 
149  constexpr maybe(nothing_t) noexcept : MaybeBase<T>() {}
150 
154  constexpr maybe(const T& value): MaybeBase<T>(value) {}
155 
159  constexpr maybe(T&& value): MaybeBase<T>(meta::cmove(value)) {}
160 
202  template<typename... Args>
203  constexpr explicit maybe(in_place_t, Args&&... args): MaybeBase<T>(in_place, meta::cforward<Args>(args)...) {}
204 
213  maybe(const maybe& rhs): MaybeBase<T>(detail::regular_init, rhs.is_valid()) {
214  if(rhs.is_valid()) {
215  new(data()) T(rhs.internal());
216  }
217  }
218 
228  maybe(maybe&& rhs) noexcept(std::is_nothrow_move_constructible<T>()): MaybeBase<T>(detail::regular_init, rhs.is_valid()) {
229  if(rhs.is_valid()) {
230  new(data()) T(std::move(rhs.internal()));
231  }
232  }
233 
234  ~maybe() = default;
235 
246  maybe& operator=(nothing_t) noexcept {
247  clear();
248  return *this;
249  }
250 
254  maybe& operator=(const maybe& rhs) {
255  if(is_valid() && !rhs.is_valid()) {
256  clear();
257  }
258  else if(!is_valid() && rhs.is_valid()) {
259  initialise(rhs.internal());
260  }
261  else if(is_valid() && rhs.is_valid()) {
262  internal() = rhs.internal();
263  }
264 
265  return *this;
266  }
267 
271  maybe& operator=(maybe&& rhs) noexcept(std::is_nothrow_move_assignable<T>() && std::is_nothrow_move_constructible<T>()) {
272  if(is_valid() && !rhs.is_valid()) {
273  clear();
274  }
275  else if(!is_valid() && rhs.is_valid()) {
276  initialise(std::move(rhs.internal()));
277  }
278  else if(is_valid() && rhs.is_valid()) {
279  internal() = std::move(rhs.internal());
280  }
281 
282  return *this;
283  }
284 
294  template<typename U, meta::EnableIf<std::is_constructible<T, meta::Decay<U>>, std::is_assignable<T, meta::Decay<U>>> = meta::_>
296  if(is_valid()) {
297  internal() = std::forward<U>(value);
298  }
299  else {
300  initialise(std::forward<U>(value));
301  }
302  return *this;
303  }
304 
315  template<typename... Args>
316  void emplace(Args&&... args) {
317  clear();
318  initialise(std::forward<Args>(args)...);
319  }
320 
322 
338  constexpr const T* operator->() const {
339  return data();
340  }
341 
342  T* operator->() {
343  return data();
344  }
346 
348 
355  constexpr const T& operator*() const {
356  return internal();
357  }
358 
359  T& operator*() {
360  return internal();
361  }
363 
365 
373  constexpr const T& value() const {
374  return is_valid() ? internal() : (throw detail::bad_maybe_access(), internal());
375  }
376 
377  T& value() {
378  return is_valid() ? internal() : (throw detail::bad_maybe_access(), internal());
379  }
381 
387  constexpr explicit operator bool() const noexcept {
388  return is_valid();
389  }
390 
400  template<typename U>
401  constexpr T value_or(U&& value) const {
402  return is_valid() ? internal() : static_cast<T>(meta::cforward<U>(value));
403  }
404 };
405 
416 template<typename T>
417 constexpr maybe<meta::Decay<T>> just(T&& t) {
418  return { meta::cforward<T>(t) };
419 }
420 
438 template<typename T>
439 constexpr bool operator==(const maybe<T>& lhs, const maybe<T>& rhs) {
440  return static_cast<bool>(lhs) != static_cast<bool>(rhs) ? false : static_cast<bool>(lhs) == false ? true : *lhs == *rhs;
441 }
442 
446 template<typename T>
447 constexpr bool operator!=(const maybe<T>& lhs, const maybe<T>& rhs) {
448  return !(lhs == rhs);
449 }
450 
454 template<typename T>
455 constexpr bool operator<(const maybe<T>& lhs, const maybe<T>& rhs) {
456  return !rhs ? false : !lhs ? true : *lhs < *rhs;
457 }
458 
462 template<typename T>
463 constexpr bool operator>(const maybe<T>& lhs, const maybe<T>& rhs) {
464  return (rhs < lhs);
465 }
466 
470 template<typename T>
471 constexpr bool operator<=(const maybe<T>& lhs, const maybe<T>& rhs) {
472  return !(rhs < lhs);
473 }
474 
478 template<typename T>
479 constexpr bool operator>=(const maybe<T>& lhs, const maybe<T>& rhs) {
480  return !(lhs < rhs);
481 }
483 
484 // Comparison with nothing
510 template<typename T>
511 constexpr bool operator==(const maybe<T>& lhs, nothing_t) noexcept {
512  return !lhs;
513 }
514 
515 template<typename T>
516 constexpr bool operator==(nothing_t, const maybe<T>& rhs) noexcept {
517  return !rhs;
518 }
519 
520 template<typename T>
521 constexpr bool operator!=(const maybe<T>& lhs, nothing_t) noexcept {
522  return static_cast<bool>(lhs);
523 }
524 
525 template<typename T>
526 constexpr bool operator!=(nothing_t, const maybe<T>& rhs) noexcept {
527  return static_cast<bool>(rhs);
528 }
529 
530 template<typename T>
531 constexpr bool operator<(const maybe<T>& lhs, nothing_t) noexcept {
532  return false;
533 }
534 
535 template<typename T>
536 constexpr bool operator<(nothing_t, const maybe<T>& rhs) noexcept {
537  return static_cast<bool>(rhs);
538 }
539 
540 template<typename T>
541 constexpr bool operator>(const maybe<T>& lhs, nothing_t) noexcept {
542  return static_cast<bool>(lhs);
543 }
544 
545 template<typename T>
546 constexpr bool operator>(nothing_t, const maybe<T>&) noexcept {
547  return false;
548 }
549 
550 template<typename T>
551 constexpr bool operator<=(const maybe<T>& lhs, nothing_t) noexcept {
552  return !lhs;
553 }
554 
555 template<typename T>
556 constexpr bool operator<=(nothing_t, const maybe<T>&) noexcept {
557  return true;
558 }
559 
560 template<typename T>
561 constexpr bool operator>=(const maybe<T>&, nothing_t) noexcept {
562  return true;
563 }
564 
565 template<typename T>
566 constexpr bool operator>=(nothing_t, const maybe<T>& rhs) noexcept {
567  return !rhs;
568 }
570 
584 template<typename T>
585 constexpr bool operator==(const maybe<T>& lhs, const T& value) {
586  return static_cast<bool>(lhs) ? *lhs == value : false;
587 }
588 
589 template<typename T>
590 constexpr bool operator==(const T& value, const maybe<T>& rhs) {
591  return static_cast<bool>(rhs) ? value == *rhs : false;
592 }
593 
597 template<typename T>
598 constexpr bool operator!=(const maybe<T>& lhs, const T& value) {
599  return static_cast<bool>(lhs) ? *lhs != value : true;
600 }
601 
602 template<typename T>
603 constexpr bool operator!=(const T& value, const maybe<T>& rhs) {
604  return static_cast<bool>(rhs) ? value != *rhs : true;
605 }
606 
610 template<typename T>
611 constexpr bool operator<(const maybe<T>& lhs, const T& value) {
612  return static_cast<bool>(lhs) ? *lhs < value : true;
613 }
614 
615 template<typename T>
616 constexpr bool operator>(const T& value, const maybe<T>& rhs) {
617  return static_cast<bool>(rhs) ? value > *rhs : true;
618 }
619 
623 template<typename T>
624 constexpr bool operator>(const maybe<T>& lhs, const T& value) {
625  return static_cast<bool>(lhs) ? *lhs > value : false;
626 }
627 
628 template<typename T>
629 constexpr bool operator<(const T& value, const maybe<T>& rhs) {
630  return static_cast<bool>(rhs) ? value < *rhs : false;
631 }
632 
636 template<typename T>
637 constexpr bool operator>=(const maybe<T>& lhs, const T& value) {
638  return static_cast<bool>(lhs) ? *lhs >= value : false;
639 }
640 
641 template<typename T>
642 constexpr bool operator<=(const T& value, const maybe<T>& rhs) {
643  return static_cast<bool>(rhs) ? value <= *rhs : false;
644 }
645 
649 template<typename T>
650 constexpr bool operator<=(const maybe<T>& lhs, const T& value) {
651  return static_cast<bool>(lhs) ? *lhs <= value : true;
652 }
653 
654 template<typename T>
655 constexpr bool operator>=(const T& value, const maybe<T>& rhs) {
656  return static_cast<bool>(rhs) ? value >= *rhs : true;
657 }
659 } // utility
660 } // gears
661 
662 #endif // GEARS_UTILITY_MAYBE_HPP