maybe_null.hpp 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. //
  2. // maybe_null.hpp
  3. // pointer
  4. //
  5. // Created by Sam Jaffe on 9/24/15.
  6. //
  7. //
  8. #pragma once
  9. #include <stdexcept>
  10. #include <memory>
  11. #include "pointer_fwd.hpp"
  12. #include "pointer_traits.hpp"
  13. #include "not_null.hpp"
  14. class unchecked_pointer_exception : public std::logic_error {
  15. using std::logic_error::logic_error;
  16. };
  17. template <typename P> class maybe_null<not_null<P>>; // not permitted
  18. template <typename T>
  19. class maybe_null {
  20. public:
  21. using element_type = typename detail::pointer_traits<T>::element_type;
  22. using pointer = typename detail::pointer_traits<T>::pointer;
  23. using reference = typename detail::pointer_traits<T>::reference;
  24. maybe_null() : _ptr(nullptr) {}
  25. template <typename... Args> maybe_null(Args && ...args) : _ptr(std::forward<Args>(args)...) { }
  26. maybe_null(maybe_null const&) = default;
  27. template <typename Y> maybe_null(maybe_null<Y> const& other) : _ptr(other.ptr_) { }
  28. template <typename Y> maybe_null(not_null<Y> const& other) : _ptr(other.get()) { }
  29. maybe_null& operator=(T ptr) { return operator=(maybe_null<T>(ptr)); }
  30. maybe_null& operator=(maybe_null const&) = default;
  31. template <typename Y> maybe_null& operator=(maybe_null<Y> const&other) {
  32. if (_ptr != other.get()) {
  33. _ptr = other.get();
  34. #if defined( DEBUG )
  35. tested_ = other.tested_;
  36. #endif
  37. }
  38. return *this;
  39. }
  40. template <typename Y> maybe_null& operator=(not_null<Y> const&other) {
  41. _ptr = other.get();
  42. #if defined( DEBUG )
  43. tested_ = true;
  44. #endif
  45. return *this;
  46. }
  47. operator bool() const {
  48. #if defined( DEBUG )
  49. tested_ = true;
  50. #endif
  51. return bool(_ptr);
  52. }
  53. pointer get() const {
  54. #if defined( DEBUG )
  55. if ( !tested_ ) {
  56. throw unchecked_pointer_exception{"did not verify that pointer was non-null"};
  57. }
  58. #endif
  59. return std::addressof(operator*());
  60. }
  61. // operator T() const { return get(); }
  62. pointer operator->() const { return get(); }
  63. reference operator*() const { return *_ptr; }
  64. bool operator==(maybe_null const&rhs) const { return _ptr == rhs._ptr; }
  65. bool operator!=(maybe_null const&rhs) const { return _ptr != rhs._ptr; }
  66. bool operator<=(maybe_null const&rhs) const { return _ptr <= rhs._ptr; }
  67. bool operator>=(maybe_null const&rhs) const { return _ptr >= rhs._ptr; }
  68. bool operator< (maybe_null const&rhs) const { return _ptr < rhs._ptr; }
  69. bool operator> (maybe_null const&rhs) const { return _ptr > rhs._ptr; }
  70. private:
  71. T _ptr;
  72. #if defined( DEBUG )
  73. mutable bool tested_ = false;
  74. #endif
  75. };