diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 29af58bf..0d48c911 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -72,6 +72,8 @@ namespace unordered{ namespace detail{ namespace foa{ +static const std::size_t default_bucket_count = 0; + /* foa::table is an open-addressing hash table serving as the foundational core * of boost::unordered_flat_[map|set]. Its main internal design aspects are: * diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 48a0170d..d953b313 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -182,18 +182,6 @@ #endif #endif -// BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES - -#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES) -#if BOOST_COMP_CLANG && __cplusplus >= 201703 -#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 1 -#endif -#endif - -#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES) -#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 0 -#endif - namespace boost { namespace unordered { namespace detail { diff --git a/include/boost/unordered/detail/type_traits.hpp b/include/boost/unordered/detail/type_traits.hpp index 3d7dcf67..3fe2f404 100644 --- a/include/boost/unordered/detail/type_traits.hpp +++ b/include/boost/unordered/detail/type_traits.hpp @@ -14,6 +14,25 @@ #include #include #include +#include + +#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) +#include +#include +#include +#endif + +// BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + +#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES) +#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) +#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 1 +#endif +#endif + +#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES) +#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 0 +#endif namespace boost { namespace unordered { @@ -52,6 +71,37 @@ namespace boost { !boost::is_convertible::value && !boost::is_convertible::value; }; + +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + // https://eel.is/c++draft/container.requirements#container.alloc.reqmts-34 + // https://eel.is/c++draft/container.requirements#unord.req.general-243 + + template + constexpr bool const is_input_iterator_v = + !boost::is_integral::value; + + template struct is_allocator + { + constexpr static bool const value = false; + }; + + template + struct is_allocator().allocate(std::size_t{}))> > + { + constexpr static bool const value = true; + }; + + template + constexpr bool const is_allocator_v = is_allocator::value; + + template + constexpr bool const is_hash_v = + !boost::is_integral::value && !is_allocator_v; + + template constexpr bool const is_pred_v = !is_allocator_v

; +#endif } // namespace detail } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 7ba2ba28..ac723ce9 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -76,9 +76,9 @@ namespace boost { using init_type = typename map_types::init_type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using hasher = Hash; - using key_equal = KeyEqual; - using allocator_type = Allocator; + using hasher = typename boost::type_identity::type; + using key_equal = typename boost::type_identity::type; + using allocator_type = typename boost::type_identity::type; using reference = value_type&; using const_reference = value_type const&; using pointer = typename boost::allocator_pointer::type; @@ -628,6 +628,104 @@ namespace boost { #pragma warning(pop) /* C4714 */ #endif +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + + namespace detail { + template + using iter_key_t = + typename std::iterator_traits::value_type::first_type; + template + using iter_val_t = + typename std::iterator_traits::value_type::second_type; + template + using iter_to_alloc_t = + typename std::pair const, iter_val_t >; + } // namespace detail + + template >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::iter_to_alloc_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_flat_map(InputIterator, InputIterator, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_map, + boost::unordered::detail::iter_val_t, Hash, Pred, + Allocator>; + + template >, + class Pred = std::equal_to >, + class Allocator = std::allocator >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_flat_map(std::initializer_list >, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_map, T, Hash, Pred, + Allocator>; + + template >, + class = boost::enable_if_t > > + unordered_flat_map(InputIterator, InputIterator, std::size_t, Allocator) + -> unordered_flat_map, + boost::unordered::detail::iter_val_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = boost::enable_if_t > > + unordered_flat_map(InputIterator, InputIterator, Allocator) + -> unordered_flat_map, + boost::unordered::detail::iter_val_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_flat_map( + InputIterator, InputIterator, std::size_t, Hash, Allocator) + -> unordered_flat_map, + boost::unordered::detail::iter_val_t, Hash, + std::equal_to >, + Allocator>; + + template > > + unordered_flat_map(std::initializer_list >, std::size_t, + Allocator) -> unordered_flat_map, T, + boost::hash >, + std::equal_to >, Allocator>; + + template > > + unordered_flat_map(std::initializer_list >, Allocator) + -> unordered_flat_map, T, + boost::hash >, + std::equal_to >, Allocator>; + + template >, + class = boost::enable_if_t > > + unordered_flat_map(std::initializer_list >, std::size_t, + Hash, Allocator) -> unordered_flat_map, T, + Hash, std::equal_to >, Allocator>; +#endif + } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index ef96d4e1..b1291caf 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -503,6 +503,68 @@ namespace boost { #pragma warning(pop) /* C4714 */ #endif +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + template ::value_type>, + class Pred = + std::equal_to::value_type>, + class Allocator = std::allocator< + typename std::iterator_traits::value_type>, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_flat_set(InputIterator, InputIterator, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_set< + typename std::iterator_traits::value_type, Hash, Pred, + Allocator>; + + template , + class Pred = std::equal_to, class Allocator = std::allocator, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_flat_set(std::initializer_list, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_set; + + template >, + class = boost::enable_if_t > > + unordered_flat_set(InputIterator, InputIterator, std::size_t, Allocator) + -> unordered_flat_set< + typename std::iterator_traits::value_type, + boost::hash::value_type>, + std::equal_to::value_type>, + Allocator>; + + template >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_flat_set( + InputIterator, InputIterator, std::size_t, Hash, Allocator) + -> unordered_flat_set< + typename std::iterator_traits::value_type, Hash, + std::equal_to::value_type>, + Allocator>; + + template > > + unordered_flat_set(std::initializer_list, std::size_t, Allocator) + -> unordered_flat_set, std::equal_to, Allocator>; + + template >, + class = boost::enable_if_t > > + unordered_flat_set(std::initializer_list, std::size_t, Hash, Allocator) + -> unordered_flat_set, Allocator>; +#endif + } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 4a060358..9d80d743 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) #include @@ -50,9 +51,9 @@ namespace boost { typedef K key_type; typedef T mapped_type; typedef std::pair value_type; - typedef H hasher; - typedef P key_equal; - typedef A allocator_type; + typedef typename boost::type_identity::type hasher; + typedef typename boost::type_identity

::type key_equal; + typedef typename boost::type_identity::type allocator_type; private: typedef boost::unordered::detail::map types; @@ -931,7 +932,7 @@ namespace boost { template using iter_to_alloc_t = typename std::pair const, iter_val_t >; - } + } // namespace detail template >, class Allocator = std::allocator< - boost::unordered::detail::iter_to_alloc_t > > + boost::unordered::detail::iter_to_alloc_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_map(InputIterator, InputIterator, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_map, + -> unordered_map, boost::unordered::detail::iter_val_t, Hash, Pred, Allocator>; - template , - class Pred = std::equal_to, - class Allocator = std::allocator > > - unordered_map(std::initializer_list >, + template >, + class Pred = std::equal_to >, + class Allocator = std::allocator >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_map(std::initializer_list >, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_map; + -> unordered_map, T, Hash, Pred, Allocator>; - template + template >, + class = boost::enable_if_t > > unordered_map(InputIterator, InputIterator, std::size_t, Allocator) - ->unordered_map, + -> unordered_map, boost::unordered::detail::iter_val_t, boost::hash >, std::equal_to >, Allocator>; - template + template >, + class = boost::enable_if_t > > unordered_map(InputIterator, InputIterator, Allocator) - ->unordered_map, + -> unordered_map, boost::unordered::detail::iter_val_t, boost::hash >, std::equal_to >, Allocator>; - template + template >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_map(InputIterator, InputIterator, std::size_t, Hash, Allocator) - ->unordered_map, + -> unordered_map, boost::unordered::detail::iter_val_t, Hash, std::equal_to >, Allocator>; - template - unordered_map( - std::initializer_list >, std::size_t, Allocator) - ->unordered_map, std::equal_to, Allocator>; + template > > + unordered_map(std::initializer_list >, std::size_t, + Allocator) -> unordered_map, T, + boost::hash >, + std::equal_to >, Allocator>; - template - unordered_map(std::initializer_list >, Allocator) - ->unordered_map, std::equal_to, Allocator>; + template > > + unordered_map(std::initializer_list >, Allocator) + -> unordered_map, T, + boost::hash >, + std::equal_to >, Allocator>; - template - unordered_map(std::initializer_list >, std::size_t, - Hash, Allocator) - ->unordered_map, Allocator>; + template >, + class = boost::enable_if_t > > + unordered_map(std::initializer_list >, std::size_t, Hash, + Allocator) -> unordered_map, T, Hash, + std::equal_to >, Allocator>; #endif @@ -1007,9 +1030,9 @@ namespace boost { typedef K key_type; typedef T mapped_type; typedef std::pair value_type; - typedef H hasher; - typedef P key_equal; - typedef A allocator_type; + typedef typename boost::type_identity::type hasher; + typedef typename boost::type_identity

::type key_equal; + typedef typename boost::type_identity::type allocator_type; private: typedef boost::unordered::detail::map types; @@ -1612,62 +1635,82 @@ namespace boost { class Pred = std::equal_to >, class Allocator = std::allocator< - boost::unordered::detail::iter_to_alloc_t > > + boost::unordered::detail::iter_to_alloc_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_multimap(InputIterator, InputIterator, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_multimap, + -> unordered_multimap, boost::unordered::detail::iter_val_t, Hash, Pred, Allocator>; - template , - class Pred = std::equal_to, - class Allocator = std::allocator > > - unordered_multimap(std::initializer_list >, + template >, + class Pred = std::equal_to >, + class Allocator = std::allocator >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + unordered_multimap(std::initializer_list >, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_multimap; + -> unordered_multimap, T, Hash, Pred, + Allocator>; - template + template >, + class = boost::enable_if_t > > unordered_multimap(InputIterator, InputIterator, std::size_t, Allocator) - ->unordered_multimap, + -> unordered_multimap, boost::unordered::detail::iter_val_t, boost::hash >, std::equal_to >, Allocator>; - template + template >, + class = boost::enable_if_t > > unordered_multimap(InputIterator, InputIterator, Allocator) - ->unordered_multimap, + -> unordered_multimap, boost::unordered::detail::iter_val_t, boost::hash >, std::equal_to >, Allocator>; - template + template >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_multimap( InputIterator, InputIterator, std::size_t, Hash, Allocator) - ->unordered_multimap, + -> unordered_multimap, boost::unordered::detail::iter_val_t, Hash, std::equal_to >, Allocator>; - template - unordered_multimap( - std::initializer_list >, std::size_t, Allocator) - ->unordered_multimap, std::equal_to, - Allocator>; + template > > + unordered_multimap(std::initializer_list >, std::size_t, + Allocator) -> unordered_multimap, T, + boost::hash >, + std::equal_to >, Allocator>; - template - unordered_multimap( - std::initializer_list >, Allocator) - ->unordered_multimap, std::equal_to, - Allocator>; + template > > + unordered_multimap(std::initializer_list >, Allocator) + -> unordered_multimap, T, + boost::hash >, + std::equal_to >, Allocator>; - template - unordered_multimap(std::initializer_list >, - std::size_t, Hash, Allocator) - ->unordered_multimap, Allocator>; + template >, + class = boost::enable_if_t > > + unordered_multimap(std::initializer_list >, std::size_t, + Hash, Allocator) -> unordered_multimap, T, + Hash, std::equal_to >, Allocator>; #endif diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index b3e75134..7c8ce72c 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) #include @@ -621,41 +622,56 @@ namespace boost { class Pred = std::equal_to::value_type>, class Allocator = std::allocator< - typename std::iterator_traits::value_type> > + typename std::iterator_traits::value_type>, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_set(InputIterator, InputIterator, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_set::value_type, + -> unordered_set::value_type, Hash, Pred, Allocator>; template , - class Pred = std::equal_to, class Allocator = std::allocator > + class Pred = std::equal_to, class Allocator = std::allocator, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_set(std::initializer_list, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_set; + -> unordered_set; - template + template >, + class = boost::enable_if_t > > unordered_set(InputIterator, InputIterator, std::size_t, Allocator) - ->unordered_set::value_type, + -> unordered_set::value_type, boost::hash::value_type>, std::equal_to::value_type>, Allocator>; - template + template >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_set(InputIterator, InputIterator, std::size_t, Hash, Allocator) - ->unordered_set::value_type, + -> unordered_set::value_type, Hash, std::equal_to::value_type>, Allocator>; - template + template > > unordered_set(std::initializer_list, std::size_t, Allocator) - ->unordered_set, std::equal_to, Allocator>; + -> unordered_set, std::equal_to, Allocator>; - template + template >, + class = boost::enable_if_t > > unordered_set(std::initializer_list, std::size_t, Hash, Allocator) - ->unordered_set, Allocator>; + -> unordered_set, Allocator>; #endif @@ -1233,44 +1249,59 @@ namespace boost { class Pred = std::equal_to::value_type>, class Allocator = std::allocator< - typename std::iterator_traits::value_type> > + typename std::iterator_traits::value_type>, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_multiset(InputIterator, InputIterator, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_multiset< + -> unordered_multiset< typename std::iterator_traits::value_type, Hash, Pred, Allocator>; template , - class Pred = std::equal_to, class Allocator = std::allocator > + class Pred = std::equal_to, class Allocator = std::allocator, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_multiset(std::initializer_list, std::size_t = boost::unordered::detail::default_bucket_count, Hash = Hash(), Pred = Pred(), Allocator = Allocator()) - ->unordered_multiset; + -> unordered_multiset; - template + template >, + class = boost::enable_if_t > > unordered_multiset(InputIterator, InputIterator, std::size_t, Allocator) - ->unordered_multiset< + -> unordered_multiset< typename std::iterator_traits::value_type, boost::hash::value_type>, std::equal_to::value_type>, Allocator>; - template + template >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > unordered_multiset( InputIterator, InputIterator, std::size_t, Hash, Allocator) - ->unordered_multiset< + -> unordered_multiset< typename std::iterator_traits::value_type, Hash, std::equal_to::value_type>, Allocator>; - template + template > > unordered_multiset(std::initializer_list, std::size_t, Allocator) - ->unordered_multiset, std::equal_to, Allocator>; + -> unordered_multiset, std::equal_to, Allocator>; - template + template >, + class = boost::enable_if_t > > unordered_multiset(std::initializer_list, std::size_t, Hash, Allocator) - ->unordered_multiset, Allocator>; + -> unordered_multiset, Allocator>; #endif diff --git a/test/unordered/deduction_tests.cpp b/test/unordered/deduction_tests.cpp index cffb0c1d..c979937f 100644 --- a/test/unordered/deduction_tests.cpp +++ b/test/unordered/deduction_tests.cpp @@ -3,11 +3,17 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include #include +#include #include #include #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + +#include +#include + struct hash_equals { template bool operator()(T const& x) const @@ -33,22 +39,15 @@ template struct test_allocator bool operator==(test_allocator const&) const { return true; } bool operator!=(test_allocator const&) const { return false; } }; -#endif -int main() +template