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