diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index db09234a..fcc34115 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -38,6 +38,8 @@ #include #include +#include + template struct X; #if defined(__SSE2__)||\ @@ -739,18 +741,18 @@ private: struct no_mix { template - static inline std::size_t mix(const Hash& h,const T& x) + static inline std::size_t mix(const Hash& h,T&& x) { - return h(x); + return h(std::forward(x)); } }; struct xmx_mix { template - static inline std::size_t mix(const Hash& h,const T& x) + static inline std::size_t mix(const Hash& h,T&& x) { - return xmx(h(x)); + return xmx(h(std::forward(x))); } }; @@ -807,12 +809,15 @@ class table; /* internal conversion from const_iterator to iterator */ class const_iterator_cast_tag {}; -template +template class table_iterator { + using type_policy=TypePolicy; + using table_element_type=typename type_policy::element_type; + public: using difference_type=std::ptrdiff_t; - using value_type=Value; + using value_type=typename type_policy::value_type; using pointer= typename std::conditional::type; using reference= @@ -823,14 +828,15 @@ public: table_iterator()=default; template::type* =nullptr> - table_iterator(const table_iterator& x): + table_iterator(const table_iterator& x): pc{x.pc},p{x.p}{} table_iterator( - const_iterator_cast_tag, const table_iterator& x): + const_iterator_cast_tag, const table_iterator& x): pc{x.pc},p{x.p}{} - inline reference operator*()const noexcept{return *p;} - inline pointer operator->()const noexcept{return p;} + inline reference operator*()const noexcept{return type_policy::value_from(*p);} + inline pointer operator->()const noexcept + {return std::addressof(type_policy::value_from(*p));} inline table_iterator& operator++()noexcept{increment();return *this;} inline table_iterator operator++(int)noexcept {auto x=*this;increment();return x;} @@ -845,9 +851,9 @@ private: template friend class table_iterator; template friend class table; - table_iterator(Group* pg,std::size_t n,const Value* p_): + table_iterator(Group* pg,std::size_t n,const table_element_type* p_): pc{reinterpret_cast(const_cast(pg))+n}, - p{const_cast(p_)} + p{const_cast(p_)} {} inline std::size_t rebase() noexcept @@ -881,8 +887,8 @@ private: } } - unsigned char *pc=nullptr; - Value *p=nullptr; + unsigned char *pc=nullptr; + table_element_type *p=nullptr; }; /* table_arrays controls allocation, initialization and deallocation of @@ -1182,7 +1188,7 @@ public: using key_type=typename type_policy::key_type; using init_type=typename type_policy::init_type; using value_type=typename type_policy::value_type; - using storage_type=typename type_policy::storage_type; + using element_type=typename type_policy::element_type; private: static constexpr bool has_mutable_iterator= @@ -1198,10 +1204,10 @@ public: using const_reference=const value_type&; using size_type=std::size_t; using difference_type=std::ptrdiff_t; - using const_iterator=table_iterator; + using const_iterator=table_iterator; using iterator=typename std::conditional< has_mutable_iterator, - table_iterator, + table_iterator, const_iterator>::type; table( @@ -1252,7 +1258,7 @@ public: /* This works because subsequent x.clear() does not depend on the * elements' values. */ - x.for_all_elements([this](storage_type* p){ + x.for_all_elements([this](element_type* p){ unchecked_insert(type_policy::move(*p)); }); } @@ -1260,7 +1266,7 @@ public: ~table()noexcept { - for_all_elements([this](storage_type* p){ + for_all_elements([this](element_type* p){ destroy_element(p); }); delete_arrays(arrays); @@ -1349,7 +1355,7 @@ public: /* This works because subsequent x.clear() does not depend on the * elements' values. */ - x.for_all_elements([this](storage_type* p){ + x.for_all_elements([this](element_type* p){ unchecked_insert(type_policy::move(*p)); }); } @@ -1496,7 +1502,7 @@ public: template void merge(table& x) { - x.for_all_elements([&,this](group_type* pg,unsigned int n,storage_type* p){ + x.for_all_elements([&,this](group_type* pg,unsigned int n,element_type* p){ if(emplace_impl(type_policy::move(*p)).second){ x.erase(iterator{pg,n,p}); } @@ -1559,7 +1565,7 @@ public: private: template friend class table; - using arrays_type=table_arrays; + using arrays_type=table_arrays; struct clear_on_exit { @@ -1585,14 +1591,15 @@ private: } template - void construct_element(storage_type* p,Args&&... args) + void construct_element(element_type* p,Args&&... args) { type_policy::construct(al(),p,std::forward(args)...); } template - void construct_element(storage_type* p,try_emplace_args_t,Args&&... args) + void construct_element(element_type* p,try_emplace_args_t,Args&&... args) { + std::cout << "so hopefully I'm seeing this..." << std::endl; construct_element_from_try_emplace_args( p, std::integral_constant::value>{}, @@ -1601,7 +1608,7 @@ private: template void construct_element_from_try_emplace_args( - storage_type* p,std::false_type,Key&& x,Args&&... args) + element_type* p,std::false_type,Key&& x,Args&&... args) { type_policy::construct( al(),p, @@ -1616,12 +1623,12 @@ private: template void construct_element_from_try_emplace_args( - storage_type* p,std::true_type,Key&& x) + element_type* p,std::true_type,Key&& x) { type_policy::construct(al(),p,std::forward(x)); } - void destroy_element(storage_type* p)noexcept + void destroy_element(element_type* p)noexcept { type_policy::destroy(al(),p); } @@ -1630,7 +1637,7 @@ private: { ~destroy_element_on_exit(){this_->destroy_element(p);} table *this_; - storage_type *p; + element_type *p; }; void copy_elements_from(const table& x) @@ -1641,7 +1648,7 @@ private: fast_copy_elements_from(x); } else{ - x.for_all_elements([this](const storage_type* p){ + x.for_all_elements([this](const element_type* p){ unchecked_insert(*p); }); } @@ -1692,14 +1699,14 @@ private: { std::size_t num_constructed=0; BOOST_TRY{ - x.for_all_elements([&,this](const storage_type* p){ + x.for_all_elements([&,this](const element_type* p){ construct_element(arrays.elements+(p-x.arrays.elements),*p); ++num_constructed; }); } BOOST_CATCH(...){ if(num_constructed){ - x.for_all_elements_while([&,this](const storage_type* p){ + x.for_all_elements_while([&,this](const element_type* p){ destroy_element(arrays.elements+(p-x.arrays.elements)); return --num_constructed!=0; }); @@ -1746,16 +1753,16 @@ private: } template - static inline const Key& key_from( - try_emplace_args_t,const Key& x,const Args&...) + static inline Key&& key_from( + try_emplace_args_t,Key&& x,const Args&...) { - return x; + return std::forward(x); } template - inline std::size_t hash_for(const Key& x)const + inline std::size_t hash_for(Key&& x)const { - return mix_policy::mix(h(),x); + return mix_policy::mix(h(),std::forward(x)); } inline std::size_t position_for(std::size_t hash)const @@ -1769,7 +1776,7 @@ private: return size_policy::position(hash,arrays_.groups_size_index); } - static inline void prefetch_elements(const storage_type* p) + static inline void prefetch_elements(const element_type* p) { /* We have experimentally confirmed that ARM architectures get a higher * speedup when around the first half of the element slots in a group are @@ -1833,12 +1840,13 @@ private: template BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { - const auto &k=key_from(std::forward(args)...); - auto hash=hash_for(k); - auto pos0=position_for(hash); - auto it=find_impl(k,pos0,hash); + auto &&k=key_from(std::forward(args)...); + auto hash=hash_for(std::forward(k)); + auto pos0=position_for(hash); + auto it=find_impl(k,pos0,hash); if(it!=end()){ + std::cout << "preventing duplicated insertion" << std::endl; return {it,false}; } if(BOOST_LIKELY(size_::value|| - std::is_same::value|| - !std::is_copy_constructible::value>{}); + std::is_same::value|| + !std::is_copy_constructible::value>{}); } void nosize_transfer_element( - storage_type* p,std::size_t hash,const arrays_type& arrays_, + element_type* p,std::size_t hash,const arrays_type& arrays_, std::size_t& num_destroyed,std::true_type /* ->move */) { /* Destroy p even if an an exception is thrown in the middle of move @@ -1990,12 +1998,12 @@ private: } void nosize_transfer_element( - storage_type* p,std::size_t hash,const arrays_type& arrays_, + element_type* p,std::size_t hash,const arrays_type& arrays_, std::size_t& /*num_destroyed*/,std::false_type /* ->copy */) { nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash, - const_cast(*p)); + const_cast(*p)); } template @@ -2032,7 +2040,7 @@ private: std::size_t erase_if_impl(Predicate pr) { std::size_t s=size(); - for_all_elements([&,this](group_type* pg,unsigned int n,storage_type* p){ + for_all_elements([&,this](group_type* pg,unsigned int n,element_type* p){ if(pr(*p)) erase(iterator{pg,n,p}); }); return std::size_t(s-size()); @@ -2048,7 +2056,7 @@ private: static auto for_all_elements(const arrays_type& arrays_,F f) ->decltype(f(nullptr),void()) { - for_all_elements_while(arrays_,[&](storage_type* p){f(p);return true;}); + for_all_elements_while(arrays_,[&](element_type* p){f(p);return true;}); } template @@ -2056,7 +2064,7 @@ private: ->decltype(f(nullptr,0,nullptr),void()) { for_all_elements_while( - arrays_,[&](group_type* pg,unsigned int n,storage_type* p) + arrays_,[&](group_type* pg,unsigned int n,element_type* p) {f(pg,n,p);return true;}); } @@ -2071,7 +2079,7 @@ private: ->decltype(f(nullptr),void()) { for_all_elements_while( - arrays_,[&](group_type*,unsigned int,storage_type* p){return f(p);}); + arrays_,[&](group_type*,unsigned int,element_type* p){return f(p);}); } template diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 2e43453d..7ceebc40 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -43,7 +43,9 @@ namespace boost { using moved_type = std::pair; using value_type = std::pair; - using storage_type = value_type; + using element_type = value_type; + + static value_type& value_from(element_type& x) { return x; } template static raw_key_type const& extract(std::pair const& kv) @@ -51,7 +53,7 @@ namespace boost { return kv.first; } - static moved_type move(storage_type& x) + static moved_type move(element_type& x) { // TODO: we probably need to launder here return {std::move(const_cast(x.first)), @@ -59,18 +61,18 @@ namespace boost { } template - static void construct(A& al, storage_type* p, moved_type&& x) + static void construct(A& al, element_type* p, moved_type&& x) { boost::allocator_construct(al, p, std::move(x)); } template - static void construct(A& al, storage_type* p, Args&&... args) + static void construct(A& al, element_type* p, Args&&... args) { boost::allocator_construct(al, p, std::forward(args)...); } - template static void destroy(A& al, storage_type* p) noexcept + template static void destroy(A& al, element_type* p) noexcept { boost::allocator_destroy(al, p); } diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 343a8675..3ee23ff7 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -37,24 +37,47 @@ namespace boost { using init_type = Key; using value_type = Key; - using storage_type = Key; + struct element_type + { + value_type p; + + element_type(element_type const& rhs) : p(rhs.p) {} + element_type(element_type&& rhs): p(std::move(rhs.p)) {} + + element_type(value_type&& p_) : p(std::move(p_)) {} + + template + element_type(Args&&... args) : p(std::forward(args)...) + { + } + }; + + static Key& value_from(element_type& x) { return x.p; } static Key const& extract(value_type const& key) { return key; } - static Key&& move(value_type& x) { return std::move(x); } + static Key const& extract(element_type const& x) { return x.p; } + static element_type&& move(element_type& x) { return std::move(x); } template - static void construct(A& al, storage_type* p, Key&& x) + static void construct(A& al, element_type* p, element_type const& copy) + { + std::cout << "Okay, I should be seeing this, I guess..." << std::endl; + boost::allocator_construct(al, p, copy); + } + + template + static void construct(A& al, element_type* p, Key&& x) { boost::allocator_construct(al, p, std::move(x)); } template - static void construct(A& al, storage_type* p, Args&&... args) + static void construct(A& al, element_type* p, Args&&... args) { boost::allocator_construct(al, p, std::forward(args)...); } - template static void destroy(A& al, storage_type* p) noexcept + template static void destroy(A& al, element_type* p) noexcept { boost::allocator_destroy(al, p); } @@ -261,6 +284,7 @@ namespace boost { std::pair >::type insert(K&& k) { + std::cout << "this should be my insert() overload" << std::endl; return table_.try_emplace(std::forward(k)); } diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 37af760d..61a2223a 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -16,7 +16,6 @@ #include #include -#include #include #include @@ -41,10 +40,14 @@ namespace boost { using raw_mapped_type = typename std::remove_const::type; using init_type = std::pair; - using moved_type = std::pair*; using value_type = std::pair; - using storage_type = value_type*; + struct element_type + { + value_type* p; + }; + + static value_type& value_from(element_type x) { return *(x.p); } template static raw_key_type const& extract(std::pair const& kv) @@ -52,58 +55,57 @@ namespace boost { return kv.first; } - template - static raw_key_type const& extract(std::pair const* kv) + static raw_key_type const& extract(element_type kv) { - return kv->first; + return kv.p->first; } - static storage_type&& move(storage_type& x) { return std::move(x); } + static element_type&& move(element_type& x) { return std::move(x); } template - static void construct(A&, storage_type* p, moved_type&& x) + static void construct(A&, element_type* p, element_type&& x) { - *p = x; - x = nullptr; + p->p = x.p; + x.p = nullptr; } template - static void construct(A& al, storage_type* p, storage_type const& copy) + static void construct(A& al, element_type* p, element_type const& copy) { - *p = boost::to_address(boost::allocator_allocate(al, 1)); + p->p = boost::to_address(boost::allocator_allocate(al, 1)); try { - boost::allocator_construct(al, *p, *copy); + boost::allocator_construct(al, p->p, *copy.p); } catch (...) { boost::allocator_deallocate(al, boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(**p), + typename boost::allocator_pointer::type>::pointer_to(*p->p), 1); throw; } } template - static void construct(A& al, storage_type* p, Args&&... args) + static void construct(A& al, element_type* p, Args&&... args) { - *p = boost::to_address(boost::allocator_allocate(al, 1)); + p->p = boost::to_address(boost::allocator_allocate(al, 1)); try { - boost::allocator_construct(al, *p, std::forward(args)...); + boost::allocator_construct(al, p->p, std::forward(args)...); } catch (...) { boost::allocator_deallocate(al, boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(**p), + typename boost::allocator_pointer::type>::pointer_to(*p->p), 1); throw; } } - template static void destroy(A& al, storage_type* p) noexcept + template static void destroy(A& al, element_type* p) noexcept { - if (*p) { - boost::allocator_destroy(al, *p); + if (p->p) { + boost::allocator_destroy(al, p->p); boost::allocator_deallocate(al, boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(**p), + typename boost::allocator_pointer::type>::pointer_to(*p->p), 1); } } @@ -142,9 +144,8 @@ namespace boost { using pointer = typename boost::allocator_pointer::type; using const_pointer = typename boost::allocator_const_pointer::type; - using iterator = boost::indirect_iterator; - using const_iterator = - boost::indirect_iterator; + using iterator = typename table_type::iterator; + using const_iterator = typename table_type::const_iterator; unordered_node_map() : unordered_node_map(0) {} @@ -338,24 +339,23 @@ namespace boost { template std::pair insert_or_assign(key_type const& key, M&& obj) { - auto iter_bool_pair = table_.try_emplace(key, std::forward(obj)); - if (iter_bool_pair.second) { - return iter_bool_pair; + auto ibp = table_.try_emplace(key, std::forward(obj)); + if (ibp.second) { + return ibp; } - (*(iter_bool_pair.first))->second = std::forward(obj); - return iter_bool_pair; + ibp.first->second = std::forward(obj); + return ibp; } template std::pair insert_or_assign(key_type&& key, M&& obj) { - auto iter_bool_pair = - table_.try_emplace(std::move(key), std::forward(obj)); - if (iter_bool_pair.second) { - return iter_bool_pair; + auto ibp = table_.try_emplace(std::move(key), std::forward(obj)); + if (ibp.second) { + return ibp; } - (*(iter_bool_pair.first))->second = std::forward(obj); - return iter_bool_pair; + ibp.first->second = std::forward(obj); + return ibp; } template @@ -489,12 +489,12 @@ namespace boost { BOOST_FORCEINLINE mapped_type& operator[](key_type const& key) { - return (*(table_.try_emplace(key).first))->second; + return table_.try_emplace(key).first->second; } BOOST_FORCEINLINE mapped_type& operator[](key_type&& key) { - return (*(table_.try_emplace(std::move(key)).first))->second; + return table_.try_emplace(std::move(key)).first->second; } BOOST_FORCEINLINE size_type count(key_type const& key) const diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index 685a2dd0..582c3360 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -39,57 +39,61 @@ namespace boost { using init_type = Key; using value_type = Key; - using storage_type = Key*; - using moved_type = storage_type; + struct element_type + { + value_type* p; + }; + + static value_type& value_from(element_type x) { return *x.p; } static Key const& extract(value_type const& key) { return key; } - static Key const& extract(storage_type k) { return *k; } - static storage_type&& move(storage_type& x) { return std::move(x); } + static Key const& extract(element_type k) { return *k.p; } + static element_type&& move(element_type& x) { return std::move(x); } template - static void construct(A&, storage_type* p, moved_type&& x) + static void construct(A&, element_type* p, element_type&& x) { - *p = x; - x = nullptr; + p->p = x.p; + x.p = nullptr; } - template - static void construct(A& al, storage_type* p, storage_type const& copy) + template + static void construct(A& al, element_type* p, element_type const& copy) { - *p = boost::to_address(boost::allocator_allocate(al, 1)); + p->p = boost::to_address(boost::allocator_allocate(al, 1)); try { - boost::allocator_construct(al, *p, *copy); + boost::allocator_construct(al, p->p, *copy.p); } catch (...) { boost::allocator_deallocate(al, boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(**p), + typename boost::allocator_pointer::type>::pointer_to(*p->p), 1); throw; } } template - static void construct(A& al, storage_type* p, Args&&... args) + static void construct(A& al, element_type* p, Args&&... args) { - *p = boost::to_address(boost::allocator_allocate(al, 1)); + p->p = boost::to_address(boost::allocator_allocate(al, 1)); try { - boost::allocator_construct(al, *p, std::forward(args)...); + boost::allocator_construct(al, p->p, std::forward(args)...); } catch (...) { boost::allocator_deallocate(al, boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(**p), + typename boost::allocator_pointer::type>::pointer_to(*p->p), 1); throw; } } - template static void destroy(A& al, storage_type* p) noexcept + template static void destroy(A& al, element_type* p) noexcept { - if (*p) { - boost::allocator_destroy(al, *p); + if (p->p) { + boost::allocator_destroy(al, p->p); boost::allocator_deallocate(al, boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(**p), + typename boost::allocator_pointer::type>::pointer_to(*p->p), 1); } } @@ -125,9 +129,8 @@ namespace boost { using pointer = typename boost::allocator_pointer::type; using const_pointer = typename boost::allocator_const_pointer::type; - using iterator = boost::indirect_iterator; - using const_iterator = - boost::indirect_iterator; + using iterator = typename table_type::iterator; + using const_iterator = typename table_type::const_iterator; unordered_node_set() : unordered_node_set(0) {}