#ifndef CORE_PROPAGATE_CONST_HPP #define CORE_PROPAGATE_CONST_HPP #include #include #include #include #include namespace core { inline namespace v2 { namespace impl { template constexpr auto pointer_to (T const& t) -> decltype(t.get()) { return t.get(); } template constexpr T* pointer_to (T* t) { return t; } } /* namespace impl */ template struct propagate_const final { using element_type = remove_reference_t())>; using underlying_type = T; /* Although these are public, they are undocumented and for internal use */ template using is_self = ::std::is_same, propagate_const>; using is_nothrow_swap = is_nothrow_swappable; propagate_const (propagate_const const&) = delete; constexpr propagate_const (propagate_const&&) = default; constexpr propagate_const () = default; template < class U, meta::require<::std::is_constructible::value> = __LINE__, meta::inhibit<::std::is_convertible::value> = __LINE__ > explicit propagate_const (propagate_const&& that) : pointer { ::core::move(that.pointer) } { } template < class U, meta::require::value> = __LINE__, meta::require<::std::is_constructible::value> = __LINE__, meta::require::value> = __LINE__ > explicit propagate_const (U&& value) : pointer { ::core::forward(value) } { } template < class U, meta::require<::std::is_constructible::value> = __LINE__, meta::require<::std::is_convertible::value> = __LINE__ > propagate_const (propagate_const&& that) : pointer { move(that.pointer) } { } template < class U, meta::require<::std::is_constructible::value> = __LINE__, meta::require<::std::is_convertible::value> = __LINE__, meta::require::value> = __LINE__ > propagate_const (U&& value) : pointer { ::core::forward(value) } { } propagate_const& operator = (propagate_const const&) = delete; propagate_const& operator = (propagate_const&&) = default; template propagate_const& operator = (propagate_const&& that) { this->pointer = ::core::move(that.pointer); return *this; } template < class U, meta::require<::std::is_convertible::value> = __LINE__, meta::require::value> = __LINE__ > propagate_const& operator = (U&& value) { this->pointer = ::core::forward(value); return *this; } void swap (propagate_const& that) noexcept(is_nothrow_swap::value) { using ::std::swap; swap(this->pointer, that.pointer); } constexpr explicit operator bool () const noexcept { return bool(this->pointer); } constexpr operator element_type const* () const { return this->get(); } operator element_type* () { return this->get(); } constexpr element_type const* operator -> () const { return this->get(); } element_type* operator -> () { return this->get(); } constexpr element_type const& operator * () const { return *this->get(); } element_type& operator * () { return *this->get(); } constexpr element_type const* get () const { return impl::pointer_to(this->pointer); } element_type* get () { return impl::pointer_to(this->pointer); } friend constexpr underlying_type const& get_underlying ( propagate_const const& pc ) noexcept { return pc.pointer; } friend constexpr underlying_type& get_underlying ( propagate_const& pc ) noexcept { return pc.pointer; } private: underlying_type pointer; }; template void swap (propagate_const& lhs, propagate_const& rhs) noexcept( noexcept(lhs.swap(rhs)) ) { lhs.swap(rhs); } template constexpr bool operator == ( propagate_const const& l, propagate_const const& r ) { return get_underlying(l) == get_underlying(r); } template constexpr bool operator != ( propagate_const const& l, propagate_const const& r ) { return get_underlying(l) != get_underlying(r); } template constexpr bool operator >= ( propagate_const const& l, propagate_const const& r ) { return get_underlying(l) >= get_underlying(r); } template constexpr bool operator <= ( propagate_const const& l, propagate_const const& r ) { return get_underlying(l) <= get_underlying(r); } template constexpr bool operator > ( propagate_const const& l, propagate_const const& r ) { return get_underlying(l) > get_underlying(r); } template constexpr bool operator < ( propagate_const const& l, propagate_const const& r ) { return get_underlying(l) < get_underlying(r); } template constexpr bool operator == (propagate_const const& l, U const& r) { return get_underlying(l) == r; } template constexpr bool operator != (propagate_const const& l, U const& r) { return get_underlying(l) != r; } template constexpr bool operator >= (propagate_const const& l, U const& r) { return get_underlying(l) >= r; } template constexpr bool operator <= (propagate_const const& l, U const& r) { return get_underlying(l) <= r; } template constexpr bool operator > (propagate_const const& l, U const& r) { return get_underlying(l) > r; } template constexpr bool operator < (propagate_const const& l, U const& r) { return get_underlying(l) < r; } template constexpr bool operator == ( propagate_const const& l, ::std::nullptr_t ) { return not l; } template constexpr bool operator != ( propagate_const const& l, ::std::nullptr_t ) { return bool(l); } template constexpr bool operator == ( ::std::nullptr_t, propagate_const const& r ) { return not r; } template struct equal_to> { constexpr bool operator () ( propagate_const const& l, propagate_const const& r ) const { return equal_to { }(get_underlying(l), get_underlying(r)); } }; template struct not_equal_to> { constexpr bool operator () ( propagate_const const& l, propagate_const const& r ) const { return not_equal_to { }(get_underlying(l), get_underlying(r)); } }; template struct greater_equal> { constexpr bool operator () ( propagate_const const& l, propagate_const const& r ) const { return greater_equal { }(get_underlying(l), get_underlying(r)); } }; template struct less_equal> { constexpr bool operator () ( propagate_const const& l, propagate_const const& r ) const { return less_equal { }(get_underlying(l), get_underlying(r)); } }; template struct greater> { constexpr bool operator () ( propagate_const const& l, propagate_const const& r ) const { return greater { }(get_underlying(l), get_underlying(r)); } }; template struct less> { constexpr bool operator () ( propagate_const const& l, propagate_const const& r ) const { return less { }(get_underlying(l), get_underlying(r)); } }; }} /* namespace core::v2 */ namespace std { template struct hash<::core::v2::propagate_const> { using argument_type = ::core::v2::propagate_const; using result_type = size_t; result_type operator () (argument_type const& value) const { using underlying_type = typename argument_type::underlying_type; return hash { }(get_underlying(value)); } }; template struct equal_to<::core::v2::propagate_const> { using result_type = bool; using first_argument_type = ::core::v2::propagate_const; using second_argument_type = ::core::v2::propagate_const; bool operator () ( ::core::v2::propagate_const const& lhs, ::core::v2::propagate_const const& rhs ) const { return equal_to { }(get_underlying(lhs), get_underlying(rhs)); } }; template struct not_equal_to<::core::v2::propagate_const> { using result_type = bool; using first_argument_type = ::core::v2::propagate_const; using second_argument_type = ::core::v2::propagate_const; bool operator () ( ::core::v2::propagate_const const& lhs, ::core::v2::propagate_const const& rhs ) const { return not_equal_to { }(get_underlying(lhs), get_underlying(rhs)); } }; template struct greater_equal<::core::v2::propagate_const> { using result_type = bool; using first_argument_type = ::core::v2::propagate_const; using second_argument_type = ::core::v2::propagate_const; bool operator () ( ::core::v2::propagate_const const& lhs, ::core::v2::propagate_const const& rhs ) const { return greater_equal { }(get_underlying(lhs), get_underlying(rhs)); } }; template struct less_equal<::core::v2::propagate_const> { using result_type = bool; using first_argument_type = ::core::v2::propagate_const; using second_argument_type = ::core::v2::propagate_const; bool operator () ( ::core::v2::propagate_const const& lhs, ::core::v2::propagate_const const& rhs ) const { return less_equal { }(get_underlying(lhs), get_underlying(rhs)); } }; template struct greater<::core::v2::propagate_const> { using result_type = bool; using first_argument_type = ::core::v2::propagate_const; using second_argument_type = ::core::v2::propagate_const; bool operator () ( ::core::v2::propagate_const const& lhs, ::core::v2::propagate_const const& rhs ) const { return greater { }(get_underlying(lhs), get_underlying(rhs)); } }; template struct less<::core::v2::propagate_const> { using result_type = bool; using first_argument_type = ::core::v2::propagate_const; using second_argument_type = ::core::v2::propagate_const; bool operator () ( ::core::v2::propagate_const const& lhs, ::core::v2::propagate_const const& rhs ) const { return less { }(get_underlying(lhs), get_underlying(rhs)); } }; } /* namespace std */ #endif /* CORE_PROPAGATE_CONST_HPP */