Skip to content

Commit

Permalink
Merge pull request #269 from k3DW/191
Browse files Browse the repository at this point in the history
static_assert on the constructibility of the containers' types
  • Loading branch information
k3DW authored Aug 8, 2024
2 parents 65f3ea6 + a14b159 commit a39cf60
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 12 deletions.
12 changes: 10 additions & 2 deletions include/boost/unordered/detail/foa/flat_map_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#ifndef 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>

namespace boost {
Expand All @@ -25,6 +27,9 @@ namespace boost {

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; }

template <class K, class V>
Expand All @@ -48,18 +53,21 @@ namespace boost {
template <class A, class... 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)...);
}

template <class A, class... 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)...);
}

template <class A, class... 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)...);
}

Expand All @@ -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
10 changes: 8 additions & 2 deletions include/boost/unordered/detail/foa/flat_set_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#ifndef 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>

namespace boost {
Expand All @@ -21,13 +23,17 @@ namespace boost {

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 element_type&& move(element_type& x) { return std::move(x); }

template <class A, class... 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)...);
}

Expand All @@ -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
19 changes: 15 additions & 4 deletions include/boost/unordered/detail/foa/node_map_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP

#include <boost/unordered/detail/foa/element_type.hpp>
#include <boost/unordered/detail/foa/types_constructibility.hpp>
#include <boost/unordered/detail/type_traits.hpp>

#include <boost/core/allocator_access.hpp>
#include <boost/core/no_exceptions_support.hpp>
Expand All @@ -29,6 +31,9 @@ namespace boost {

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)
{
return *(x.p);
Expand Down Expand Up @@ -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 <class A, class... 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)...);
}

template <class A, class... 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)...);
}

template <class A, class... 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)...);
}

Expand All @@ -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>(args)...);
boost::allocator_construct(
al, boost::to_address(p->p), std::forward<Args>(args)...);
al, address, std::forward<Args>(args)...);
}
BOOST_CATCH(...)
{
Expand Down Expand Up @@ -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
17 changes: 13 additions & 4 deletions include/boost/unordered/detail/foa/node_set_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP

#include <boost/unordered/detail/foa/element_type.hpp>
#include <boost/unordered/detail/foa/types_constructibility.hpp>
#include <boost/unordered/detail/type_traits.hpp>

#include <boost/core/allocator_access.hpp>
#include <boost/core/no_exceptions_support.hpp>
Expand All @@ -26,6 +28,9 @@ namespace boost {

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 Key const& extract(element_type const& k) { return *k.p; }
static element_type&& move(element_type& x) { return std::move(x); }
Expand All @@ -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 <typename Allocator>
Expand All @@ -49,6 +54,7 @@ namespace boost {
template <class A, class... 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)...);
}

Expand All @@ -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>(args)...);
boost::allocator_construct(
al, boost::to_address(p->p), std::forward<Args>(args)...);
al, address, std::forward<Args>(args)...);
}
BOOST_CATCH(...)
{
Expand All @@ -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
172 changes: 172 additions & 0 deletions include/boost/unordered/detail/foa/types_constructibility.hpp
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit a39cf60

Please sign in to comment.