mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-09 15:13:59 +00:00
Update foa to construct stack-locals with the user's Allocator during emplace()
This commit is contained in:
parent
0ff1fa0f6e
commit
86318c1e88
@ -1129,6 +1129,25 @@ _STL_RESTORE_DEPRECATED_WARNING
|
||||
*/
|
||||
constexpr static float const mlf = 0.875f;
|
||||
|
||||
template <class T>
|
||||
union storage
|
||||
{
|
||||
T t_;
|
||||
storage(){}
|
||||
~storage(){}
|
||||
};
|
||||
|
||||
template <class TypePolicy,class A,class T>
|
||||
struct drop_guard
|
||||
{
|
||||
using type_policy=TypePolicy;
|
||||
|
||||
A& a;
|
||||
T* p;
|
||||
~drop_guard(){type_policy::destroy(a,p);};
|
||||
};
|
||||
|
||||
|
||||
/* foa::table interface departs in a number of ways from that of C++ unordered
|
||||
* associative containers because it's not for end-user consumption
|
||||
* (boost::unordered_[flat|node]_[map|set]) wrappers complete it as
|
||||
@ -1418,18 +1437,35 @@ public:
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace(Args&&... args)
|
||||
{
|
||||
/* We dispatch based on whether or not the value_type is constructible from
|
||||
* an rvalue reference of the deduced emplace_type. We do this specifically
|
||||
* for the case of the node-based containers. To this end, we're able to
|
||||
* avoid allocating a node when a duplicate element is attempted to be
|
||||
* inserted. For immovable types, we instead dispatch to the routine that
|
||||
* unconditionally allocates via `type_policy::construct()`.
|
||||
*/
|
||||
return emplace_value(
|
||||
using emplace_type=typename std::conditional<
|
||||
std::is_constructible<init_type,Args...>::value,
|
||||
init_type,
|
||||
value_type
|
||||
>::type;
|
||||
|
||||
using insert_type=typename std::conditional<
|
||||
std::is_constructible<
|
||||
value_type,
|
||||
emplace_type<Args...>&&>{},
|
||||
std::forward<Args>(args)...);
|
||||
value_type,emplace_type>::value,
|
||||
emplace_type,element_type
|
||||
>::type;
|
||||
|
||||
using alloc_insert_type=typename std::conditional<
|
||||
std::is_constructible<
|
||||
value_type,emplace_type>::value,
|
||||
emplace_type,value_type
|
||||
>::type;
|
||||
|
||||
using alloc_type=
|
||||
typename boost::allocator_rebind<Allocator,alloc_insert_type>::type;
|
||||
|
||||
storage<insert_type> s;
|
||||
alloc_type alloc{al()};
|
||||
auto *p=std::addressof(s.t_);
|
||||
|
||||
type_policy::construct(alloc,p,std::forward<Args>(args)...);
|
||||
|
||||
drop_guard<type_policy,alloc_type,insert_type> guard{alloc,p};
|
||||
return emplace_impl(type_policy::move(*p));
|
||||
}
|
||||
|
||||
template<typename Key,typename... Args>
|
||||
@ -1614,15 +1650,6 @@ private:
|
||||
template<typename,typename,typename,typename> friend class table;
|
||||
using arrays_type=table_arrays<element_type,group_type,size_policy>;
|
||||
|
||||
template<typename... Args>
|
||||
using emplace_type = typename std::conditional<
|
||||
std::is_constructible<
|
||||
init_type,Args...
|
||||
>::value,
|
||||
init_type,
|
||||
value_type
|
||||
>::type;
|
||||
|
||||
struct clear_on_exit
|
||||
{
|
||||
~clear_on_exit(){x.clear();}
|
||||
@ -1904,29 +1931,6 @@ private:
|
||||
#pragma warning(pop) /* C4800 */
|
||||
#endif
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_value(
|
||||
std::true_type /* movable value_type */,Args&&... args
|
||||
) {
|
||||
using emplace_type_t = emplace_type<Args...>;
|
||||
return emplace_impl(emplace_type_t(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_value(
|
||||
std::false_type /* immovable value_type */,Args&&... args
|
||||
) {
|
||||
alignas(element_type)
|
||||
unsigned char buf[sizeof(element_type)];
|
||||
element_type* p = reinterpret_cast<element_type*>(buf);
|
||||
|
||||
type_policy::construct(al(),p,std::forward<Args>(args)...);
|
||||
destroy_element_on_exit d{this,p};
|
||||
(void)d;
|
||||
|
||||
return emplace_impl(type_policy::move(*p));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_impl(Args&&... args)
|
||||
{
|
||||
|
@ -105,6 +105,9 @@ struct node_handle_base
|
||||
|
||||
node_handle_base& operator=(node_handle_base&& nh)noexcept
|
||||
{
|
||||
element_type x;
|
||||
x.p=p_;
|
||||
|
||||
if(this!=&nh){
|
||||
if(empty()){
|
||||
if(nh.empty()){ /* empty(), nh.empty() */
|
||||
@ -115,7 +118,7 @@ struct node_handle_base
|
||||
}
|
||||
}else{
|
||||
if(nh.empty()){ /* !empty(), nh.empty() */
|
||||
type_policy::destroy(al(),p_);
|
||||
type_policy::destroy(al(),&x);
|
||||
reset();
|
||||
}else{ /* !empty(), !nh.empty() */
|
||||
bool const pocma=
|
||||
@ -124,7 +127,7 @@ struct node_handle_base
|
||||
|
||||
BOOST_ASSERT(pocma||al()==nh.al());
|
||||
|
||||
type_policy::destroy(al(),p_);
|
||||
type_policy::destroy(al(),&x);
|
||||
if(pocma){
|
||||
al()=std::move(nh.al());
|
||||
}
|
||||
@ -137,7 +140,7 @@ struct node_handle_base
|
||||
if(empty()){ /* empty(), nh.empty() */
|
||||
/* nothing to do */
|
||||
}else{ /* !empty(), !nh.empty() */
|
||||
type_policy::destroy(al(),p_);
|
||||
type_policy::destroy(al(),&x);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
@ -147,7 +150,9 @@ struct node_handle_base
|
||||
~node_handle_base()
|
||||
{
|
||||
if(!empty()){
|
||||
type_policy::destroy(al(),p_);
|
||||
element_type x;
|
||||
x.p=p_;
|
||||
type_policy::destroy(al(),&x);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,11 @@ namespace boost {
|
||||
return kv.first;
|
||||
}
|
||||
|
||||
static moved_type move(init_type& x)
|
||||
{
|
||||
return {std::get<0>(std::move(x)), std::get<1>(std::move(x))};
|
||||
}
|
||||
|
||||
static moved_type move(element_type& x)
|
||||
{
|
||||
// TODO: we probably need to launder here
|
||||
@ -61,11 +66,26 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
static void construct(A& al, init_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
using alloc_type =
|
||||
typename boost::allocator_rebind<A, value_type>::type;
|
||||
alloc_type alloc(al);
|
||||
std::allocator_traits<alloc_type>::construct(
|
||||
alloc, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, init_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
|
@ -77,6 +77,11 @@ namespace boost {
|
||||
}
|
||||
|
||||
static element_type&& move(element_type& x) { return std::move(x); }
|
||||
static moved_type move(init_type& x)
|
||||
{
|
||||
return {std::get<0>(std::move(x)), std::get<1>(std::move(x))};
|
||||
}
|
||||
|
||||
static moved_type move(value_type& x)
|
||||
{
|
||||
return {std::move(const_cast<raw_key_type&>(x.first)),
|
||||
@ -96,6 +101,18 @@ namespace boost {
|
||||
construct(al, p, *copy.p);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, init_type* p, 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)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
@ -106,10 +123,11 @@ namespace boost {
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
typename boost::allocator_pointer<A>::type>::pointer_to(*p->p),
|
||||
1);
|
||||
using pointer_type=typename boost::allocator_pointer<A>::type;
|
||||
using pointer_traits=boost::pointer_traits<pointer_type>;
|
||||
|
||||
boost::allocator_deallocate(
|
||||
al,pointer_traits::pointer_to(*(p->p)),1);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@ -118,16 +136,22 @@ namespace boost {
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
typename boost::allocator_pointer<A>::type>::pointer_to(*p),
|
||||
1);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, init_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
if (p->p) {
|
||||
destroy(al,p->p);
|
||||
using pointer_type=typename boost::allocator_pointer<A>::type;
|
||||
using pointer_traits=boost::pointer_traits<pointer_type>;
|
||||
|
||||
destroy(al, p->p);
|
||||
boost::allocator_deallocate(
|
||||
al,pointer_traits::pointer_to(*(p->p)), 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -137,8 +161,7 @@ namespace boost {
|
||||
: public detail::foa::node_handle_base<TypePolicy, Allocator>
|
||||
{
|
||||
private:
|
||||
using base_type =
|
||||
detail::foa::node_handle_base<TypePolicy, Allocator>;
|
||||
using base_type = detail::foa::node_handle_base<TypePolicy, Allocator>;
|
||||
|
||||
using typename base_type::type_policy;
|
||||
|
||||
|
@ -78,6 +78,12 @@ namespace boost {
|
||||
x.p = nullptr;
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, value_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
@ -100,16 +106,16 @@ namespace boost {
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
typename boost::allocator_pointer<A>::type>::pointer_to(*p),
|
||||
1);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
if (p->p) {
|
||||
destroy(al, p->p);
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<typename boost::allocator_pointer<
|
||||
A>::type>::pointer_to(*(p->p)),
|
||||
1);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -119,8 +125,7 @@ namespace boost {
|
||||
: public detail::foa::node_handle_base<TypePolicy, Allocator>
|
||||
{
|
||||
private:
|
||||
using base_type =
|
||||
detail::foa::node_handle_base<TypePolicy, Allocator>;
|
||||
using base_type = detail::foa::node_handle_base<TypePolicy, Allocator>;
|
||||
|
||||
using typename base_type::type_policy;
|
||||
|
||||
@ -391,7 +396,7 @@ namespace boost {
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
typename set_types::element_type x;
|
||||
x.p=std::addressof(nh.element());
|
||||
x.p = std::addressof(nh.element());
|
||||
|
||||
auto itp = table_.insert(std::move(x));
|
||||
if (itp.second) {
|
||||
@ -411,7 +416,7 @@ namespace boost {
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
typename set_types::element_type x;
|
||||
x.p=std::addressof(nh.element());
|
||||
x.p = std::addressof(nh.element());
|
||||
|
||||
auto itp = table_.insert(std::move(x));
|
||||
if (itp.second) {
|
||||
@ -478,7 +483,7 @@ namespace boost {
|
||||
node_type extract(key_type const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
return pos!=end()?extract(pos):node_type();
|
||||
return pos != end() ? extract(pos) : node_type();
|
||||
}
|
||||
|
||||
template <class K>
|
||||
@ -489,7 +494,7 @@ namespace boost {
|
||||
extract(K const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
return pos!=end()?extract(pos):node_type();
|
||||
return pos != end() ? extract(pos) : node_type();
|
||||
}
|
||||
|
||||
template <class H2, class P2>
|
||||
|
Loading…
x
Reference in New Issue
Block a user