/* * 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 #include namespace folly { // folly::HeterogeneousAccessEqualTo, and // folly::HeterogeneousAccessHash are functors suitable as defaults // for containers that support heterogeneous access. When possible, they // will be marked as transparent. When no transparent implementation // is available then they fall back to std::equal_to and std::hash // respectively. Since the fallbacks are not marked as transparent, // heterogeneous lookup won't be available in that case. A corresponding // HeterogeneousAccessLess could be easily added if desired. // // If T can be implicitly converted to a StringPiece or // to a Range that is hashable, then // HeterogeneousAccess{EqualTo,Hash} will be transparent without any // additional work. In practice this is true for T that can be convered to // StringPiece or Range. This includes std::string, // std::string_view (when available), std::array, folly::Range, // std::vector, and folly::small_vector. // // Additional specializations of HeterogeneousAccess* should go in // the header that declares T. Don't forget to typedef is_transparent to // void and folly_is_avalanching to std::true_type in the specializations. template struct HeterogeneousAccessEqualTo : std::equal_to {}; template struct HeterogeneousAccessHash : std::hash { using folly_is_avalanching = IsAvalanchingHasher, T>; }; //////// strings namespace detail { template struct ValueTypeForTransparentConversionToRange { using type = char; }; // We assume that folly::hasher> won't be enabled // when it would be lower quality than std::hash for a U that is // convertible to folly::Range. template struct ValueTypeForTransparentConversionToRange< T, void_t>>()( std::declval>()))>> { using type = std::remove_const_t; }; template using TransparentlyConvertibleToRange = std::is_convertible< T, Range::type const*>>; template struct TransparentRangeEqualTo { using is_transparent = void; template bool operator()(U1 const& lhs, U2 const& rhs) const { return Range{lhs} == Range{rhs}; } // This overload is not required for functionality, but // guarantees that replacing std::equal_to with // HeterogeneousAccessEqualTo is truly zero overhead bool operator()(std::string const& lhs, std::string const& rhs) const { return lhs == rhs; } }; template struct TransparentRangeHash { using is_transparent = void; using folly_is_avalanching = std::true_type; private: template static std::size_t hashImpl(Range piece) { return hasher>{}(piece); } static std::size_t hashImpl(StringPiece piece) { #if defined(_GLIBCXX_STRING) return std::_Hash_impl::hash(piece.begin(), piece.size()); #elif defined(_LIBCPP_STRING) return std::__do_string_hash(piece.begin(), piece.end()); #else return hasher{}(piece); #endif } public: template std::size_t operator()(U const& stringish) const { return hashImpl(Range{stringish}); } // Neither this overload nor the platform-conditional compilation // is required for functionality, but implementing it this // way guarantees that replacing std::hash with // HeterogeneousAccessHash is actually zero overhead // in the case that the underlying implementations make different // optimality tradeoffs (short versus long string performance, for // example). If folly::hasher dominated the performance // of std::hash then we should consider using it all of // the time. std::size_t operator()(std::string const& str) const { #if defined(_GLIBCXX_STRING) || defined(_LIBCPP_STRING) return std::hash{}(str); #else return hasher{}(str); #endif } }; } // namespace detail template struct HeterogeneousAccessEqualTo< T, std::enable_if_t::value>> : detail::TransparentRangeEqualTo< typename detail::ValueTypeForTransparentConversionToRange::type> { }; template struct HeterogeneousAccessHash< T, std::enable_if_t::value>> : detail::TransparentRangeHash< typename detail::ValueTypeForTransparentConversionToRange::type> { }; } // namespace folly