diff --git a/include/boost/unordered/detail/foa/flat_map_types.hpp b/include/boost/unordered/detail/foa/flat_map_types.hpp index 05610e460..750691310 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)...); } @@ -79,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 493cb4fe4..3da1f49e3 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)...); } @@ -37,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 4de679a99..f13a7a84d 100644 --- a/include/boost/unordered/detail/foa/node_map_types.hpp +++ b/include/boost/unordered/detail/foa/node_map_types.hpp @@ -7,6 +7,8 @@ #define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP #include +#include +#include #include #include @@ -29,6 +31,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); @@ -68,24 +73,27 @@ 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 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 +103,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(...) { @@ -132,8 +143,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 710ac6ccd..da47793f7 100644 --- a/include/boost/unordered/detail/foa/node_set_types.hpp +++ b/include/boost/unordered/detail/foa/node_set_types.hpp @@ -6,6 +6,8 @@ #define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP #include +#include +#include #include #include @@ -26,6 +28,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); } @@ -35,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 @@ -49,6 +54,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 +64,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(...) { @@ -85,8 +94,8 @@ namespace boost { }; } // namespace foa - } // namespace detail - } // namespace unordered + } // namespace detail + } // namespace unordered } // namespace boost #endif // BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP 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