static_assert on the constructibility of the containers' types

This commit is contained in:
Braden Ganetsky
2024-08-07 14:16:09 -05:00
parent 65f3ea60dd
commit c117f4448f
5 changed files with 206 additions and 2 deletions

View File

@ -6,6 +6,8 @@
#ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP #ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP
#define BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP #define BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP
#include <boost/unordered/detail/foa/types_constructibility.hpp>
#include <boost/core/allocator_access.hpp> #include <boost/core/allocator_access.hpp>
namespace boost { namespace boost {
@ -25,6 +27,9 @@ namespace boost {
using element_type = value_type; using element_type = value_type;
using types = flat_map_types<Key, T>;
using constructibility_checker = map_types_constructibility<types>;
static value_type& value_from(element_type& x) { return x; } static value_type& value_from(element_type& x) { return x; }
template <class K, class V> template <class K, class V>
@ -48,18 +53,21 @@ namespace boost {
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, init_type* p, Args&&... args) static void construct(A& al, init_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, value_type* p, Args&&... args) static void construct(A& al, value_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, key_type* p, Args&&... args) static void construct(A& al, key_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }

View File

@ -5,6 +5,8 @@
#ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP #ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP
#define BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP #define BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP
#include <boost/unordered/detail/foa/types_constructibility.hpp>
#include <boost/core/allocator_access.hpp> #include <boost/core/allocator_access.hpp>
namespace boost { namespace boost {
@ -21,6 +23,9 @@ namespace boost {
using element_type = value_type; using element_type = value_type;
using types = flat_set_types<Key>;
using constructibility_checker = set_types_constructibility<types>;
static Key& value_from(element_type& x) { return x; } static Key& value_from(element_type& x) { return x; }
static element_type&& move(element_type& x) { return std::move(x); } static element_type&& move(element_type& x) { return std::move(x); }
@ -28,6 +33,7 @@ namespace boost {
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, value_type* p, Args&&... args) static void construct(A& al, value_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }

View File

@ -7,6 +7,7 @@
#define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP #define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP
#include <boost/unordered/detail/foa/element_type.hpp> #include <boost/unordered/detail/foa/element_type.hpp>
#include <boost/unordered/detail/foa/types_constructibility.hpp>
#include <boost/core/allocator_access.hpp> #include <boost/core/allocator_access.hpp>
#include <boost/core/no_exceptions_support.hpp> #include <boost/core/no_exceptions_support.hpp>
@ -29,6 +30,9 @@ namespace boost {
using element_type = foa::element_type<value_type, VoidPtr>; using element_type = foa::element_type<value_type, VoidPtr>;
using types = node_map_types<Key, T, VoidPtr>;
using constructibility_checker = map_types_constructibility<types>;
static value_type& value_from(element_type const& x) static value_type& value_from(element_type const& x)
{ {
return *(x.p); return *(x.p);
@ -74,18 +78,21 @@ namespace boost {
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, init_type* p, Args&&... args) static void construct(A& al, init_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, value_type* p, Args&&... args) static void construct(A& al, value_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, key_type* p, Args&&... args) static void construct(A& al, key_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }
@ -95,8 +102,11 @@ namespace boost {
p->p = boost::allocator_allocate(al, 1); p->p = boost::allocator_allocate(al, 1);
BOOST_TRY BOOST_TRY
{ {
auto address = boost::to_address(p->p);
constructibility_checker::check(
al, address, std::forward<Args>(args)...);
boost::allocator_construct( boost::allocator_construct(
al, boost::to_address(p->p), std::forward<Args>(args)...); al, address, std::forward<Args>(args)...);
} }
BOOST_CATCH(...) BOOST_CATCH(...)
{ {

View File

@ -6,6 +6,7 @@
#define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP #define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP
#include <boost/unordered/detail/foa/element_type.hpp> #include <boost/unordered/detail/foa/element_type.hpp>
#include <boost/unordered/detail/foa/types_constructibility.hpp>
#include <boost/core/allocator_access.hpp> #include <boost/core/allocator_access.hpp>
#include <boost/core/no_exceptions_support.hpp> #include <boost/core/no_exceptions_support.hpp>
@ -26,6 +27,9 @@ namespace boost {
using element_type = foa::element_type<value_type, VoidPtr>; using element_type = foa::element_type<value_type, VoidPtr>;
using types = node_set_types<Key, VoidPtr>;
using constructibility_checker = set_types_constructibility<types>;
static value_type& value_from(element_type const& x) { return *x.p; } static value_type& value_from(element_type const& x) { return *x.p; }
static Key const& extract(element_type const& k) { return *k.p; } static Key const& extract(element_type const& k) { return *k.p; }
static element_type&& move(element_type& x) { return std::move(x); } static element_type&& move(element_type& x) { return std::move(x); }
@ -49,6 +53,7 @@ namespace boost {
template <class A, class... Args> template <class A, class... Args>
static void construct(A& al, value_type* p, Args&&... args) static void construct(A& al, value_type* p, Args&&... args)
{ {
constructibility_checker::check(al, p, std::forward<Args>(args)...);
boost::allocator_construct(al, p, std::forward<Args>(args)...); boost::allocator_construct(al, p, std::forward<Args>(args)...);
} }
@ -58,8 +63,11 @@ namespace boost {
p->p = boost::allocator_allocate(al, 1); p->p = boost::allocator_allocate(al, 1);
BOOST_TRY BOOST_TRY
{ {
auto address = boost::to_address(p->p);
constructibility_checker::check(
al, address, std::forward<Args>(args)...);
boost::allocator_construct( boost::allocator_construct(
al, boost::to_address(p->p), std::forward<Args>(args)...); al, address, std::forward<Args>(args)...);
} }
BOOST_CATCH(...) BOOST_CATCH(...)
{ {

View File

@ -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 <memory>
#include <tuple>
#include <type_traits>
#include <utility>
namespace boost {
namespace unordered {
namespace detail {
namespace foa {
template <class Key, class... Args> struct check_key_type_t
{
static_assert(std::is_constructible<Key, Args...>::value,
"key_type must be constructible from Args");
};
template <class Key> struct check_key_type_t<Key>
{
static_assert(std::is_constructible<Key>::value,
"key_type must be default constructible");
};
template <class Key> struct check_key_type_t<Key, const Key&>
{
static_assert(std::is_constructible<Key, const Key&>::value,
"key_type must be copy constructible");
};
template <class Key> struct check_key_type_t<Key, Key&&>
{
static_assert(std::is_constructible<Key, Key&&>::value,
"key_type must be move constructible");
};
template <class Mapped, class... Args> struct check_mapped_type_t
{
static_assert(std::is_constructible<Mapped, Args...>::value,
"mapped_type must be constructible from Args");
};
template <class Mapped> struct check_mapped_type_t<Mapped>
{
static_assert(std::is_constructible<Mapped>::value,
"mapped_type must be default constructible");
};
template <class Mapped>
struct check_mapped_type_t<Mapped, const Mapped&>
{
static_assert(std::is_constructible<Mapped, const Mapped&>::value,
"mapped_type must be copy constructible");
};
template <class Mapped> struct check_mapped_type_t<Mapped, Mapped&&>
{
static_assert(std::is_constructible<Mapped, Mapped&&>::value,
"mapped_type must be move constructible");
};
template <class TypePolicy> 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 <class A, class X, class... Args>
static void check(A&, X*, Args&&...)
{
// Pass through, as we cannot say anything about a general allocator
}
template <class... Args> static void check_key_type()
{
(void)check_key_type_t<key_type, Args...>{};
}
template <class... Args> static void check_mapped_type()
{
(void)check_mapped_type_t<mapped_type, Args...>{};
}
template <class Arg>
static void check(std::allocator<value_type>&, key_type*, Arg&&)
{
check_key_type<Arg&&>();
}
template <class Arg1, class Arg2>
static void check(
std::allocator<value_type>&, value_type*, Arg1&&, Arg2&&)
{
check_key_type<Arg1&&>();
check_mapped_type<Arg2&&>();
}
template <class Arg1, class Arg2>
static void check(std::allocator<value_type>&, value_type*,
const std::pair<Arg1, Arg2>&)
{
check_key_type<const Arg1&>();
check_mapped_type<const Arg2&>();
}
template <class Arg1, class Arg2>
static void check(
std::allocator<value_type>&, value_type*, std::pair<Arg1, Arg2>&&)
{
check_key_type<Arg1&&>();
check_mapped_type<Arg2&&>();
}
template <class... Args1, class... Args2>
static void check(std::allocator<value_type>&, value_type*,
std::piecewise_construct_t, std::tuple<Args1...>&&,
std::tuple<Args2...>&&)
{
check_key_type<Args1&&...>();
check_mapped_type<Args2&&...>();
}
template <class Arg1, class Arg2>
static void check(
std::allocator<value_type>&, init_type*, Arg1&&, Arg2&&)
{
check_key_type<Arg1&&>();
check_mapped_type<Arg2&&>();
}
template <class Arg1, class Arg2>
static void check(std::allocator<value_type>&, init_type*,
const std::pair<Arg1, Arg2>&)
{
check_key_type<const Arg1&>();
check_mapped_type<const Arg2&>();
}
template <class Arg1, class Arg2>
static void check(
std::allocator<value_type>&, init_type*, std::pair<Arg1, Arg2>&&)
{
check_key_type<Arg1&&>();
check_mapped_type<Arg2&&>();
}
template <class... Args1, class... Args2>
static void check(std::allocator<value_type>&, init_type*,
std::piecewise_construct_t, std::tuple<Args1...>&&,
std::tuple<Args2...>&&)
{
check_key_type<Args1&&...>();
check_mapped_type<Args2&&...>();
}
};
template <class TypePolicy> struct set_types_constructibility
{
using key_type = typename TypePolicy::key_type;
using value_type = typename TypePolicy::value_type;
static_assert(std::is_same<key_type, value_type>::value, "");
template <class A, class X, class... Args>
static void check(A&, X*, Args&&...)
{
// Pass through, as we cannot say anything about a general allocator
}
template <class... Args>
static void check(std::allocator<value_type>&, key_type*, Args&&...)
{
(void)check_key_type_t<key_type, Args&&...>{};
}
};
} // namespace foa
} // namespace detail
} // namespace unordered
} // namespace boost
#endif // BOOST_UNORDERED_DETAIL_FOA_TYPES_CONSTRUCTIBILITY_HPP