From c117f4448f629337dd55386646733dd842b2351e Mon Sep 17 00:00:00 2001 From: Braden Ganetsky Date: Wed, 7 Aug 2024 14:16:09 -0500 Subject: [PATCH 1/3] static_assert on the constructibility of the containers' types --- .../unordered/detail/foa/flat_map_types.hpp | 8 + .../unordered/detail/foa/flat_set_types.hpp | 6 + .../unordered/detail/foa/node_map_types.hpp | 12 +- .../unordered/detail/foa/node_set_types.hpp | 10 +- .../detail/foa/types_constructibility.hpp | 172 ++++++++++++++++++ 5 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 include/boost/unordered/detail/foa/types_constructibility.hpp diff --git a/include/boost/unordered/detail/foa/flat_map_types.hpp b/include/boost/unordered/detail/foa/flat_map_types.hpp index 05610e460..c7f58706b 100644 --- a/include/boost/unordered/detail/foa/flat_map_types.hpp +++ b/include/boost/unordered/detail/foa/flat_map_types.hpp @@ -6,6 +6,8 @@ #ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP #define BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP +#include + #include namespace boost { @@ -25,6 +27,9 @@ namespace boost { using element_type = value_type; + using types = flat_map_types; + using constructibility_checker = map_types_constructibility; + static value_type& value_from(element_type& x) { return x; } template @@ -48,18 +53,21 @@ namespace boost { template static void construct(A& al, init_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } template static void construct(A& al, value_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } template static void construct(A& al, key_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } diff --git a/include/boost/unordered/detail/foa/flat_set_types.hpp b/include/boost/unordered/detail/foa/flat_set_types.hpp index 493cb4fe4..558077f49 100644 --- a/include/boost/unordered/detail/foa/flat_set_types.hpp +++ b/include/boost/unordered/detail/foa/flat_set_types.hpp @@ -5,6 +5,8 @@ #ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP #define BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP +#include + #include namespace boost { @@ -21,6 +23,9 @@ namespace boost { using element_type = value_type; + using types = flat_set_types; + using constructibility_checker = set_types_constructibility; + static Key& value_from(element_type& x) { return x; } static element_type&& move(element_type& x) { return std::move(x); } @@ -28,6 +33,7 @@ namespace boost { template static void construct(A& al, value_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } diff --git a/include/boost/unordered/detail/foa/node_map_types.hpp b/include/boost/unordered/detail/foa/node_map_types.hpp index 4de679a99..0b3d4528e 100644 --- a/include/boost/unordered/detail/foa/node_map_types.hpp +++ b/include/boost/unordered/detail/foa/node_map_types.hpp @@ -7,6 +7,7 @@ #define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP #include +#include #include #include @@ -29,6 +30,9 @@ namespace boost { using element_type = foa::element_type; + using types = node_map_types; + using constructibility_checker = map_types_constructibility; + static value_type& value_from(element_type const& x) { return *(x.p); @@ -74,18 +78,21 @@ namespace boost { template static void construct(A& al, init_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } template static void construct(A& al, value_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } template static void construct(A& al, key_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } @@ -95,8 +102,11 @@ namespace boost { p->p = boost::allocator_allocate(al, 1); BOOST_TRY { + auto address = boost::to_address(p->p); + constructibility_checker::check( + al, address, std::forward(args)...); boost::allocator_construct( - al, boost::to_address(p->p), std::forward(args)...); + al, address, std::forward(args)...); } BOOST_CATCH(...) { diff --git a/include/boost/unordered/detail/foa/node_set_types.hpp b/include/boost/unordered/detail/foa/node_set_types.hpp index 710ac6ccd..79cf12f0a 100644 --- a/include/boost/unordered/detail/foa/node_set_types.hpp +++ b/include/boost/unordered/detail/foa/node_set_types.hpp @@ -6,6 +6,7 @@ #define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP #include +#include #include #include @@ -26,6 +27,9 @@ namespace boost { using element_type = foa::element_type; + using types = node_set_types; + using constructibility_checker = set_types_constructibility; + static value_type& value_from(element_type const& x) { return *x.p; } static Key const& extract(element_type const& k) { return *k.p; } static element_type&& move(element_type& x) { return std::move(x); } @@ -49,6 +53,7 @@ namespace boost { template static void construct(A& al, value_type* p, Args&&... args) { + constructibility_checker::check(al, p, std::forward(args)...); boost::allocator_construct(al, p, std::forward(args)...); } @@ -58,8 +63,11 @@ namespace boost { p->p = boost::allocator_allocate(al, 1); BOOST_TRY { + auto address = boost::to_address(p->p); + constructibility_checker::check( + al, address, std::forward(args)...); boost::allocator_construct( - al, boost::to_address(p->p), std::forward(args)...); + al, address, std::forward(args)...); } BOOST_CATCH(...) { diff --git a/include/boost/unordered/detail/foa/types_constructibility.hpp b/include/boost/unordered/detail/foa/types_constructibility.hpp new file mode 100644 index 000000000..10b9208b1 --- /dev/null +++ b/include/boost/unordered/detail/foa/types_constructibility.hpp @@ -0,0 +1,172 @@ +// Copyright (C) 2024 Braden Ganetsky +// 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) + +#ifndef BOOST_UNORDERED_DETAIL_FOA_TYPES_CONSTRUCTIBILITY_HPP +#define BOOST_UNORDERED_DETAIL_FOA_TYPES_CONSTRUCTIBILITY_HPP + +#include +#include +#include +#include + +namespace boost { + namespace unordered { + namespace detail { + namespace foa { + template struct check_key_type_t + { + static_assert(std::is_constructible::value, + "key_type must be constructible from Args"); + }; + template struct check_key_type_t + { + static_assert(std::is_constructible::value, + "key_type must be default constructible"); + }; + template struct check_key_type_t + { + static_assert(std::is_constructible::value, + "key_type must be copy constructible"); + }; + template struct check_key_type_t + { + static_assert(std::is_constructible::value, + "key_type must be move constructible"); + }; + + template struct check_mapped_type_t + { + static_assert(std::is_constructible::value, + "mapped_type must be constructible from Args"); + }; + template struct check_mapped_type_t + { + static_assert(std::is_constructible::value, + "mapped_type must be default constructible"); + }; + template + struct check_mapped_type_t + { + static_assert(std::is_constructible::value, + "mapped_type must be copy constructible"); + }; + template struct check_mapped_type_t + { + static_assert(std::is_constructible::value, + "mapped_type must be move constructible"); + }; + + template struct map_types_constructibility + { + using key_type = typename TypePolicy::key_type; + using mapped_type = typename TypePolicy::mapped_type; + using init_type = typename TypePolicy::init_type; + using value_type = typename TypePolicy::value_type; + + template + static void check(A&, X*, Args&&...) + { + // Pass through, as we cannot say anything about a general allocator + } + + template static void check_key_type() + { + (void)check_key_type_t{}; + } + template static void check_mapped_type() + { + (void)check_mapped_type_t{}; + } + + template + static void check(std::allocator&, key_type*, Arg&&) + { + check_key_type(); + } + + template + static void check( + std::allocator&, value_type*, Arg1&&, Arg2&&) + { + check_key_type(); + check_mapped_type(); + } + template + static void check(std::allocator&, value_type*, + const std::pair&) + { + check_key_type(); + check_mapped_type(); + } + template + static void check( + std::allocator&, value_type*, std::pair&&) + { + check_key_type(); + check_mapped_type(); + } + template + static void check(std::allocator&, value_type*, + std::piecewise_construct_t, std::tuple&&, + std::tuple&&) + { + check_key_type(); + check_mapped_type(); + } + + template + static void check( + std::allocator&, init_type*, Arg1&&, Arg2&&) + { + check_key_type(); + check_mapped_type(); + } + template + static void check(std::allocator&, init_type*, + const std::pair&) + { + check_key_type(); + check_mapped_type(); + } + template + static void check( + std::allocator&, init_type*, std::pair&&) + { + check_key_type(); + check_mapped_type(); + } + template + static void check(std::allocator&, init_type*, + std::piecewise_construct_t, std::tuple&&, + std::tuple&&) + { + check_key_type(); + check_mapped_type(); + } + }; + + template struct set_types_constructibility + { + using key_type = typename TypePolicy::key_type; + using value_type = typename TypePolicy::value_type; + static_assert(std::is_same::value, ""); + + template + static void check(A&, X*, Args&&...) + { + // Pass through, as we cannot say anything about a general allocator + } + + template + static void check(std::allocator&, key_type*, Args&&...) + { + (void)check_key_type_t{}; + } + }; + } // namespace foa + } // namespace detail + } // namespace unordered +} // namespace boost + +#endif // BOOST_UNORDERED_DETAIL_FOA_TYPES_CONSTRUCTIBILITY_HPP From 793fad5620a7f9fda20852a987df90f3eb676d09 Mon Sep 17 00:00:00 2001 From: Braden Ganetsky Date: Sat, 3 Aug 2024 11:10:46 -0500 Subject: [PATCH 2/3] Run clang-format on the 'types' files --- include/boost/unordered/detail/foa/flat_map_types.hpp | 4 ++-- include/boost/unordered/detail/foa/flat_set_types.hpp | 4 ++-- include/boost/unordered/detail/foa/node_map_types.hpp | 4 ++-- include/boost/unordered/detail/foa/node_set_types.hpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/detail/foa/flat_map_types.hpp b/include/boost/unordered/detail/foa/flat_map_types.hpp index c7f58706b..750691310 100644 --- a/include/boost/unordered/detail/foa/flat_map_types.hpp +++ b/include/boost/unordered/detail/foa/flat_map_types.hpp @@ -87,8 +87,8 @@ namespace boost { } }; } // namespace foa - } // namespace detail - } // namespace unordered + } // namespace detail + } // namespace unordered } // namespace boost #endif // BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP diff --git a/include/boost/unordered/detail/foa/flat_set_types.hpp b/include/boost/unordered/detail/foa/flat_set_types.hpp index 558077f49..3da1f49e3 100644 --- a/include/boost/unordered/detail/foa/flat_set_types.hpp +++ b/include/boost/unordered/detail/foa/flat_set_types.hpp @@ -43,8 +43,8 @@ namespace boost { } }; } // namespace foa - } // namespace detail - } // namespace unordered + } // namespace detail + } // namespace unordered } // namespace boost #endif // BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP diff --git a/include/boost/unordered/detail/foa/node_map_types.hpp b/include/boost/unordered/detail/foa/node_map_types.hpp index 0b3d4528e..789251a6a 100644 --- a/include/boost/unordered/detail/foa/node_map_types.hpp +++ b/include/boost/unordered/detail/foa/node_map_types.hpp @@ -142,8 +142,8 @@ namespace boost { }; } // namespace foa - } // namespace detail - } // namespace unordered + } // namespace detail + } // namespace unordered } // namespace boost #endif // BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP diff --git a/include/boost/unordered/detail/foa/node_set_types.hpp b/include/boost/unordered/detail/foa/node_set_types.hpp index 79cf12f0a..bc2ee8aca 100644 --- a/include/boost/unordered/detail/foa/node_set_types.hpp +++ b/include/boost/unordered/detail/foa/node_set_types.hpp @@ -93,8 +93,8 @@ namespace boost { }; } // namespace foa - } // namespace detail - } // namespace unordered + } // namespace detail + } // namespace unordered } // namespace boost #endif // BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP From a14b1596650d0c402b8af98f9df0477db9106b3a Mon Sep 17 00:00:00 2001 From: Braden Ganetsky Date: Wed, 7 Aug 2024 16:15:36 -0500 Subject: [PATCH 3/3] Add missing calls to as_const(), otherwise we may call a 'T(T&)' constructor instead of the intended 'T(T const&)' --- include/boost/unordered/detail/foa/node_map_types.hpp | 3 ++- include/boost/unordered/detail/foa/node_set_types.hpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa/node_map_types.hpp b/include/boost/unordered/detail/foa/node_map_types.hpp index 789251a6a..f13a7a84d 100644 --- a/include/boost/unordered/detail/foa/node_map_types.hpp +++ b/include/boost/unordered/detail/foa/node_map_types.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -72,7 +73,7 @@ namespace boost { static void construct( A& al, element_type* p, element_type const& copy) { - construct(al, p, *copy.p); + construct(al, p, detail::as_const(*copy.p)); } template diff --git a/include/boost/unordered/detail/foa/node_set_types.hpp b/include/boost/unordered/detail/foa/node_set_types.hpp index bc2ee8aca..da47793f7 100644 --- a/include/boost/unordered/detail/foa/node_set_types.hpp +++ b/include/boost/unordered/detail/foa/node_set_types.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -39,7 +40,7 @@ namespace boost { static void construct( A& al, element_type* p, element_type const& copy) { - construct(al, p, *copy.p); + construct(al, p, detail::as_const(*copy.p)); } template