// // maybe_null.hpp // pointer // // Created by Sam Jaffe on 9/24/15. // // #pragma once #include #include #include "pointer_fwd.hpp" class unchecked_pointer_exception : public std::logic_error { using std::logic_error::logic_error; }; template class maybe_null>; // not permitted template class maybe_null { public: using element_type = typename std::pointer_traits::element_type; using pointer = element_type *; using reference = element_type &; maybe_null() : _ptr(nullptr) {} maybe_null(T const & p) : _ptr(p) { } maybe_null(T && p) : _ptr(std::move(p)) { } maybe_null(maybe_null const&) = default; template explicit operator maybe_null() const { return _ptr; } maybe_null& operator=(maybe_null const&) = default; template maybe_null& operator=(maybe_null const&other) { if (_ptr != other._ptr) { _ptr = other._ptr; #if defined( DEBUG ) tested_ = other.tested_; #endif } return *this; } operator bool() const { #if defined( DEBUG ) tested_ = true; #endif return static_cast(_ptr); } pointer get() const { return std::addressof(*_ptr); } pointer operator->() const { return std::addressof(operator*()); } reference operator*() const { #if defined( DEBUG ) if ( !tested_ ) { throw unchecked_pointer_exception{"did not verify that pointer was non-null"}; } #endif return *_ptr; } private: T _ptr; #if defined( DEBUG ) mutable bool tested_ = false; #endif }; template bool operator==(maybe_null const&lhs, maybe_null const&rhs) { return lhs.get() == rhs.get(); } template bool operator!=(maybe_null const&lhs, maybe_null const&rhs) { return !(lhs == rhs); } template bool operator< (maybe_null const&lhs, maybe_null const&rhs) { typedef typename std::common_type< typename maybe_null::pointer, typename maybe_null::pointer>::type V; return std::less(lhs.get(), rhs.get()); } template bool operator> (maybe_null const&lhs, maybe_null const&rhs) { return rhs < lhs; } template bool operator<=(maybe_null const&lhs, maybe_null const&rhs) { return !(rhs < lhs); } template bool operator>=(maybe_null const&lhs, maybe_null const&rhs) { return !(lhs < rhs); } template bool operator==(maybe_null const&lhs, std::nullptr_t) { return !lhs; } template bool operator==(std::nullptr_t, maybe_null const&rhs) { return !rhs; } template bool operator!=(maybe_null const&lhs, std::nullptr_t) { return static_cast(lhs); } template bool operator!=(std::nullptr_t, maybe_null const&rhs) { return static_cast(rhs); } template bool operator< (maybe_null const&lhs, std::nullptr_t) { typedef typename maybe_null::pointer V; return std::less(lhs.get(), nullptr); } template bool operator< (std::nullptr_t, maybe_null const&rhs) { typedef typename maybe_null::pointer V; return std::less(nullptr, rhs.get()); } template bool operator> (maybe_null const&lhs, std::nullptr_t) { return nullptr < lhs; } template bool operator> (std::nullptr_t, maybe_null const&rhs) { return rhs < nullptr; } template bool operator<=(maybe_null const&lhs, std::nullptr_t) { return !(nullptr < lhs); } template bool operator<=(std::nullptr_t, maybe_null const&rhs) { return !(rhs < nullptr); } template bool operator>=(maybe_null const&lhs, std::nullptr_t) { return !(lhs < nullptr); } template bool operator>=(std::nullptr_t, maybe_null const&rhs) { return !(nullptr < rhs); }