/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include namespace folly { template class propagate_const; template constexpr Pointer& get_underlying(propagate_const& obj) { return obj.pointer_; } template constexpr Pointer const& get_underlying(propagate_const const& obj) { return obj.pointer_; } namespace detail { template using is_propagate_const = is_instantiation_of; template using is_decay_propagate_const = is_propagate_const>; namespace propagate_const_adl { using std::swap; template auto adl_swap(T& a, T& b) noexcept(noexcept(swap(a, b))) -> decltype(swap(a, b)) { swap(a, b); } } // namespace propagate_const_adl } // namespace detail // mimic: std::experimental::propagate_const, C++ Library Fundamentals TS v2 template class propagate_const { public: using element_type = std::remove_reference_t())>; constexpr propagate_const() = default; constexpr propagate_const(propagate_const&&) = default; propagate_const(propagate_const const&) = delete; template < typename OtherPointer, std::enable_if_t< std::is_constructible::value && !std::is_convertible::value, int> = 0> constexpr explicit propagate_const(propagate_const&& other) : pointer_(static_cast(other.pointer_)) {} template < typename OtherPointer, std::enable_if_t< std::is_constructible::value && std::is_convertible::value, int> = 0> constexpr propagate_const(propagate_const&& other) : pointer_(static_cast(other.pointer_)) {} template < typename OtherPointer, std::enable_if_t< !detail::is_decay_propagate_const::value && std::is_constructible::value && !std::is_convertible::value, int> = 0> constexpr explicit propagate_const(OtherPointer&& other) : pointer_(static_cast(other)) {} template < typename OtherPointer, std::enable_if_t< !detail::is_decay_propagate_const::value && std::is_constructible::value && std::is_convertible::value, int> = 0> constexpr propagate_const(OtherPointer&& other) : pointer_(static_cast(other)) {} constexpr propagate_const& operator=(propagate_const&&) = default; propagate_const& operator=(propagate_const const&) = delete; template < typename OtherPointer, typename = std::enable_if_t::value>> constexpr propagate_const& operator=(propagate_const&& other) { pointer_ = static_cast(other.pointer_); } template < typename OtherPointer, typename = std::enable_if_t< !detail::is_decay_propagate_const::value && std::is_convertible::value>> constexpr propagate_const& operator=(OtherPointer&& other) { pointer_ = static_cast(other); return *this; } constexpr void swap(propagate_const& other) noexcept( noexcept(detail::propagate_const_adl::adl_swap( std::declval(), other.pointer_))) { detail::propagate_const_adl::adl_swap(pointer_, other.pointer_); } constexpr element_type* get() { return get_(pointer_); } constexpr element_type const* get() const { return get_(pointer_); } constexpr explicit operator bool() const { return static_cast(pointer_); } constexpr element_type& operator*() { return *get(); } constexpr element_type const& operator*() const { return *get(); } constexpr element_type* operator->() { return get(); } constexpr element_type const* operator->() const { return get(); } template < typename OtherPointer = Pointer, typename = std::enable_if_t< std::is_pointer::value || std::is_convertible::value>> constexpr operator element_type*() { return get(); } template < typename OtherPointer = Pointer, typename = std::enable_if_t< std::is_pointer::value || std::is_convertible::value>> constexpr operator element_type const*() const { return get(); } private: friend Pointer& get_underlying<>(propagate_const&); friend Pointer const& get_underlying<>(propagate_const const&); template friend class propagate_const; template constexpr static T* get_(T* t) { return t; } template constexpr static auto get_(T& t) -> decltype(t.get()) { return t.get(); } Pointer pointer_; }; template constexpr void swap( propagate_const& a, propagate_const& b) noexcept(noexcept(a.swap(b))) { a.swap(b); } template constexpr bool operator==(propagate_const const& a, std::nullptr_t) { return get_underlying(a) == nullptr; } template constexpr bool operator==(std::nullptr_t, propagate_const const& a) { return nullptr == get_underlying(a); } template constexpr bool operator!=(propagate_const const& a, std::nullptr_t) { return get_underlying(a) != nullptr; } template constexpr bool operator!=(std::nullptr_t, propagate_const const& a) { return nullptr != get_underlying(a); } template constexpr bool operator==( propagate_const const& a, propagate_const const& b) { return get_underlying(a) == get_underlying(b); } template constexpr bool operator!=( propagate_const const& a, propagate_const const& b) { return get_underlying(a) != get_underlying(b); } template constexpr bool operator<( propagate_const const& a, propagate_const const& b) { return get_underlying(a) < get_underlying(b); } template constexpr bool operator<=( propagate_const const& a, propagate_const const& b) { return get_underlying(a) <= get_underlying(b); } template constexpr bool operator>( propagate_const const& a, propagate_const const& b) { return get_underlying(a) > get_underlying(b); } template constexpr bool operator>=( propagate_const const& a, propagate_const const& b) { return get_underlying(a) >= get_underlying(b); } // Note: contrary to the specification, the heterogeneous comparison operators // only participate in overload resolution when the equivalent heterogeneous // comparison operators on the underlying pointers, as returned by invocation // of get_underlying, would also participate in overload resolution. template constexpr auto operator==(propagate_const const& a, Other const& b) -> decltype(get_underlying(a) == b, false) { return get_underlying(a) == b; } template constexpr auto operator!=(propagate_const const& a, Other const& b) -> decltype(get_underlying(a) != b, false) { return get_underlying(a) != b; } template constexpr auto operator<(propagate_const const& a, Other const& b) -> decltype(get_underlying(a) < b, false) { return get_underlying(a) < b; } template constexpr auto operator<=(propagate_const const& a, Other const& b) -> decltype(get_underlying(a) <= b, false) { return get_underlying(a) <= b; } template constexpr auto operator>(propagate_const const& a, Other const& b) -> decltype(get_underlying(a) > b, false) { return get_underlying(a) > b; } template constexpr auto operator>=(propagate_const const& a, Other const& b) -> decltype(get_underlying(a) >= b, false) { return get_underlying(a) >= b; } template constexpr auto operator==(Other const& a, propagate_const const& b) -> decltype(a == get_underlying(b), false) { return a == get_underlying(b); } template constexpr auto operator!=(Other const& a, propagate_const const& b) -> decltype(a != get_underlying(b), false) { return a != get_underlying(b); } template constexpr auto operator<(Other const& a, propagate_const const& b) -> decltype(a < get_underlying(b), false) { return a < get_underlying(b); } template constexpr auto operator<=(Other const& a, propagate_const const& b) -> decltype(a <= get_underlying(b), false) { return a <= get_underlying(b); } template constexpr auto operator>(Other const& a, propagate_const const& b) -> decltype(a > get_underlying(b), false) { return a > get_underlying(b); } template constexpr auto operator>=(Other const& a, propagate_const const& b) -> decltype(a >= get_underlying(b), false) { return a >= get_underlying(b); } } // namespace folly namespace std { template struct hash> : private hash { using hash::hash; size_t operator()(folly::propagate_const const& obj) const { return hash::operator()(folly::get_underlying(obj)); } }; template struct equal_to> : private equal_to { using equal_to::equal_to; constexpr bool operator()( folly::propagate_const const& a, folly::propagate_const const& b) { return equal_to::operator()( folly::get_underlying(a), folly::get_underlying(b)); } }; template struct not_equal_to> : private not_equal_to { using not_equal_to::not_equal_to; constexpr bool operator()( folly::propagate_const const& a, folly::propagate_const const& b) { return not_equal_to::operator()( folly::get_underlying(a), folly::get_underlying(b)); } }; template struct less> : private less { using less::less; constexpr bool operator()( folly::propagate_const const& a, folly::propagate_const const& b) { return less::operator()( folly::get_underlying(a), folly::get_underlying(b)); } }; template struct greater> : private greater { using greater::greater; constexpr bool operator()( folly::propagate_const const& a, folly::propagate_const const& b) { return greater::operator()( folly::get_underlying(a), folly::get_underlying(b)); } }; template struct less_equal> : private less_equal { using less_equal::less_equal; constexpr bool operator()( folly::propagate_const const& a, folly::propagate_const const& b) { return less_equal::operator()( folly::get_underlying(a), folly::get_underlying(b)); } }; template struct greater_equal> : private greater_equal { using greater_equal::greater_equal; constexpr bool operator()( folly::propagate_const const& a, folly::propagate_const const& b) { return greater_equal::operator()( folly::get_underlying(a), folly::get_underlying(b)); } }; } // namespace std