From 7d69d184738207f809c3e0e4a7a9c9d58e16479c Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 26 Sep 2022 10:12:05 -0700 Subject: [PATCH 001/279] Initial commit of foa.hpp --- include/boost/unordered/detail/foa.hpp | 994 +++++++++++++++++++++++++ 1 file changed, 994 insertions(+) create mode 100644 include/boost/unordered/detail/foa.hpp diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp new file mode 100644 index 00000000..ddf2baaa --- /dev/null +++ b/include/boost/unordered/detail/foa.hpp @@ -0,0 +1,994 @@ +/* Fast open-addressing hash table. + * + * Copyright 2022 Joaquin M Lopez Munoz. + * 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) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_DETAIL_FOA_HPP +#define BOOST_UNORDERED_DETAIL_FOA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__SSE2__)||\ + defined(_M_X64)||(defined(_M_IX86_FP)&&_M_IX86_FP>=2) +#define BOOST_UNORDERED_SSE2 +#include +#elif defined(__ARM_NEON) +#define BOOST_UNORDERED_NEON +#include +#endif + +#ifdef __has_builtin +#define BOOST_UNORDERED_HAS_BUILTIN(x) __has_builtin(x) +#else +#define BOOST_UNORDERED_HAS_BUILTIN(x) 0 +#endif + +#if !defined(NDEBUG) +#define BOOST_UNORDERED_ASSUME(cond) BOOST_ASSERT(cond) +#elif BOOST_UNORDERED_HAS_BUILTIN(__builtin_assume) +#define BOOST_UNORDERED_ASSUME(cond) __builtin_assume(cond) +#elif defined(__GNUC__) || BOOST_UNORDERED_HAS_BUILTIN(__builtin_unreachable) +#define BOOST_UNORDERED_ASSUME(cond) \ + do{ \ + if(!(cond))__builtin_unreachable(); \ + }while(0) +#elif defined(_MSC_VER) +#define BOOST_UNORDERED_ASSUME(cond) __assume(cond) +#else +#define BOOST_UNORDERED_ASSUME(cond) \ + do{ \ + static_cast(false&&(cond)); \ + }while(0) +#endif + +namespace boost{ +namespace unordered{ +namespace detail{ +namespace foa{ + +/* TODO: description */ + +#ifdef BOOST_UNORDERED_SSE2 + +struct group15 +{ + static constexpr int N=15; + + inline void set(std::size_t pos,std::size_t hash) + { + BOOST_ASSERT(pos(&m)[pos]; + } + + inline unsigned char at(std::size_t pos)const + { + return reinterpret_cast(&m)[pos]; + } + + inline unsigned char& overflow() + { + return at(N); + } + + inline unsigned char overflow()const + { + return at(N); + } + + __m128i m; +}; +#endif + +inline unsigned int unchecked_countr_zero(int x) +{ +#if defined(BOOST_MSVC) + unsigned long r; + _BitScanForward(&r,(unsigned long)x); + return (unsigned int)r; +#else + BOOST_UNORDERED_ASSUME(x); + return (unsigned int)boost::core::countr_zero((unsigned int)x); +#endif +} + +inline void prefetch(const void* p) +{ +#if defined(BOOST_GCC)||defined(BOOST_CLANG) + __builtin_prefetch((const char*)p); +#elif defined(BOOST_UNORDERED_SSE2) + _mm_prefetch((const char*)p,_MM_HINT_T0); +#endif +} + +struct pow2_size_policy +{ + static inline std::size_t size_index(std::size_t n) + { + // TODO: min size is 2, see if we can bring it down to 1 without loss + // of performance + + return sizeof(std::size_t)*CHAR_BIT- + (n<=2?1:((std::size_t)(boost::core::bit_width(n-1)))); + } + + static inline std::size_t size(std::size_t size_index) + { + return std::size_t(1)<<(sizeof(std::size_t)*CHAR_BIT-size_index); + } + + static inline std::size_t position(std::size_t hash,std::size_t size_index) + { + return hash>>size_index; + } +}; + +struct pow2_quadratic_prober +{ + pow2_quadratic_prober(std::size_t pos):pos{pos}{} + + inline std::size_t get()const{return pos;} + + inline bool next(std::size_t mask) + { + step+=1; + pos=(pos+step)&mask; + return step<=mask; + } + +private: + std::size_t pos,step=0; +}; + +template +class table; + +template +class table_iterator +{ +public: + using difference_type=std::ptrdiff_t; + using value_type=typename std::conditional::type; + using pointer=value_type*; + using reference=value_type&; + using iterator_category=std::forward_iterator_tag; + + table_iterator()=default; + template::type* =nullptr> + table_iterator(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 table_iterator& operator++()noexcept{increment();return *this;} + inline table_iterator operator++(int)noexcept + {auto x=*this;increment();return x;} + friend inline bool operator==( + const table_iterator& x,const table_iterator& y) + {return x.p==y.p;} + friend inline bool operator!=( + const table_iterator& x,const table_iterator& y) + {return !(x==y);} + +private: + template friend class table_iterator; + template friend class table; + + table_iterator(Group* pg,std::size_t n,const Value* p): + pc{reinterpret_cast(const_cast(pg))+n}, + p{const_cast(p)} + {} + + inline std::size_t rebase() noexcept + { + std::size_t off=reinterpret_cast(pc)%sizeof(Group); + pc-=off; + return off; + } + + inline void increment()noexcept + { + std::size_t n0=rebase(); + + int mask=(reinterpret_cast(pc)->match_occupied()>>(n0+1))<<(n0+1); + if(!mask){ + do{ + pc+=sizeof(Group); + p+=Group::N; + } + while(!(mask=reinterpret_cast(pc)->match_occupied())); + } + + auto n=unchecked_countr_zero(mask); + if(BOOST_UNLIKELY(reinterpret_cast(pc)->is_sentinel(n))){ + p=nullptr; + } + else{ + pc+=n; + p+=n-n0; + } + } + + unsigned char *pc=nullptr; + Value *p=nullptr; +}; + +template +class table +{ + using type_policy=TypePolicy; + using group_type=group15; + static constexpr auto N=group_type::N; + using size_policy=pow2_size_policy; + using prober=pow2_quadratic_prober; + +public: + using key_type=typename type_policy::key_type; + using value_type=typename type_policy::value_type; + +private: + static constexpr bool has_mutable_iterator= + !std::is_same::value; + +public: + using hasher=Hash; + using key_equal=Pred; + using allocator_type=Allocator; + using pointer=value_type*; + using const_pointer=const value_type*; + using reference=value_type&; + using const_reference=const value_type&; + using size_type=std::size_t; + using difference_type=std::ptrdiff_t; + using const_iterator=table_iterator; + using iterator=typename std::conditional< + has_mutable_iterator, + table_iterator, + const_iterator>::type; + + table( + std::size_t n=0,const Hash& h=Hash(),const Pred& pred=Pred(), + const Allocator& al=Allocator()): + h{h},pred{pred},al{al},size_{0},arrays{new_arrays(n)},ml{max_load()} + {} + + table(const table& x):table(x,x.al){} + + table(table&& x) + noexcept( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value): + // TODO verify if we should copy or move copy hash, pred and al + h{std::move(x.h)},pred{std::move(x.pred)},al{std::move(x.al)}, + size_{x.size_},arrays{x.arrays},ml{x.ml} + { + x.size_=0; + x.arrays=x.new_arrays(0); + x.ml=x.max_load(); + } + + table(const table& x,const Allocator& al): + h{x.h},pred{x.pred},al{al},size_{0}, + arrays{new_arrays(std::size_t(std::ceil(x.size()/mlf)))}, + ml{max_load()} + { + BOOST_TRY{ + x.for_all_elements([this](value_type* p){ + unchecked_insert(*p); + }); + } + BOOST_CATCH(...){ + clear(); + delete_arrays(arrays); + } + BOOST_CATCH_END + } + + table(table&& x,const Allocator& al): + table{0,std::move(x.h),std::move(x.pred),al} + { + if(al==x.al){ + size_=x.size_; + arrays=x.arrays; + ml=x.ml; + x.size_=0; + x.arrays=x.new_arrays(0); + x.ml=x.max_load(); + } + else{ + reserve(x.size()); + BOOST_TRY{ + /* This works because subsequent x.clear() does not depend on the + * elements' values. + */ + + x.for_all_elements([this](value_type* p){ + unchecked_insert(std::move(*p)); + }); + } + BOOST_CATCH(...){ + clear(); + delete_arrays(arrays); + x.clear(); + } + BOOST_CATCH_END + x.clear(); + } + } + + ~table()noexcept + { + clear(); + delete_arrays(arrays); + } + + table& operator=(const table& x) + { + if(this!=&x){ + clear(); + h=x.h; + pred=x.pred; + if(alloc_traits::propagate_on_container_copy_assignment::value){ + if(al!=x.al)reserve(0); + al=x.al; + } + // TODO may shrink arrays and miss an opportunity for memory reuse + reserve(x.size()); + x.for_all_elements([this](value_type* p){ + unchecked_insert(*p); + }); + } + return *this; + } + + table& operator=(table&& x) + noexcept( + alloc_traits::is_always_equal::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_assignable::value) + { + if(this!=&x){ + // TODO explain why not constexpr + auto pocma=alloc_traits::propagate_on_container_move_assignment::value; + clear(); + h=std::move(x.h); + pred=std::move(x.pred); + if(pocma||al==x.al){ + using std::swap; + reserve(0); + swap(arrays,x.arrays); + swap(ml,x.ml); + if(pocma)al=std::move(x.al); + } + else{ + reserve(x.size()); + BOOST_TRY{ + /* This works because subsequent x.clear() does not depend on the + * elements' values. + */ + + x.for_all_elements([this](value_type* p){ + unchecked_insert(std::move(*p)); + }); + } + BOOST_CATCH(...){ + x.clear(); + } + BOOST_CATCH_END + x.clear(); + } + } + return *this; + } + + allocator_type get_allocator()const noexcept{return al;} + + iterator begin()noexcept + { + iterator it{arrays.groups,0,arrays.elements}; + if(!(arrays.groups[0].match_occupied()&0x1))++it; + return it; + } + + const_iterator begin()const noexcept + {return const_cast(this)->begin();} + iterator end()noexcept{return {};} + const_iterator end()const noexcept{return const_cast(this)->end();} + const_iterator cbegin()const noexcept{return begin();} + const_iterator cend()const noexcept{return end();} + + bool empty()const noexcept{return size()!=0;} + std::size_t size()const noexcept{return size_;} + std::size_t max_size()const noexcept{return SIZE_MAX;} + + template + BOOST_FORCEINLINE std::pair emplace(Args&&... args) + { + return emplace_impl(value_type(std::forward(args)...)); + } + + template + BOOST_FORCEINLINE std::pair try_emplace( + Key&& k,Args&&... args) + { + return emplace_impl( + std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)); + } + + BOOST_FORCEINLINE std::pair insert(const value_type& x) + { + return emplace_impl(x); + } + + BOOST_FORCEINLINE std::pair insert(value_type&& x) + { + return emplace_impl(std::move(x)); + } + + template< + bool dependent_value=false, + typename std::enable_if< + has_mutable_iterator||dependent_value>::type* =nullptr + > + void erase(iterator pos)noexcept{return erase(const_iterator(pos));} + + void erase(const_iterator pos)noexcept + { + destroy_element(pos.p); + group_type::reset(pos.pc); + --size_; + } + + template + std::size_t erase(const Key& x) + { + auto it=find(x); + if(it!=end()){ + erase(it); + return 1; + } + else return 0; + } + + void swap(table& x) + noexcept( + alloc_traits::is_always_equal::value&& + boost::is_nothrow_swappable::value&& + boost::is_nothrow_swappable::value) + { + using std::swap; + swap(h,x.h); + swap(pred,x.pred); + if(alloc_traits::propagate_on_container_swap::value)swap(al,x.al); + else BOOST_ASSERT(al==x.al); + swap(size_,x.size_); + swap(arrays,x.arrays); + swap(ml,x.ml); + } + + void clear()noexcept + { + for_all_elements([this](value_type* p){destroy_element(p);}); + size_=0; + } + + hasher hash_function()const{return h;} + key_equal key_eq()const{return pred;} + + template + BOOST_FORCEINLINE iterator find(const Key& x) + { + auto hash=h(x); + return find_impl(x,position_for(hash),hash); + } + + template + BOOST_FORCEINLINE const_iterator find(const Key& x)const + { + return const_cast(this)->find(x); + } + + std::size_t capacity()const noexcept + { + return arrays.elements?(arrays.groups_size_mask+1)*N-1:0; + } + + float load_factor()const noexcept{return float(size())/capacity();} + float max_load_factor()const noexcept{return mlf;} + + void rehash(std::size_t n) + { + auto c1=std::size_t(std::ceil(float(size())/mlf)); + auto c2=n?size_policy::size(size_policy::size_index(n/N+1))*N-1:0; + auto c=c1>c2?c1:c2; /* we avoid std::max to not include */ + + if(c!=capacity())unchecked_rehash(c); + } + + void reserve(std::size_t n) + { + rehash(std::size_t(std::ceil(n/mlf))); + } + +private: + using alloc_traits=std::allocator_traits; + using group_allocator= + typename alloc_traits::template rebind_alloc; + using group_alloc_traits=std::allocator_traits; + + struct arrays_info{ + std::size_t groups_size_index; + std::size_t groups_size_mask; + group_type *groups; + value_type *elements; + }; + + arrays_info new_arrays(std::size_t n) + { + auto groups_size_index=size_policy::size_index(n/N+1); + auto groups_size=size_policy::size(groups_size_index); + arrays_info new_arrays_{ + groups_size_index, + groups_size-1, + nullptr, + nullptr + }; + if(!n){ + new_arrays_.groups=dummy_groups(); + } + else{ + group_allocator gal=al; + new_arrays_.groups=group_alloc_traits::allocate(gal,groups_size); + // TODO: explain why memset + std::memset( + new_arrays_.groups,0,sizeof(group_type)*groups_size-1); + new_arrays_.groups[groups_size-1].set_sentinel(); + BOOST_TRY{ + new_arrays_.elements=alloc_traits::allocate(al,groups_size*N-1); + } + BOOST_CATCH(...){ + group_alloc_traits::deallocate(gal,new_arrays_.groups,groups_size); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + return new_arrays_; + } + + static group_type* dummy_groups()noexcept + { +#if defined(BOOST_UNORDERED_SSE2) + static_assert( + std::is_same::value, + "encapsulation breach" + ); + alignas(group_type) static constexpr unsigned char + storage[sizeof(group_type)*2]={ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 + }; + + return reinterpret_cast(const_cast(storage)); + } +#else +#error encapsulation breach +#endif + + void delete_arrays(const arrays_info& arrays_)noexcept + { + if(arrays_.elements){ + auto groups_size=arrays_.groups_size_mask+1; + alloc_traits::deallocate(al,arrays_.elements,groups_size*N-1); + group_allocator gal=al; + group_alloc_traits::deallocate(gal,arrays_.groups,groups_size); + } + } + + template + void construct_element(value_type* p,Args&&... args) + { + alloc_traits::construct(al,p,std::forward(args)...); + } + + void destroy_element(value_type* p)noexcept + { + alloc_traits::destroy(al,p); + } + + std::size_t max_load()const + { + if(!arrays.elements){ + return 0; + } + else { + float fml=mlf*(float)(capacity()); + auto res=(std::numeric_limits::max)(); + if(res>fml)res=(std::size_t)fml; + return res; + } + } + + static inline auto key_from(const value_type& x) + ->decltype(type_policy::extract(x)) + { + return type_policy::extract(x); + } + + template + static inline const Key& key_from(const Key& x) + { + return x; + } + + template + static inline auto key_from( + std::piecewise_construct_t,const Arg1& k,const Arg2&) + ->decltype(std::get<0>(k)) + { + return std::get<0>(k); + } + + inline std::size_t position_for(std::size_t hash)const + { + return position_for(hash,arrays); + } + + static inline std::size_t position_for( + std::size_t hash,const arrays_info& arrays_) + { + return size_policy::position(hash,arrays_.groups_size_index); + } + + static inline void prefetch_elements(const value_type* p) + { +#if BOOST_ARCH_ARM + constexpr int cache_line=64; // TODO: get from Boost.Predef? + // TODO: check if this is 128 in current benchmark machine + const char *p0=reinterpret_cast(p), + *p1=p0+sizeof(value_type)*N/2; + for(auto p=p0;p + BOOST_FORCEINLINE iterator find_impl( + const Key& x,std::size_t pos0,std::size_t hash)const + { + prober pb(pos0); + do{ + auto pos=pb.get(); + auto pg=arrays.groups+pos; + auto mask=pg->match(hash); + if(mask){ + auto p=arrays.elements+pos*N; + prefetch_elements(p); + do{ + auto n=unchecked_countr_zero(mask); + if(BOOST_LIKELY(pred(x,key_from(p[n])))){ + return {pg,n,p+n}; + } + mask&=mask-1; + }while(mask); + } + if(BOOST_LIKELY(pg->is_not_overflowed(hash))){ + return {}; // TODO end() does not work (returns const_iterator) + } + } + while(BOOST_LIKELY(pb.next(arrays.groups_size_mask))); + return {}; // TODO end() does not work (returns const_iterator) + } + + template + BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) + { + const auto &k=key_from(std::forward(args)...); + auto hash=h(k); + auto pos0=position_for(hash); + auto it=find_impl(k,pos0,hash); + + if(it!=end()){ + return {it,false}; + } + else if(BOOST_UNLIKELY(size_>=ml)){ + unchecked_rehash(capacity()+1); // TODO wrong if mlf is allowed to change + pos0=position_for(hash); + } + return { + unchecked_emplace_at(pos0,hash,std::forward(args)...), + true + }; + } + + BOOST_NOINLINE void unchecked_rehash(std::size_t n) + { + auto new_arrays_=new_arrays(n); + std::size_t num_tx=0; + BOOST_TRY{ + for_all_elements([&,this](value_type* p){ + nosize_transfer_element(p,new_arrays_); + ++num_tx; + }); + } + BOOST_CATCH(...){ + size_-=num_tx; + if(num_tx){ + auto pg=arrays.groups; + for(std::size_t pos=0;;++pos,++pg){ + auto mask=pg->match_occupied(); + while(mask){ + auto n=unchecked_countr_zero(mask); + pg->reset(n); + if(!(--num_tx))goto continue_; + } + } + } + continue_: + for_all_elements(new_arrays_,[this](value_type* p){ + destroy_element(p); + }); + delete_arrays(new_arrays_); + BOOST_RETHROW; + } + BOOST_CATCH_END + delete_arrays(arrays); + arrays=new_arrays_; + ml=max_load(); + } + + template + void unchecked_insert(Value&& x) + { + auto hash=h(key_from(x)); + unchecked_emplace_at(position_for(hash),hash,std::forward(x)); + } + + void nosize_transfer_element(value_type* p,const arrays_info& arrays_) + { + auto hash=h(key_from(*p)); + nosize_unchecked_emplace_at( + arrays_,position_for(hash,arrays_),hash,std::move(*p)); + destroy_element(p); + } + + template + iterator unchecked_emplace_at( + std::size_t pos0,std::size_t hash,Args&&... args) + { + auto res=nosize_unchecked_emplace_at( + arrays,pos0,hash,std::forward(args)...); + ++size_; + return res; + } + +#if 0 + template + iterator nosize_unchecked_emplace_at( + const arrays_info& arrays_,std::size_t pos0,std::size_t hash, + Args&&... args) + { + auto p=insert_position(arrays_,pos0,hash); + auto &pos=p.first; + auto &n=p.second; + auto pg=arrays_.groups+pos; + auto p=arrays_.elements+pos*N+n; + construct_element(p,std::forward(args)...); + pg->set(n,hash); + return {pg,n,p}; + } + + std::pair + static insert_position( + const arrays_info& arrays_,std::size_t pos0,std::size_t hash) + { + for(prober pb(pos0);;pb.next(arrays_.groups_size_mask)){ + auto pos=pb.get(); + auto pg=arrays_.groups+pos; + auto mask=pg->match_available(); + if(BOOST_LIKELY(mask)){ + return {pos,unchecked_countr_zero(mask)}; + } + else pg->mark_overflow(hash); + } + } +#else + template + iterator nosize_unchecked_emplace_at( + const arrays_info& arrays_,std::size_t pos0,std::size_t hash, + Args&&... args) + { + for(prober pb(pos0);;pb.next(arrays_.groups_size_mask)){ + auto pos=pb.get(); + auto pg=arrays_.groups+pos; + auto mask=pg->match_available(); + if(BOOST_LIKELY(mask)){ + auto n=unchecked_countr_zero(mask); + auto p=arrays_.elements+pos*N+n; + construct_element(p,std::forward(args)...); + pg->set(n,hash); + return {pg,n,p}; + } + else pg->mark_overflow(hash); + } + } +#endif + + template + void for_all_elements(F f)const + { + for_all_elements(arrays,f); + } + + template + static void for_all_elements(const arrays_info& arrays_,F f) + { + auto pg=arrays_.groups; + auto p=arrays_.elements; + for(std::size_t pos=0,last=arrays_.groups_size_mask+1; + pos!=last;++pos,++pg,p+=N){ + auto mask=pg->match_really_occupied(); + while(mask){ + f(p+unchecked_countr_zero(mask)); + mask&=mask-1; + } + } + } + + Hash h; + Pred pred; + Allocator al; + static constexpr float mlf=0.875; + std::size_t size_; + arrays_info arrays; + std::size_t ml; +}; + +} /* namespace foa */ +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#undef BOOST_UNORDERED_ASSUME +#undef BOOST_UNORDERED_HAS_BUILTIN +#ifdef BOOST_UNORDERED_NEON +#undef BOOST_UNORDERED_NEON +#endif +#ifdef BOOST_UNORDERED_SSE2 +#undef BOOST_UNORDERED_SSE2 +#endif +#endif From ad352a6703e062650b7d9bb8fa7a8988ef02d6ef Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 26 Sep 2022 10:27:22 -0700 Subject: [PATCH 002/279] Fix cast warning in mark_overflow() --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index ddf2baaa..331ec82b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -118,7 +118,7 @@ struct group15 inline void mark_overflow(std::size_t hash) { - overflow()|=1<<(hash%8); + overflow()|=static_cast(1<<(hash%8)); } inline int match_available()const From 5d34b137a38377ad9d7632c0f893a8c75fbb48e9 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 26 Sep 2022 11:40:47 -0700 Subject: [PATCH 003/279] Fix shadowing warnings in foa.hpp --- include/boost/unordered/detail/foa.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 331ec82b..96456bcb 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -256,7 +256,7 @@ struct pow2_size_policy struct pow2_quadratic_prober { - pow2_quadratic_prober(std::size_t pos):pos{pos}{} + pow2_quadratic_prober(std::size_t _pos):pos{_pos}{} inline std::size_t get()const{return pos;} @@ -305,9 +305,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 Value* _p): pc{reinterpret_cast(const_cast(pg))+n}, - p{const_cast(p)} + p{const_cast(_p)} {} inline std::size_t rebase() noexcept @@ -378,9 +378,9 @@ public: const_iterator>::type; table( - std::size_t n=0,const Hash& h=Hash(),const Pred& pred=Pred(), - const Allocator& al=Allocator()): - h{h},pred{pred},al{al},size_{0},arrays{new_arrays(n)},ml{max_load()} + std::size_t n=0,const Hash& _h=Hash(),const Pred& _pred=Pred(), + const Allocator& _al=Allocator()): + h{_h},pred{_pred},al{_al},size_{0},arrays{new_arrays(n)},ml{max_load()} {} table(const table& x):table(x,x.al){} @@ -399,8 +399,8 @@ public: x.ml=x.max_load(); } - table(const table& x,const Allocator& al): - h{x.h},pred{x.pred},al{al},size_{0}, + table(const table& x,const Allocator& _al): + h{x.h},pred{x.pred},al{_al},size_{0}, arrays{new_arrays(std::size_t(std::ceil(x.size()/mlf)))}, ml{max_load()} { @@ -416,8 +416,8 @@ public: BOOST_CATCH_END } - table(table&& x,const Allocator& al): - table{0,std::move(x.h),std::move(x.pred),al} + table(table&& x,const Allocator& _al): + table{0,std::move(x.h),std::move(x.pred),_al} { if(al==x.al){ size_=x.size_; @@ -852,8 +852,8 @@ private: for(std::size_t pos=0;;++pos,++pg){ auto mask=pg->match_occupied(); while(mask){ - auto n=unchecked_countr_zero(mask); - pg->reset(n); + auto nz=unchecked_countr_zero(mask); + pg->reset(nz); if(!(--num_tx))goto continue_; } } From e8715ffb96dba87f1711e32b68e16ea84187023a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 26 Sep 2022 15:16:52 -0700 Subject: [PATCH 004/279] Update internal foa table implementation to use to_address when Allocators use fancy pointers --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 96456bcb..a62fd049 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -672,13 +672,13 @@ private: } else{ group_allocator gal=al; - new_arrays_.groups=group_alloc_traits::allocate(gal,groups_size); + new_arrays_.groups=boost::to_address(group_alloc_traits::allocate(gal,groups_size)); // TODO: explain why memset std::memset( new_arrays_.groups,0,sizeof(group_type)*groups_size-1); new_arrays_.groups[groups_size-1].set_sentinel(); BOOST_TRY{ - new_arrays_.elements=alloc_traits::allocate(al,groups_size*N-1); + new_arrays_.elements=boost::to_address(alloc_traits::allocate(al,groups_size*N-1)); } BOOST_CATCH(...){ group_alloc_traits::deallocate(gal,new_arrays_.groups,groups_size); From 12b9bd0a6def28c1ad69f6f1d5c0096d11ea26fb Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 26 Sep 2022 15:17:21 -0700 Subject: [PATCH 005/279] Fix warnings in internal foa table about float/size_t conversions --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index a62fd049..e869cbf0 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -627,7 +627,7 @@ public: return arrays.elements?(arrays.groups_size_mask+1)*N-1:0; } - float load_factor()const noexcept{return float(size())/capacity();} + float load_factor()const noexcept{return float(size())/float(capacity());} float max_load_factor()const noexcept{return mlf;} void rehash(std::size_t n) @@ -737,7 +737,7 @@ private: else { float fml=mlf*(float)(capacity()); auto res=(std::numeric_limits::max)(); - if(res>fml)res=(std::size_t)fml; + if(res>(std::size_t)fml)res=(std::size_t)fml; return res; } } From 505b06063786cbe17cc8822878adabb817f823a6 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 26 Sep 2022 15:17:54 -0700 Subject: [PATCH 006/279] Update insert_tests to handle new open-addressing table implementation --- test/Jamfile.v2 | 4 ++++ test/helpers/invariants.hpp | 4 ++++ test/unordered/insert_tests.cpp | 15 +++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 421dc4fe..e6b3ff91 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -5,6 +5,9 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) import testing ; +import ../../config/checks/config : requires ; + +CPP14 = [ requires cxx14 ] ; # Adding -Wundef is blocked on (at least) # https://github.com/boostorg/type_traits/issues/165 @@ -49,6 +52,7 @@ run unordered/copy_tests.cpp ; run unordered/move_tests.cpp ; run unordered/assign_tests.cpp ; run unordered/insert_tests.cpp ; +run unordered/insert_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; run unordered/insert_stable_tests.cpp ; run unordered/insert_hint_tests.cpp ; run unordered/emplace_tests.cpp ; diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index a555da60..3a4ddedf 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -58,6 +58,7 @@ namespace test { std::cerr << x1.count(key) << "," << count << "\n"; } +#ifndef BOOST_UNORDERED_FOA_TESTS // Check that the keys are in the correct bucket and are // adjacent in the bucket. typename X::size_type bucket = x1.bucket(key); @@ -86,6 +87,7 @@ namespace test { } } } +#endif }; // Check that size matches up. @@ -104,6 +106,7 @@ namespace test { if (fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64) BOOST_ERROR("x1.load_factor() doesn't match actual load_factor."); +#ifndef BOOST_UNORDERED_FOA_TESTS // Check that size in the buckets matches up. typename X::size_type bucket_size = 0; @@ -120,6 +123,7 @@ namespace test { BOOST_ERROR("x1.size() doesn't match bucket size."); std::cout << x1.size() << "/" << bucket_size << std::endl; } +#endif } } diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 7ddb41fd..471b8b2f 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -12,6 +12,10 @@ #include "../helpers/postfix.hpp" // clang-format on +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#endif + #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../helpers/random_values.hpp" @@ -884,13 +888,24 @@ namespace insert_tests { boost::unordered_multimap >* test_multimap; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered::unordered_flat_map >* test_flat_map; +#endif + using test::default_generator; using test::generate_collisions; using test::limited_range; +#ifdef BOOST_UNORDERED_FOA_TESTS + UNORDERED_TEST(unique_insert_tests1, + ((test_set_std_alloc)(test_set)(test_map)(test_flat_map))( + (default_generator)(generate_collisions)(limited_range))) +#else UNORDERED_TEST(unique_insert_tests1, ((test_set_std_alloc)(test_set)(test_map))( (default_generator)(generate_collisions)(limited_range))) +#endif UNORDERED_TEST(equivalent_insert_tests1, ((test_multimap_std_alloc)(test_multiset)(test_multimap))( From ba5cbd5ca60c30a8185f849e58ae38e40ee07d03 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 26 Sep 2022 15:18:13 -0700 Subject: [PATCH 007/279] Add simple initial draft of unordered_flat_map --- .../boost/unordered/unordered_flat_map.hpp | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 include/boost/unordered/unordered_flat_map.hpp diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp new file mode 100644 index 00000000..fddadd4a --- /dev/null +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -0,0 +1,90 @@ +#ifndef BOOST_UNORDERED_UNORDERED_FLAT_MAP_HPP_INCLUDED +#define BOOST_UNORDERED_UNORDERED_FLAT_MAP_HPP_INCLUDED + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#include + +#include + +namespace boost { + namespace unordered { + template + class unordered_flat_map + { + struct map_types + { + using key_type = Key; + using value_type = std::pair; + static Key const& extract(value_type const& kv) { return kv.first; } + }; + + using table_type = detail::foa::table::type>; + + table_type table_; + + public: + using key_type = Key; + using mapped_type = T; + using value_type = typename map_types::value_type; + using size_type = std::size_t; + using key_equal = KeyEqual; + using iterator = typename table_type::iterator; + using const_iterator = typename table_type::const_iterator; + + iterator begin() noexcept { return table_.begin(); } + const_iterator begin() const noexcept { return table_.begin(); } + const_iterator cbegin() const noexcept { return table_.cbegin(); } + + iterator end() noexcept { return table_.end(); } + const_iterator end() const noexcept { return table_.end(); } + const_iterator cend() const noexcept { return table_.cend(); } + + size_type size() const noexcept { return table_.size(); } + + std::pair insert(value_type const& value) + { + return table_.insert(value); + } + + size_type count(key_type const& key) const + { + auto pos = table_.find(key); + return pos != table_.end() ? 1 : 0; + } + + std::pair equal_range(key_type const& key) + { + auto pos = table_.find(key); + return {pos, pos == table_.end() ? pos : ++pos}; + } + + std::pair equal_range( + key_type const& key) const + { + auto pos = table_.find(key); + return {pos, pos == table_.end() ? pos : ++pos}; + } + + size_type bucket_count() const noexcept { return table_.capacity(); } + + float load_factor() const noexcept { return table_.load_factor(); } + + float max_load_factor() const noexcept + { + return table_.max_load_factor(); + } + + key_equal key_eq() const { return table_.key_eq(); } + }; + } // namespace unordered +} // namespace boost + +#endif From fc0f354df4123e34adb3d45ea61e6049ddb04f57 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 08:19:01 -0700 Subject: [PATCH 008/279] Switch from leading underscore to trailing underscore for shadowed variables --- include/boost/unordered/detail/foa.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index e869cbf0..f8dbb0a4 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -256,7 +256,7 @@ struct pow2_size_policy struct pow2_quadratic_prober { - pow2_quadratic_prober(std::size_t _pos):pos{_pos}{} + pow2_quadratic_prober(std::size_t pos_):pos{pos_}{} inline std::size_t get()const{return pos;} @@ -305,9 +305,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 Value* p_): pc{reinterpret_cast(const_cast(pg))+n}, - p{const_cast(_p)} + p{const_cast(p_)} {} inline std::size_t rebase() noexcept @@ -378,9 +378,9 @@ public: const_iterator>::type; table( - std::size_t n=0,const Hash& _h=Hash(),const Pred& _pred=Pred(), - const Allocator& _al=Allocator()): - h{_h},pred{_pred},al{_al},size_{0},arrays{new_arrays(n)},ml{max_load()} + std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(), + const Allocator& al_=Allocator()): + h{h_},pred{pred_},al{al_},size_{0},arrays{new_arrays(n)},ml{max_load()} {} table(const table& x):table(x,x.al){} @@ -399,8 +399,8 @@ public: x.ml=x.max_load(); } - table(const table& x,const Allocator& _al): - h{x.h},pred{x.pred},al{_al},size_{0}, + table(const table& x,const Allocator& al_): + h{x.h},pred{x.pred},al{al_},size_{0}, arrays{new_arrays(std::size_t(std::ceil(x.size()/mlf)))}, ml{max_load()} { @@ -416,8 +416,8 @@ public: BOOST_CATCH_END } - table(table&& x,const Allocator& _al): - table{0,std::move(x.h),std::move(x.pred),_al} + table(table&& x,const Allocator& al_): + table{0,std::move(x.h),std::move(x.pred),al_} { if(al==x.al){ size_=x.size_; From e1156348126a1e996a7a276e76372e5d5ec9e5f1 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 10:27:41 -0700 Subject: [PATCH 009/279] Fix bug in equal_range() for unordered_flat_map --- include/boost/unordered/unordered_flat_map.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index fddadd4a..f8ec0d20 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -63,14 +63,26 @@ namespace boost { std::pair equal_range(key_type const& key) { auto pos = table_.find(key); - return {pos, pos == table_.end() ? pos : ++pos}; + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; } std::pair equal_range( key_type const& key) const { auto pos = table_.find(key); - return {pos, pos == table_.end() ? pos : ++pos}; + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; } size_type bucket_count() const noexcept { return table_.capacity(); } From 3da4b6411c2750336587e0c7ecbcea2b8b3ff6df Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 10:28:10 -0700 Subject: [PATCH 010/279] Add rvalue overload of insert() for flat_map --- include/boost/unordered/unordered_flat_map.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index f8ec0d20..13d08395 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -49,11 +49,19 @@ namespace boost { size_type size() const noexcept { return table_.size(); } + /// Modifiers + /// + std::pair insert(value_type const& value) { return table_.insert(value); } + std::pair insert(value_type&& value) + { + return table_.insert(std::move(value)); + } + size_type count(key_type const& key) const { auto pos = table_.find(key); From b64b88eb654a9a147a75491724b46d1591d3ad80 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 10:28:50 -0700 Subject: [PATCH 011/279] Add intial erase() impl for benchmarks --- include/boost/unordered/unordered_flat_map.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 13d08395..37344c50 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -68,6 +68,10 @@ namespace boost { return pos != table_.end() ? 1 : 0; } + void erase(iterator pos) { table_.erase(pos); } + void erase(const_iterator pos) { return table_.erase(pos); } + size_type erase(key_type const& key) { return table_.erase(key); } + std::pair equal_range(key_type const& key) { auto pos = table_.find(key); From 2eb57995ddba70190db8da487acde0650f51b1c8 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 10:30:14 -0700 Subject: [PATCH 012/279] Add initial find() impl for benchmarks --- include/boost/unordered/unordered_flat_map.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 37344c50..9229f381 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -72,6 +72,16 @@ namespace boost { void erase(const_iterator pos) { return table_.erase(pos); } size_type erase(key_type const& key) { return table_.erase(key); } + /// Lookup + /// + + iterator find(key_type const& key) { return table_.find(key); } + + const_iterator find(key_type const& key) const + { + return table_.find(key); + } + std::pair equal_range(key_type const& key) { auto pos = table_.find(key); From 8905157c1e45e7e7d7e31ebe8488ecc53c6378bc Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 10:30:39 -0700 Subject: [PATCH 013/279] Update uint64 benchmarks to profile the new container, its internal table and the rc15 release candidate --- benchmark/uint64.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/benchmark/uint64.cpp b/benchmark/uint64.cpp index a2c1b3a3..4abc4a3e 100644 --- a/benchmark/uint64.cpp +++ b/benchmark/uint64.cpp @@ -5,12 +5,14 @@ #define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING #include +#include #include #include #include #include #include #include +#include #ifdef HAVE_ABSEIL # include "absl/container/node_hash_map.h" # include "absl/container/flat_hash_map.h" @@ -311,6 +313,29 @@ template using std_unordered_map = template using boost_unordered_map = boost::unordered_map, std::equal_to, allocator_for>; +template struct map_types +{ + using key_type = Key; + using value_type = std::pair; + static auto& extract(const value_type& x) { return x.first; } +}; + +template +using boost_unordered_detail_foa_table = + boost::unordered::detail::foa::table, + absl::container_internal::hash_default_hash, std::equal_to, + allocator_for >; + +template +using boost_unordered_flat_map = boost::unordered::unordered_flat_map, std::equal_to, + allocator_for >; + +template +using rc15_flat_map = foa_unordered_rc_map, std::equal_to, + allocator_for >; + #ifdef HAVE_ABSEIL template using absl_node_hash_map = @@ -347,6 +372,9 @@ int main() test( "std::unordered_map" ); test( "boost::unordered_map" ); + test( "boost_unordered_detail_foa_table" ); + test( "boost::unordered_flat_map" ); + test( "rc15_flat_map" ); test( "multi_index_map" ); #ifdef HAVE_ABSEIL @@ -374,7 +402,7 @@ int main() for( auto const& x: times ) { - std::cout << std::setw( 25 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n"; + std::cout << std::setw( 34 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n"; } } From 892e437428c845252852a7f165a8e12ae789efbe Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 10:34:04 -0700 Subject: [PATCH 014/279] Restructure insert_tests invocations --- test/unordered/insert_tests.cpp | 37 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 471b8b2f..b2eaa391 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -874,6 +874,17 @@ namespace insert_tests { test::check_equivalent_keys(x); } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifndef BOOST_UNORDERED_FOA_TESTS + boost::unordered::unordered_flat_map >* test_flat_map; + + UNORDERED_TEST(unique_insert_tests1, + ((test_flat_map))((default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_set >* test_set_std_alloc; boost::unordered_multimap >* test_multimap; -#ifdef BOOST_UNORDERED_FOA_TESTS - boost::unordered::unordered_flat_map >* test_flat_map; -#endif - - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - -#ifdef BOOST_UNORDERED_FOA_TESTS - UNORDERED_TEST(unique_insert_tests1, - ((test_set_std_alloc)(test_set)(test_map)(test_flat_map))( - (default_generator)(generate_collisions)(limited_range))) -#else UNORDERED_TEST(unique_insert_tests1, ((test_set_std_alloc)(test_set)(test_map))( (default_generator)(generate_collisions)(limited_range))) -#endif UNORDERED_TEST(equivalent_insert_tests1, ((test_multimap_std_alloc)(test_multiset)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) UNORDERED_TEST(insert_tests2, - ((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)( - test_multimap))((default_generator)(generate_collisions)(limited_range))) + ((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) UNORDERED_TEST(unique_emplace_tests1, ((test_set_std_alloc)(test_set)(test_map))( @@ -924,13 +920,11 @@ namespace insert_tests { (default_generator)(generate_collisions)(limited_range))) UNORDERED_TEST(move_emplace_tests, - ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)( - test_multiset)(test_multimap))( + ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)(test_multiset)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) UNORDERED_TEST(default_emplace_tests, - ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)( - test_multiset)(test_multimap))( + ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)(test_multiset)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) UNORDERED_TEST(map_tests, @@ -946,6 +940,7 @@ namespace insert_tests { UNORDERED_TEST(map_insert_range_test2, ((test_multimap_std_alloc)(test_map)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) +#endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) From 450c915284b3a25036dea6e857eb36b9753bf0b3 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 27 Sep 2022 14:25:57 -0700 Subject: [PATCH 015/279] Get insert_tests passing under sanitizers --- include/boost/unordered/detail/foa.hpp | 3 ++- test/unordered/insert_tests.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f8dbb0a4..906accb1 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -336,7 +336,7 @@ private: } else{ pc+=n; - p+=n-n0; + p+=static_cast(n)-static_cast(n0); } } @@ -959,6 +959,7 @@ private: { auto pg=arrays_.groups; auto p=arrays_.elements; + if(!p){return;} for(std::size_t pos=0,last=arrays_.groups_size_mask+1; pos!=last;++pos,++pg,p+=N){ auto mask=pg->match_really_occupied(); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index b2eaa391..acf7cf9e 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -878,7 +878,7 @@ namespace insert_tests { using test::generate_collisions; using test::limited_range; -#ifndef BOOST_UNORDERED_FOA_TESTS +#ifdef BOOST_UNORDERED_FOA_TESTS boost::unordered::unordered_flat_map >* test_flat_map; From 701cdff982858fa1db48b4c9b3b57a43ca2af857 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 09:36:52 +0200 Subject: [PATCH 016/279] refactored dummy_groups --- include/boost/unordered/detail/foa.hpp | 28 +++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 906accb1..bca20d8a 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -15,13 +15,14 @@ #include #include #include +#include #include #include #include -#include -#include #include #include +#include +#include #include #include #include @@ -137,6 +138,9 @@ struct group15 return at(N-1)==sentinel_?match_occupied()&0x3FFF:match_occupied(); } + static constexpr struct{alignas(16) unsigned char storage[N+1];} dummy_group= + {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}}; + private: static constexpr unsigned char available_=0, sentinel_=1; @@ -691,22 +695,14 @@ private: static group_type* dummy_groups()noexcept { -#if defined(BOOST_UNORDERED_SSE2) - static_assert( - std::is_same::value, - "encapsulation breach" - ); - alignas(group_type) static constexpr unsigned char - storage[sizeof(group_type)*2]={ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 - }; + using dummy_group_layout= + typename std::remove_const::type; - return reinterpret_cast(const_cast(storage)); + static constexpr dummy_group_layout + storage[2]={group_type::dummy_group,group_type::dummy_group}; + + return reinterpret_cast(const_cast(storage)); } -#else -#error encapsulation breach -#endif void delete_arrays(const arrays_info& arrays_)noexcept { From f4940d9344566ee4db4d3ca0adc367fa1f3427e2 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 09:40:05 +0200 Subject: [PATCH 017/279] avoided ugly casts in table_iterator::increment --- include/boost/unordered/detail/foa.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index bca20d8a..6bcc2b45 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -340,7 +340,8 @@ private: } else{ pc+=n; - p+=static_cast(n)-static_cast(n0); + p-=n0; + p+=n; } } @@ -701,7 +702,8 @@ private: static constexpr dummy_group_layout storage[2]={group_type::dummy_group,group_type::dummy_group}; - return reinterpret_cast(const_cast(storage)); + return reinterpret_cast( + const_cast(storage)); } void delete_arrays(const arrays_info& arrays_)noexcept From 43f8e5e9334da7b488b706ff44eaf36a54650a98 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 09:42:37 +0200 Subject: [PATCH 018/279] avoided being too smart in new_arrays's memory initialization --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 6bcc2b45..2970b594 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -680,7 +680,7 @@ private: new_arrays_.groups=boost::to_address(group_alloc_traits::allocate(gal,groups_size)); // TODO: explain why memset std::memset( - new_arrays_.groups,0,sizeof(group_type)*groups_size-1); + new_arrays_.groups,0,sizeof(group_type)*groups_size); new_arrays_.groups[groups_size-1].set_sentinel(); BOOST_TRY{ new_arrays_.elements=boost::to_address(alloc_traits::allocate(al,groups_size*N-1)); From 7a1a25991f463d657f9e5e44eba539040c2193c7 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 09:45:55 +0200 Subject: [PATCH 019/279] removed unnecessary check in max_load --- include/boost/unordered/detail/foa.hpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2970b594..4e635550 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -729,15 +729,10 @@ private: std::size_t max_load()const { - if(!arrays.elements){ - return 0; - } - else { - float fml=mlf*(float)(capacity()); - auto res=(std::numeric_limits::max)(); - if(res>(std::size_t)fml)res=(std::size_t)fml; - return res; - } + float fml=mlf*(float)(capacity()); + auto res=(std::numeric_limits::max)(); + if(res>(std::size_t)fml)res=(std::size_t)fml; + return res; } static inline auto key_from(const value_type& x) From 2889aab2269a35b42b3cbf1d0de07833d23a98fd Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 09:54:44 +0200 Subject: [PATCH 020/279] made dependency on size_policy minimum size explicit --- include/boost/unordered/detail/foa.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 4e635550..af100659 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -252,6 +252,8 @@ struct pow2_size_policy return std::size_t(1)<<(sizeof(std::size_t)*CHAR_BIT-size_index); } + static constexpr std::size_t min_size(){return 2;} + static inline std::size_t position(std::size_t hash,std::size_t size_index) { return hash>>size_index; @@ -699,8 +701,8 @@ private: using dummy_group_layout= typename std::remove_const::type; - static constexpr dummy_group_layout - storage[2]={group_type::dummy_group,group_type::dummy_group}; + static constexpr dummy_group_layout storage[size_policy::min_size()]= + {group_type::dummy_group,group_type::dummy_group}; return reinterpret_cast( const_cast(storage)); From 5293b328b7d03ad99b0869d3403ca9efe86c1d9a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 10:05:45 +0200 Subject: [PATCH 021/279] made emplace_impl rehashing more robust --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index af100659..282e9dc2 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -821,7 +821,7 @@ private: return {it,false}; } else if(BOOST_UNLIKELY(size_>=ml)){ - unchecked_rehash(capacity()+1); // TODO wrong if mlf is allowed to change + unchecked_rehash(std::size_t(std::ceil((size_+1)/mlf))); pos0=position_for(hash); } return { From 5a4a2f3ffd21edfdc14baf3ac83ba3a7efa7da7f Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 11:21:44 +0200 Subject: [PATCH 022/279] added Neon support --- include/boost/unordered/detail/foa.hpp | 148 ++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 282e9dc2..878a2073 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -34,8 +34,8 @@ defined(_M_X64)||(defined(_M_IX86_FP)&&_M_IX86_FP>=2) #define BOOST_UNORDERED_SSE2 #include -#elif defined(__ARM_NEON) -#define BOOST_UNORDERED_NEON +#elif defined(__ARM_NEON)&&!defined(__ARM_BIG_ENDIAN) +#define BOOST_UNORDERED_LITTLE_ENDIAN_NEON #include #endif @@ -213,6 +213,146 @@ private: __m128i m; }; + +#elif BOOST_UNORDERED_LITTLE_ENDIAN_NEON + +struct group15 +{ + static constexpr int N=15; + + inline void set(std::size_t pos,std::size_t hash) + { + BOOST_ASSERT(pos(1<<(hash%8)); + } + + inline int match_available()const + { + return simde_mm_movemask_epi8(vceqq_s8(m,vdupq_n_s8(0)))&0x7FFF; + } + + inline int match_occupied()const + { + return simde_mm_movemask_epi8( + vcgtq_u8(vreinterpretq_u8_s8(m),vdupq_n_u8(0)))&0x7FFF; + } + + inline int match_really_occupied()const /* excluding sentinel */ + { + return at(N-1)==sentinel_?match_occupied()&0x3FFF:match_occupied(); + } + + static constexpr struct{alignas(16) unsigned char storage[N+1];} dummy_group= + {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}}; + +private: + static constexpr unsigned char available_=0, + sentinel_=1; + + inline static unsigned char adjust_hash(unsigned char hash) + { + static constexpr unsigned char table[]={ + 2,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, + }; + + return table[hash]; + } + + /* copied from https://github.com/simd-everywhere/simde/blob/master/simde/x86/sse2.h#L3763 */ + + static inline int simde_mm_movemask_epi8(uint8x16_t a) + { + static const uint8_t md[16]={ + 1 << 0, 1 << 1, 1 << 2, 1 << 3, + 1 << 4, 1 << 5, 1 << 6, 1 << 7, + 1 << 0, 1 << 1, 1 << 2, 1 << 3, + 1 << 4, 1 << 5, 1 << 6, 1 << 7, + }; + + uint8x16_t masked=vandq_u8(vld1q_u8(md),a); + uint8x8x2_t tmp=vzip_u8(vget_low_u8(masked),vget_high_u8(masked)); + uint16x8_t x=vreinterpretq_u16_u8(vcombine_u8(tmp.val[0],tmp.val[1])); + return vaddvq_u16(x); + } + + inline unsigned char& at(std::size_t pos) + { + return reinterpret_cast(&m)[pos]; + } + + inline unsigned char at(std::size_t pos)const + { + return reinterpret_cast(&m)[pos]; + } + + inline unsigned char& overflow() + { + return at(N); + } + + inline unsigned char overflow()const + { + return at(N); + } + + int8x16_t m; +}; + #endif inline unsigned int unchecked_countr_zero(int x) @@ -981,8 +1121,8 @@ private: #undef BOOST_UNORDERED_ASSUME #undef BOOST_UNORDERED_HAS_BUILTIN -#ifdef BOOST_UNORDERED_NEON -#undef BOOST_UNORDERED_NEON +#ifdef BOOST_UNORDERED_LITTLE_ENDIAN_NEON +#undef BOOST_UNORDERED_LITTLE_ENDIAN_NEON #endif #ifdef BOOST_UNORDERED_SSE2 #undef BOOST_UNORDERED_SSE2 From 0ea2cb5a7a9b17c755ba85b6915a7a2de20efbe0 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 11:47:23 +0200 Subject: [PATCH 023/279] refactored dummy_groups to avoid explicit array initialization --- include/boost/unordered/detail/foa.hpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 878a2073..41ca6089 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -76,6 +76,11 @@ struct group15 { static constexpr int N=15; + struct dummy_group_type + { + alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; + }; + inline void set(std::size_t pos,std::size_t hash) { BOOST_ASSERT(pos::type; - - static constexpr dummy_group_layout storage[size_policy::min_size()]= - {group_type::dummy_group,group_type::dummy_group}; - + static constexpr group_type::dummy_group_type storage[size_policy::min_size()]; return reinterpret_cast( - const_cast(storage)); + const_cast(storage)); } void delete_arrays(const arrays_info& arrays_)noexcept From 8dcd40c8f36fd4d9ed9dce2d49f8593a38c54bb3 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 13:46:25 +0200 Subject: [PATCH 024/279] harmonized adjust_hash interface --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 41ca6089..5f4e4fc0 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -293,7 +293,7 @@ private: static constexpr unsigned char available_=0, sentinel_=1; - inline static unsigned char adjust_hash(unsigned char hash) + inline static unsigned char adjust_hash(std::size_t hash) { static constexpr unsigned char table[]={ 2,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15, @@ -314,7 +314,7 @@ private: 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, }; - return table[hash]; + return table[(unsigned char)hash]; } /* copied from https://github.com/simd-everywhere/simde/blob/master/simde/x86/sse2.h#L3763 */ From c487f246116a7409300318b9af8c55173bca2cf1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 13:55:44 +0200 Subject: [PATCH 025/279] honored select_on_container_copy_construction --- include/boost/unordered/detail/foa.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 5f4e4fc0..0ace17c4 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -534,7 +534,8 @@ public: h{h_},pred{pred_},al{al_},size_{0},arrays{new_arrays(n)},ml{max_load()} {} - table(const table& x):table(x,x.al){} + table(const table& x): + table(x,alloc_traits::select_on_container_copy_construction(x.al)){} table(table&& x) noexcept( From c61222403e2b1f6d0db5582879e93484c66d2da1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 17:24:44 +0200 Subject: [PATCH 026/279] fixed using placement --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 0ace17c4..17f738dd 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -503,6 +503,7 @@ class table static constexpr auto N=group_type::N; using size_policy=pow2_size_policy; using prober=pow2_quadratic_prober; + using alloc_traits=std::allocator_traits; public: using key_type=typename type_policy::key_type; @@ -797,7 +798,6 @@ public: } private: - using alloc_traits=std::allocator_traits; using group_allocator= typename alloc_traits::template rebind_alloc; using group_alloc_traits=std::allocator_traits; From f6544f69caf945f302e345546d86992d1ad8ba10 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 17:26:12 +0200 Subject: [PATCH 027/279] fixed macro usage --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 17f738dd..26123e37 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -70,7 +70,7 @@ namespace foa{ /* TODO: description */ -#ifdef BOOST_UNORDERED_SSE2 +#if defined(BOOST_UNORDERED_SSE2) struct group15 { @@ -216,7 +216,7 @@ private: __m128i m; }; -#elif BOOST_UNORDERED_LITTLE_ENDIAN_NEON +#elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) struct group15 { From 2e776ad155538de3469543176dc05bfbb3e375a9 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 17:53:58 +0200 Subject: [PATCH 028/279] fixed clear --- include/boost/unordered/detail/foa.hpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 26123e37..822b49ac 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -755,7 +755,20 @@ public: void clear()noexcept { - for_all_elements([this](value_type* p){destroy_element(p);}); + auto pg=arrays.groups; + auto p=arrays.elements; + if(p){ + for(std::size_t pos=0,last=arrays.groups_size_mask+1; + pos!=last;++pos,++pg,p+=N){ + auto mask=pg->match_really_occupied(); + while(mask){ + auto n=unchecked_countr_zero(mask); + destroy_element(p+n); + pg->reset(n); + mask&=mask-1; + } + } + } size_=0; } From 85324f9a433cff6d8fae6019c4543224fd4ce86a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 19:13:26 +0200 Subject: [PATCH 029/279] made microchange in find_impl to see if it impacts performance --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 822b49ac..3b40e304 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -948,7 +948,7 @@ private: prefetch_elements(p); do{ auto n=unchecked_countr_zero(mask); - if(BOOST_LIKELY(pred(x,key_from(p[n])))){ + if(BOOST_LIKELY(pred(x,type_policy::extract(p[n])))){ return {pg,n,p+n}; } mask&=mask-1; From 2a9f47ea2c4c0dbb01221961c7e89d1cb417efe1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 19:23:39 +0200 Subject: [PATCH 030/279] reverted --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3b40e304..822b49ac 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -948,7 +948,7 @@ private: prefetch_elements(p); do{ auto n=unchecked_countr_zero(mask); - if(BOOST_LIKELY(pred(x,type_policy::extract(p[n])))){ + if(BOOST_LIKELY(pred(x,key_from(p[n])))){ return {pg,n,p+n}; } mask&=mask-1; From cefe5965be9f901a6cd5dfd7d63af6bcc4b7f647 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 19:52:22 +0200 Subject: [PATCH 031/279] micro-optimized table_iterator ctor to see if it impacts performance --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 822b49ac..07504eb0 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -491,7 +491,7 @@ private: } } - unsigned char *pc=nullptr; + unsigned char *pc; Value *p=nullptr; }; From 80cb7281ba7eea3e56b2bc24f73e1ec8785350d5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 20:08:41 +0200 Subject: [PATCH 032/279] reverted --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 07504eb0..822b49ac 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -491,7 +491,7 @@ private: } } - unsigned char *pc; + unsigned char *pc=nullptr; Value *p=nullptr; }; From 63fdf675689edc65f2b74211abcfee0788316cba Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 20:19:08 +0200 Subject: [PATCH 033/279] un-inlined pow2_quadratic_prober memfuns to see it impacts performance --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 822b49ac..ffcfdc7b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -408,9 +408,9 @@ struct pow2_quadratic_prober { pow2_quadratic_prober(std::size_t pos_):pos{pos_}{} - inline std::size_t get()const{return pos;} + std::size_t get()const{return pos;} - inline bool next(std::size_t mask) + bool next(std::size_t mask) { step+=1; pos=(pos+step)&mask; From c44695eb3747a81ca9f6039d8087cec44c5b3fb2 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 28 Sep 2022 20:48:30 +0200 Subject: [PATCH 034/279] reverted --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index ffcfdc7b..822b49ac 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -408,9 +408,9 @@ struct pow2_quadratic_prober { pow2_quadratic_prober(std::size_t pos_):pos{pos_}{} - std::size_t get()const{return pos;} + inline std::size_t get()const{return pos;} - bool next(std::size_t mask) + inline bool next(std::size_t mask) { step+=1; pos=(pos+step)&mask; From 1577da25cc384149159c331503b3be0c411b296c Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 28 Sep 2022 13:47:00 -0700 Subject: [PATCH 035/279] Add proper flat_map header + forwarding header --- .../boost/unordered/unordered_flat_map.hpp | 1 + .../unordered/unordered_flat_map_fwd.hpp | 30 +++++++++++++++++++ include/boost/unordered_flat_map.hpp | 18 +++++++++++ 3 files changed, 49 insertions(+) create mode 100644 include/boost/unordered/unordered_flat_map_fwd.hpp create mode 100644 include/boost/unordered_flat_map.hpp diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 9229f381..75cad9a4 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -7,6 +7,7 @@ #endif #include +#include #include diff --git a/include/boost/unordered/unordered_flat_map_fwd.hpp b/include/boost/unordered/unordered_flat_map_fwd.hpp new file mode 100644 index 00000000..154b9093 --- /dev/null +++ b/include/boost/unordered/unordered_flat_map_fwd.hpp @@ -0,0 +1,30 @@ + +// Copyright (C) 2022 Christian Mazakas +// 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_FLAT_MAP_FWD_HPP_INCLUDED +#define BOOST_UNORDERED_FLAT_MAP_FWD_HPP_INCLUDED + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + +namespace boost { + namespace unordered { + template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator > > + class unordered_flat_map; + } + + using boost::unordered::unordered_flat_map; +} // namespace boost + +#endif diff --git a/include/boost/unordered_flat_map.hpp b/include/boost/unordered_flat_map.hpp new file mode 100644 index 00000000..bed3bc05 --- /dev/null +++ b/include/boost/unordered_flat_map.hpp @@ -0,0 +1,18 @@ + +// Copyright (C) 2022 Christian Mazakas +// 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) + +// See http://www.boost.org/libs/unordered for documentation + +#ifndef BOOST_UNORDERED_FLAT_MAP_HPP_INCLUDED +#define BOOST_UNORDERED_FLAT_MAP_HPP_INCLUDED + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#endif // BOOST_UNORDERED_FLAT_MAP_HPP_INCLUDED \ No newline at end of file From 6b1ef16e38d830420e14d97c52711fa3022a0fbf Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 28 Sep 2022 13:47:51 -0700 Subject: [PATCH 036/279] Add unordered_flat_set --- .../boost/unordered/unordered_flat_set.hpp | 186 ++++++++++++++++++ .../unordered/unordered_flat_set_fwd.hpp | 30 +++ include/boost/unordered_flat_set.hpp | 18 ++ 3 files changed, 234 insertions(+) create mode 100644 include/boost/unordered/unordered_flat_set.hpp create mode 100644 include/boost/unordered/unordered_flat_set_fwd.hpp create mode 100644 include/boost/unordered_flat_set.hpp diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp new file mode 100644 index 00000000..ced04bfb --- /dev/null +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -0,0 +1,186 @@ +// Copyright (C) 2022 Christian Mazakas +// 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_UNORDERED_FLAT_SET_HPP_INCLUDED +#define BOOST_UNORDERED_UNORDERED_FLAT_SET_HPP_INCLUDED + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include + +namespace boost { + namespace unordered { + template + class unordered_flat_set + { + struct set_types + { + using key_type = Key; + using value_type = Key; + static Key const& extract(value_type const& key) { return key; } + }; + + using table_type = detail::foa::table::type>; + + table_type table_; + + public: + using key_type = Key; + using value_type = typename set_types::value_type; + using size_type = std::size_t; + using key_equal = KeyEqual; + using reference = value_type&; + using const_reference = value_type const&; + using iterator = typename table_type::iterator; + using const_iterator = typename table_type::const_iterator; + + iterator begin() noexcept { return table_.begin(); } + const_iterator begin() const noexcept { return table_.begin(); } + const_iterator cbegin() const noexcept { return table_.cbegin(); } + + iterator end() noexcept { return table_.end(); } + const_iterator end() const noexcept { return table_.end(); } + const_iterator cend() const noexcept { return table_.cend(); } + + /// Capacity + /// + + BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept + { + return table_.empty(); + } + + size_type size() const noexcept { return table_.size(); } + + /// Modifiers + /// + + void clear() noexcept { table_.clear(); } + + std::pair insert(value_type const& value) + { + return table_.insert(value); + } + + std::pair insert(value_type&& value) + { + return table_.insert(std::move(value)); + } + + iterator insert(const_iterator, value_type const& value) + { + return table_.insert(value).first; + } + + iterator insert(const_iterator, value_type&& value) + { + return table_.insert(std::move(value)).first; + } + + template + typename std::enable_if< + std::is_base_of::value, + void>::type + insert(ForwardIterator first, ForwardIterator last) + { + auto const len = std::distance(first, last); + table_.reserve(len); + for (auto pos = first; pos != last; ++pos) { + table_.insert(*pos); + } + } + + template + typename std::enable_if< + !std::is_base_of::value, + void>::type + insert(InputIterator first, InputIterator last) + { + for (auto pos = first; pos != last; ++pos) { + table_.insert(*pos); + } + } + + void insert(std::initializer_list ilist) + { + this->insert(ilist.begin(), ilist.end()); + } + + template std::pair emplace(Args&&... args) + { + return table_.emplace(std::forward(args)...); + } + + void erase(const_iterator pos) { return table_.erase(pos); } + size_type erase(key_type const& key) { return table_.erase(key); } + + /// Lookup + /// + + size_type count(key_type const& key) const + { + auto pos = table_.find(key); + return pos != table_.end() ? 1 : 0; + } + + iterator find(key_type const& key) { return table_.find(key); } + + const_iterator find(key_type const& key) const + { + return table_.find(key); + } + + std::pair equal_range(key_type const& key) + { + auto pos = table_.find(key); + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; + } + + std::pair equal_range( + key_type const& key) const + { + auto pos = table_.find(key); + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; + } + + size_type bucket_count() const noexcept { return table_.capacity(); } + + float load_factor() const noexcept { return table_.load_factor(); } + + float max_load_factor() const noexcept + { + return table_.max_load_factor(); + } + + key_equal key_eq() const { return table_.key_eq(); } + }; + } // namespace unordered +} // namespace boost + +#endif diff --git a/include/boost/unordered/unordered_flat_set_fwd.hpp b/include/boost/unordered/unordered_flat_set_fwd.hpp new file mode 100644 index 00000000..91550cc0 --- /dev/null +++ b/include/boost/unordered/unordered_flat_set_fwd.hpp @@ -0,0 +1,30 @@ + +// Copyright (C) 2022 Christian Mazakas +// 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_FLAT_SET_FWD_HPP_INCLUDED +#define BOOST_UNORDERED_FLAT_SET_FWD_HPP_INCLUDED + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include + +namespace boost { + namespace unordered { + template , + class KeyEqual = std::equal_to, + class Allocator = std::allocator > + class unordered_flat_set; + } + + using boost::unordered::unordered_flat_set; +} // namespace boost + +#endif diff --git a/include/boost/unordered_flat_set.hpp b/include/boost/unordered_flat_set.hpp new file mode 100644 index 00000000..6e2067f8 --- /dev/null +++ b/include/boost/unordered_flat_set.hpp @@ -0,0 +1,18 @@ + +// Copyright (C) 2022 Christian Mazakas +// 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) + +// See http://www.boost.org/libs/unordered for documentation + +#ifndef BOOST_UNORDERED_FLAT_SET_HPP_INCLUDED +#define BOOST_UNORDERED_FLAT_SET_HPP_INCLUDED + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include + +#endif // BOOST_UNORDERED_FLAT_SET_HPP_INCLUDED \ No newline at end of file From 855d538ea335ba44927730bacfbfee3f9e8f844f Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 28 Sep 2022 13:48:21 -0700 Subject: [PATCH 037/279] Fix typo in foa table's empty() implementation --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 822b49ac..3f210014 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -682,7 +682,7 @@ public: const_iterator cbegin()const noexcept{return begin();} const_iterator cend()const noexcept{return end();} - bool empty()const noexcept{return size()!=0;} + bool empty()const noexcept{return size()==0;} std::size_t size()const noexcept{return size_;} std::size_t max_size()const noexcept{return SIZE_MAX;} From 19c500de27f9e59c67c208a233399fc279552fdb Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 28 Sep 2022 13:48:49 -0700 Subject: [PATCH 038/279] Silence conversion warning in foa table's emplace_impl() --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3f210014..2ad8e575 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -974,7 +974,7 @@ private: return {it,false}; } else if(BOOST_UNLIKELY(size_>=ml)){ - unchecked_rehash(std::size_t(std::ceil((size_+1)/mlf))); + unchecked_rehash(std::size_t(std::ceil(static_cast(size_+1)/mlf))); pos0=position_for(hash); } return { From 3af53a6598471adadb57b0393fcbdc155d0508c4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 28 Sep 2022 13:49:17 -0700 Subject: [PATCH 039/279] Flesh out unordered_flat_map for insert_tests --- .../boost/unordered/unordered_flat_map.hpp | 140 +++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 75cad9a4..fa210436 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -1,3 +1,7 @@ +// Copyright (C) 2022 Christian Mazakas +// 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_UNORDERED_FLAT_MAP_HPP_INCLUDED #define BOOST_UNORDERED_UNORDERED_FLAT_MAP_HPP_INCLUDED @@ -11,6 +15,9 @@ #include +#include +#include +#include #include namespace boost { @@ -37,6 +44,8 @@ namespace boost { using value_type = typename map_types::value_type; using size_type = std::size_t; using key_equal = KeyEqual; + using reference = value_type&; + using const_reference = value_type const&; using iterator = typename table_type::iterator; using const_iterator = typename table_type::const_iterator; @@ -48,11 +57,21 @@ namespace boost { const_iterator end() const noexcept { return table_.end(); } const_iterator cend() const noexcept { return table_.cend(); } + /// Capacity + /// + + BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept + { + return table_.empty(); + } + size_type size() const noexcept { return table_.size(); } /// Modifiers /// + void clear() noexcept { table_.clear(); } + std::pair insert(value_type const& value) { return table_.insert(value); @@ -63,10 +82,109 @@ namespace boost { return table_.insert(std::move(value)); } - size_type count(key_type const& key) const + iterator insert(const_iterator, value_type const& value) { - auto pos = table_.find(key); - return pos != table_.end() ? 1 : 0; + return table_.insert(value).first; + } + + iterator insert(const_iterator, value_type&& value) + { + return table_.insert(std::move(value)).first; + } + + template + typename std::enable_if< + std::is_base_of::value, + void>::type + insert(ForwardIterator first, ForwardIterator last) + { + auto const len = std::distance(first, last); + table_.reserve(len); + for (auto pos = first; pos != last; ++pos) { + table_.insert(*pos); + } + } + + template + typename std::enable_if< + !std::is_base_of::value, + void>::type + insert(InputIterator first, InputIterator last) + { + for (auto pos = first; pos != last; ++pos) { + table_.insert(*pos); + } + } + + void insert(std::initializer_list ilist) + { + this->insert(ilist.begin(), ilist.end()); + } + + 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; + } + iter_bool_pair.first->second = std::forward(obj); + return iter_bool_pair; + } + + 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; + } + iter_bool_pair.first->second = std::forward(obj); + return iter_bool_pair; + } + + template + iterator insert_or_assign(const_iterator, key_type const& key, M&& obj) + { + return this->insert_or_assign(key, std::forward(obj)).first; + } + + template + iterator insert_or_assign(const_iterator, key_type&& key, M&& obj) + { + return this->insert_or_assign(std::move(key), std::forward(obj)) + .first; + } + + template std::pair emplace(Args&&... args) + { + return table_.emplace(std::forward(args)...); + } + + template + std::pair try_emplace(key_type const& key, Args&&... args) + { + return table_.try_emplace(key, std::forward(args)...); + } + + template + std::pair try_emplace(key_type&& key, Args&&... args) + { + return table_.try_emplace(std::move(key), std::forward(args)...); + } + + template + iterator try_emplace(const_iterator, key_type const& key, Args&&... args) + { + return table_.try_emplace(key, std::forward(args)...).first; + } + + template + iterator try_emplace(const_iterator, key_type&& key, Args&&... args) + { + return table_.try_emplace(std::move(key), std::forward(args)...) + .first; } void erase(iterator pos) { table_.erase(pos); } @@ -76,6 +194,22 @@ namespace boost { /// Lookup /// + mapped_type& operator[](key_type const& key) + { + return table_.try_emplace(key).first->second; + } + + mapped_type& operator[](key_type&& key) + { + return table_.try_emplace(std::move(key)).first->second; + } + + size_type count(key_type const& key) const + { + auto pos = table_.find(key); + return pos != table_.end() ? 1 : 0; + } + iterator find(key_type const& key) { return table_.find(key); } const_iterator find(key_type const& key) const From c37cfacb4427b036b6be079bb464356189d4f4ca Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 28 Sep 2022 13:49:38 -0700 Subject: [PATCH 040/279] Finally get insert_tests passing for flat map/set --- test/unordered/insert_tests.cpp | 101 ++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index acf7cf9e..b5b1fbae 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -5,15 +5,16 @@ #if !defined(PIECEWISE_TEST_NAME) +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else // clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" // clang-format on - -#ifdef BOOST_UNORDERED_FOA_TESTS -#include #endif #include "../helpers/test.hpp" @@ -318,6 +319,7 @@ namespace insert_tests { UNORDERED_SUB_TEST("insert range with rehash tests") { + std::cout << "Starting problematic test case now!!!" << std::endl; test::check_instances check_; X x; @@ -879,11 +881,44 @@ namespace insert_tests { using test::limited_range; #ifdef BOOST_UNORDERED_FOA_TESTS - boost::unordered::unordered_flat_map >* test_flat_map; + boost::unordered_flat_set >* test_set_std_alloc; + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map >* test_map; UNORDERED_TEST(unique_insert_tests1, - ((test_flat_map))((default_generator)(generate_collisions)(limited_range))) + ((test_set_std_alloc)(test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST( + insert_tests2, ((test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(unique_emplace_tests1, + ((test_set_std_alloc)(test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(move_emplace_tests, + ((test_set_std_alloc)(test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(default_emplace_tests, + ((test_set_std_alloc)(test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(map_tests, + ((test_map))((default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST( + map_tests2, ((test_map))((default_generator)(generate_collisions))) + + UNORDERED_TEST(map_insert_range_test1, + ((test_map))((default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(map_insert_range_test2, + ((test_map))((default_generator)(generate_collisions)(limited_range))) #else boost::unordered_set >* test_set_std_alloc; @@ -960,13 +995,21 @@ namespace insert_tests { }; UNORDERED_AUTO_TEST (insert_initializer_list_set) { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set set; +#else boost::unordered_set set; +#endif set.insert({1, 2, 3, 1}); BOOST_TEST_EQ(set.size(), 3u); BOOST_TEST(set.find(1) != set.end()); BOOST_TEST(set.find(4) == set.end()); +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set set2; +#else boost::unordered_set set2; +#endif #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)) set2.insert({{1, 2}}); @@ -995,6 +1038,7 @@ namespace insert_tests { BOOST_TEST(set2.find({8, 7}) == set2.end()); } +#ifndef BOOST_UNORDERED_FOA_TESTS #if !BOOST_WORKAROUND(BOOST_MSVC, == 1800) UNORDERED_AUTO_TEST (insert_initializer_list_multiset) { @@ -1012,16 +1056,22 @@ namespace insert_tests { BOOST_TEST_EQ(multiset.count("c"), 0u); } +#endif #endif UNORDERED_AUTO_TEST (insert_initializer_list_map) { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map map; +#else boost::unordered_map map; + #endif // map.insert({}); BOOST_TEST(map.empty()); map.insert({{"a", "b"}, {"a", "b"}, {"d", ""}}); BOOST_TEST_EQ(map.size(), 2u); } +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (insert_initializer_list_multimap) { boost::unordered_multimap multimap; // multimap.insert({}); @@ -1030,6 +1080,7 @@ namespace insert_tests { BOOST_TEST_EQ(multimap.size(), 3u); BOOST_TEST_EQ(multimap.count("a"), 2u); } +#endif #endif @@ -1060,10 +1111,18 @@ namespace insert_tests { UNORDERED_AUTO_TEST (map_emplace_test) { { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map > > + x; +#else + boost::unordered_map > > x; +#endif #if !BOOST_UNORDERED_SUN_WORKAROUNDS1 x.emplace(); @@ -1080,6 +1139,7 @@ namespace insert_tests { x.find(5) != x.end() && x.find(5)->second == overloaded_constructor()); } +#ifndef BOOST_UNORDERED_FOA_TESTS { boost::unordered_multimapsecond == overloaded_constructor(3)); } +#endif } UNORDERED_AUTO_TEST (set_emplace_test) { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set x; + overloaded_constructor check; +#else boost::unordered_set x; overloaded_constructor check; +#endif #if !BOOST_UNORDERED_SUN_WORKAROUNDS1 x.emplace(); @@ -1146,6 +1212,7 @@ namespace insert_tests { } }; +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (map_emplace_test2) { // Emulating piecewise construction with boost::tuple bypasses the // allocator's construct method, but still uses test destroy method. @@ -1269,10 +1336,13 @@ namespace insert_tests { std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3)); BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); } +#endif // Use the preprocessor to generate tests using different combinations of // boost/std piecewise_construct_t/tuple. +#ifndef BOOST_UNORDERED_FOA_TESTS + #define PIECEWISE_TEST_NAME boost_tuple_piecewise_tests #define PIECEWISE_NAMESPACE boost::unordered #define TUPLE_NAMESPACE boost @@ -1299,6 +1369,8 @@ namespace insert_tests { #endif +#endif + #if !defined(BOOST_NO_CXX11_HDR_TUPLE) && \ BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT @@ -1321,12 +1393,21 @@ UNORDERED_AUTO_TEST (PIECEWISE_TEST_NAME) { #endif { +#if defined(BOOST_UNORDERED_FOA_TESTS) + boost::unordered_flat_map, + std::equal_to, + test::allocator1< + std::pair > > + x; +#else boost::unordered_map, std::equal_to, test::allocator1< std::pair > > x; +#endif x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple()); @@ -1370,6 +1451,7 @@ UNORDERED_AUTO_TEST (PIECEWISE_TEST_NAME) { x.find(overloaded_constructor(2, 3))->second == overloaded_constructor(4, 5, 6)); } +#ifndef BOOST_UNORDERED_FOA_TESTS { boost::unordered_multimap, @@ -1403,6 +1485,7 @@ UNORDERED_AUTO_TEST (PIECEWISE_TEST_NAME) { x.find(overloaded_constructor(9, 3, 1))->second == overloaded_constructor(10)); } +#endif } UNORDERED_AUTO_TEST (BOOST_PP_CAT(PIECEWISE_TEST_NAME, 2)) { @@ -1410,9 +1493,15 @@ UNORDERED_AUTO_TEST (BOOST_PP_CAT(PIECEWISE_TEST_NAME, 2)) { test::detail::disable_construction_tracking _scoped; #endif +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set< + std::pair > + x; +#else boost::unordered_set< std::pair > x; +#endif std::pair check; x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, From fdc39982f3f77be5d03781c972953e507bd52d0f Mon Sep 17 00:00:00 2001 From: joaquintides Date: Thu, 29 Sep 2022 10:49:27 +0200 Subject: [PATCH 041/279] fixed trivial error in #ifdefd-out code --- include/boost/unordered/detail/foa.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2ad8e575..7ee1ccbe 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1050,9 +1050,9 @@ private: const arrays_info& arrays_,std::size_t pos0,std::size_t hash, Args&&... args) { - auto p=insert_position(arrays_,pos0,hash); - auto &pos=p.first; - auto &n=p.second; + auto pn=insert_position(arrays_,pos0,hash); + auto &pos=pn.first; + auto &n=pn.second; auto pg=arrays_.groups+pos; auto p=arrays_.elements+pos*N+n; construct_element(p,std::forward(args)...); From 86956b0be13b69b9414efbc324035b4e91163e29 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Thu, 29 Sep 2022 19:24:15 +0200 Subject: [PATCH 042/279] added non-SIMD support --- include/boost/unordered/detail/foa.hpp | 165 +++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 7ee1ccbe..4282815b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -357,6 +357,171 @@ private: int8x16_t m; }; +#else /* non-SIMD */ + +struct group15 +{ + static constexpr int N=15; + + struct dummy_group_type + { + alignas(16) boost::uint64_t m[2]= + {0x0000000000004000ull,0x0000000000000000ull}; + }; + + inline void set(std::size_t pos,std::size_t hash) + { + BOOST_ASSERT(pos(pc)%sizeof(group15); + pc-=pos; + reinterpret_cast(pc)->reset(pos); + } + + inline int match(std::size_t hash)const + { + return match_impl(adjust_hash(hash)); + } + + inline bool is_not_overflowed(std::size_t hash)const + { + return !(reinterpret_cast(m)[hash%8] & 0x8000u); + } + + inline void mark_overflow(std::size_t hash) + { + reinterpret_cast(m)[hash%8]|=0x8000u; + } + + inline int match_available()const + { + boost::uint64_t x=~(m[0]|m[1]); + boost::uint32_t y=x&(x>>32); + y&=y>>16; + return y&0x7FFF; + } + + inline int match_occupied()const + { + boost::uint64_t x=m[0]|m[1]; + boost::uint32_t y=x|(x>>32); + y|=y>>16; + return y&0x7FFF; + } + + inline int match_really_occupied()const /* excluding sentinel */ + { + return ~(match_impl(0)|match_impl(1))&0x7FFF; + } + +private: + static constexpr unsigned char available_=0, + sentinel_=1; + + inline static unsigned char adjust_hash(std::size_t hash) + { + static constexpr unsigned char table[]={ + 2,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, + }; + + return table[(unsigned char)hash]; + } + + inline void set_impl(std::size_t pos,std::size_t n) + { + BOOST_ASSERT(n<256); + set_impl(m[0],pos,n&0xFu); + set_impl(m[1],pos,n>>4); + } + + static inline void set_impl(boost::uint64_t& x,unsigned pos,unsigned n) + { + static constexpr boost::uint64_t mask[]= + { + 0x0000000000000000ull,0x0000000000000001ull,0x0000000000010000ull, + 0x0000000000010001ull,0x0000000100000000ull,0x0000000100000001ull, + 0x0000000100010000ull,0x0000000100010001ull,0x0001000000000000ull, + 0x0001000000000001ull,0x0001000000010000ull,0x0001000000010001ull, + 0x0001000100000000ull,0x0001000100000001ull,0x0001000100010000ull, + 0x0001000100010001ull, + }; + static constexpr boost::uint64_t imask[]= + { + 0x0001000100010001ull,0x0001000100010000ull,0x0001000100000001ull, + 0x0001000100000000ull,0x0001000000010001ull,0x0001000000010000ull, + 0x0001000000000001ull,0x0001000000000000ull,0x0000000100010001ull, + 0x0000000100010000ull,0x0000000100000001ull,0x0000000100000000ull, + 0x0000000000010001ull,0x0000000000010000ull,0x0000000000000001ull, + 0x0000000000000000ull, + }; + + BOOST_ASSERT(pos<16&&n<16); + x|= mask[n]<>4])&lo; + boost::uint32_t y=hi&(hi>>32); + y&=y>>16; + return y&0x7FFF; + } + + alignas(16) boost::uint64_t m[2]; +}; + #endif inline unsigned int unchecked_countr_zero(int x) From faa6e91ed28f311f916554307a713f4c56a5869a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 11:16:58 -0700 Subject: [PATCH 043/279] Fix conversion warning in reserve() --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 4282815b..5d01c776 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -972,7 +972,7 @@ public: void reserve(std::size_t n) { - rehash(std::size_t(std::ceil(n/mlf))); + rehash(std::size_t(std::ceil(static_cast(n)/mlf))); } private: From ac3520791ea0476d5638dfdc9dd8442382e9202b Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 11:17:22 -0700 Subject: [PATCH 044/279] Clean up insert_tests --- test/unordered/insert_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index b5b1fbae..e60be128 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2010 Daniel James. +// Copyright (C) 2022 Christian Mazakas // 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) @@ -319,7 +320,6 @@ namespace insert_tests { UNORDERED_SUB_TEST("insert range with rehash tests") { - std::cout << "Starting problematic test case now!!!" << std::endl; test::check_instances check_; X x; From 8f29a32a33dfcb2f970bacc27567821152474ac4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 11:18:59 -0700 Subject: [PATCH 045/279] Simplify range-based insert() so it doesn't eagerly rehash so that insert_tests pass --- include/boost/unordered/unordered_flat_map.hpp | 18 +----------------- include/boost/unordered/unordered_flat_set.hpp | 18 +----------------- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index fa210436..f1f68e71 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -92,24 +92,8 @@ namespace boost { return table_.insert(std::move(value)).first; } - template - typename std::enable_if< - std::is_base_of::value, - void>::type - insert(ForwardIterator first, ForwardIterator last) - { - auto const len = std::distance(first, last); - table_.reserve(len); - for (auto pos = first; pos != last; ++pos) { - table_.insert(*pos); - } - } - template - typename std::enable_if< - !std::is_base_of::value, - void>::type - insert(InputIterator first, InputIterator last) + void insert(InputIterator first, InputIterator last) { for (auto pos = first; pos != last; ++pos) { table_.insert(*pos); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index ced04bfb..e571a5e4 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -91,24 +91,8 @@ namespace boost { return table_.insert(std::move(value)).first; } - template - typename std::enable_if< - std::is_base_of::value, - void>::type - insert(ForwardIterator first, ForwardIterator last) - { - auto const len = std::distance(first, last); - table_.reserve(len); - for (auto pos = first; pos != last; ++pos) { - table_.insert(*pos); - } - } - template - typename std::enable_if< - !std::is_base_of::value, - void>::type - insert(InputIterator first, InputIterator last) + void insert(InputIterator first, InputIterator last) { for (auto pos = first; pos != last; ++pos) { table_.insert(*pos); From 6ac1cf1a5f49038b05a75e1cddc08417cf7a28a4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 11:19:17 -0700 Subject: [PATCH 046/279] Add find_tests --- .../boost/unordered/unordered_flat_map.hpp | 20 +++++++++++++++ .../boost/unordered/unordered_flat_set.hpp | 22 +++++++++++++++- test/Jamfile.v2 | 1 + test/unordered/find_tests.cpp | 25 ++++++++++++++++--- 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index f1f68e71..9f077d7a 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -43,7 +43,9 @@ namespace boost { using mapped_type = T; using value_type = typename map_types::value_type; using size_type = std::size_t; + using hasher = Hash; using key_equal = KeyEqual; + using allocator_type = Allocator; using reference = value_type&; using const_reference = value_type const&; using iterator = typename table_type::iterator; @@ -57,6 +59,24 @@ namespace boost { const_iterator end() const noexcept { return table_.end(); } const_iterator cend() const noexcept { return table_.cend(); } + unordered_flat_map() : unordered_flat_map(0) {} + + explicit unordered_flat_map(size_type n, hasher const& h = hasher(), + key_equal const& pred = key_equal(), + allocator_type const& a = allocator_type()) + : table_(n, h, pred, a) + { + } + + template + unordered_flat_map(Iterator first, Iterator last, size_type n = 0, + hasher const& h = hasher(), key_equal const& pred = key_equal(), + allocator_type const& a = allocator_type()) + : unordered_flat_map(n, h, pred, a) + { + this->insert(first, last); + } + /// Capacity /// diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index e571a5e4..cec24f18 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -10,8 +10,8 @@ #pragma once #endif -#include #include +#include #include @@ -42,12 +42,32 @@ namespace boost { using key_type = Key; using value_type = typename set_types::value_type; using size_type = std::size_t; + using hasher = Hash; using key_equal = KeyEqual; + using allocator_type = Allocator; using reference = value_type&; using const_reference = value_type const&; using iterator = typename table_type::iterator; using const_iterator = typename table_type::const_iterator; + unordered_flat_set() : unordered_flat_set(0) {} + + explicit unordered_flat_set(size_type n, hasher const& h = hasher(), + key_equal const& pred = key_equal(), + allocator_type const& a = allocator_type()) + : table_(n, h, pred, a) + { + } + + template + unordered_flat_set(Iterator first, Iterator last, size_type n = 0, + hasher const& h = hasher(), key_equal const& pred = key_equal(), + allocator_type const& a = allocator_type()) + : unordered_flat_set(n, h, pred, a) + { + this->insert(first, last); + } + iterator begin() noexcept { return table_.begin(); } const_iterator begin() const noexcept { return table_.begin(); } const_iterator cbegin() const noexcept { return table_.cbegin(); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e6b3ff91..bee68b6c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -67,6 +67,7 @@ compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTIM compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_SET : insert_node_type_fail_set ; compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ; run unordered/find_tests.cpp ; +run unordered/find_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; run unordered/at_tests.cpp ; run unordered/bucket_tests.cpp ; run unordered/load_factor_tests.cpp ; diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index 031371c3..f33e9a5e 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -1,14 +1,20 @@ // Copyright 2006-2009 Daniel James. +// Copyright (C) 2022 Christian Mazakas // 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) +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else // clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" // clang-format on +#endif #include "../helpers/test.hpp" #include "../objects/test.hpp" @@ -133,6 +139,20 @@ namespace find_tests { } } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map >* test_map; + + UNORDERED_TEST( + find_tests1, ((test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_set >* test_set; boost::unordered_multiset >* test_multimap; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_TEST( find_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) UNORDERED_TEST(find_compatible_keys_test, ((test_set)(test_multiset)(test_map)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) +#endif } RUN_TESTS() From cb673135d29b02d08dbb4ce840039ae1d9784962 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 11:40:13 -0700 Subject: [PATCH 047/279] Use static_cast to silence conversion warnings --- include/boost/unordered/detail/foa.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 5d01c776..3ca8095b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -420,7 +420,7 @@ struct group15 inline int match_available()const { boost::uint64_t x=~(m[0]|m[1]); - boost::uint32_t y=x&(x>>32); + boost::uint32_t y=static_cast(x&(x>>32)); y&=y>>16; return y&0x7FFF; } @@ -428,7 +428,7 @@ struct group15 inline int match_occupied()const { boost::uint64_t x=m[0]|m[1]; - boost::uint32_t y=x|(x>>32); + boost::uint32_t y=static_cast(x|(x>>32)); y|=y>>16; return y&0x7FFF; } @@ -514,7 +514,7 @@ private: BOOST_ASSERT(n<256); boost::uint64_t lo=~(m[0]^mask[n&0xFu]); boost::uint64_t hi=~(m[1]^mask[n>>4])&lo; - boost::uint32_t y=hi&(hi>>32); + boost::uint32_t y=static_cast(hi&(hi>>32)); y&=y>>16; return y&0x7FFF; } From 30997bd9ef1176aa9437936cd8529b9a086c8e67 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 12:50:56 -0700 Subject: [PATCH 048/279] Add constructor_tests --- .../boost/unordered/unordered_flat_map.hpp | 52 ++++++++++++++++--- .../boost/unordered/unordered_flat_set.hpp | 36 +++++++++++++ test/Jamfile.v2 | 1 + test/unordered/constructor_tests.cpp | 49 +++++++++++++++-- 4 files changed, 126 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 9f077d7a..3bb3122b 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -51,14 +51,6 @@ namespace boost { using iterator = typename table_type::iterator; using const_iterator = typename table_type::const_iterator; - iterator begin() noexcept { return table_.begin(); } - const_iterator begin() const noexcept { return table_.begin(); } - const_iterator cbegin() const noexcept { return table_.cbegin(); } - - iterator end() noexcept { return table_.end(); } - const_iterator end() const noexcept { return table_.end(); } - const_iterator cend() const noexcept { return table_.cend(); } - unordered_flat_map() : unordered_flat_map(0) {} explicit unordered_flat_map(size_type n, hasher const& h = hasher(), @@ -68,6 +60,16 @@ namespace boost { { } + unordered_flat_map(size_type n, allocator_type const& a) + : unordered_flat_map(n, hasher(), key_equal(), a) + { + } + + explicit unordered_flat_map(allocator_type const& a) + : unordered_flat_map(0, a) + { + } + template unordered_flat_map(Iterator first, Iterator last, size_type n = 0, hasher const& h = hasher(), key_equal const& pred = key_equal(), @@ -77,6 +79,30 @@ namespace boost { this->insert(first, last); } + unordered_flat_map(std::initializer_list ilist, + size_type n = 0, hasher const& h = hasher(), + key_equal const& pred = key_equal(), + allocator_type const& a = allocator_type()) + : unordered_flat_map(ilist.begin(), ilist.end(), n, h, pred, a) + { + } + + allocator_type get_allocator() const noexcept + { + return table_.get_allocator(); + } + + /// Iterators + /// + + iterator begin() noexcept { return table_.begin(); } + const_iterator begin() const noexcept { return table_.begin(); } + const_iterator cbegin() const noexcept { return table_.cbegin(); } + + iterator end() noexcept { return table_.end(); } + const_iterator end() const noexcept { return table_.end(); } + const_iterator cend() const noexcept { return table_.cend(); } + /// Capacity /// @@ -246,6 +272,9 @@ namespace boost { return {pos, next}; } + /// Hash Policy + /// + size_type bucket_count() const noexcept { return table_.capacity(); } float load_factor() const noexcept { return table_.load_factor(); } @@ -255,6 +284,13 @@ namespace boost { return table_.max_load_factor(); } + void max_load_factor(float) {} + + /// Observers + /// + + hasher hash_function() const { return table_.hash_function(); } + key_equal key_eq() const { return table_.key_eq(); } }; } // namespace unordered diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index cec24f18..c7bed6fc 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -59,6 +59,16 @@ namespace boost { { } + unordered_flat_set(size_type n, allocator_type const& a) + : unordered_flat_set(n, hasher(), key_equal(), a) + { + } + + explicit unordered_flat_set(allocator_type const& a) + : unordered_flat_set(0, a) + { + } + template unordered_flat_set(Iterator first, Iterator last, size_type n = 0, hasher const& h = hasher(), key_equal const& pred = key_equal(), @@ -68,6 +78,22 @@ namespace boost { this->insert(first, last); } + unordered_flat_set(std::initializer_list ilist, + size_type n = 0, hasher const& h = hasher(), + key_equal const& pred = key_equal(), + allocator_type const& a = allocator_type()) + : unordered_flat_set(ilist.begin(), ilist.end(), n, h, pred, a) + { + } + + allocator_type get_allocator() const noexcept + { + return table_.get_allocator(); + } + + /// Iterators + /// + iterator begin() noexcept { return table_.begin(); } const_iterator begin() const noexcept { return table_.begin(); } const_iterator cbegin() const noexcept { return table_.cbegin(); } @@ -173,6 +199,9 @@ namespace boost { return {pos, next}; } + /// Hash Policy + /// + size_type bucket_count() const noexcept { return table_.capacity(); } float load_factor() const noexcept { return table_.load_factor(); } @@ -182,6 +211,13 @@ namespace boost { return table_.max_load_factor(); } + void max_load_factor(float) {} + + /// Observers + /// + + hasher hash_function() const { return table_.hash_function(); } + key_equal key_eq() const { return table_.key_eq(); } }; } // namespace unordered diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index bee68b6c..b07b2313 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -48,6 +48,7 @@ run unordered/incomplete_test.cpp ; run unordered/simple_tests.cpp ; run unordered/equivalent_keys_tests.cpp ; run unordered/constructor_tests.cpp ; +run unordered/constructor_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; run unordered/copy_tests.cpp ; run unordered/move_tests.cpp ; run unordered/assign_tests.cpp ; diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index c2a43283..2b9d3d17 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -1,14 +1,20 @@ // Copyright 2006-2010 Daniel James. +// Copyright (C) 2022 Christian Mazakas // 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) +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else // clang-format off #include "../helpers/prefix.hpp" #include #include #include "../helpers/postfix.hpp" // clang-format on +#endif #include "../helpers/test.hpp" #include "../objects/test.hpp" @@ -497,6 +503,35 @@ namespace constructor_tests { test::check_equivalent_keys(x); } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map >* test_map_std_alloc; + + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map >* test_map; + + UNORDERED_TEST(constructor_tests1, + ((test_map_std_alloc)(test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(constructor_tests2, + ((test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(map_constructor_test, + ((test_map_std_alloc)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(no_alloc_default_construct_test, + ((test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_map >* test_map_std_alloc; @@ -509,10 +544,6 @@ namespace constructor_tests { boost::unordered_multimap >* test_multimap; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_TEST(constructor_tests1, ((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) @@ -528,12 +559,17 @@ namespace constructor_tests { UNORDERED_TEST(no_alloc_default_construct_test, ((test_set)(test_multiset)(test_map)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) +#endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST (test_default_initializer_list) { std::initializer_list init; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set x1 = init; +#else boost::unordered_set x1 = init; +#endif BOOST_TEST(x1.empty()); } @@ -542,7 +578,12 @@ namespace constructor_tests { #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST (test_initializer_list) { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set x1 = {2, 10, 45, -5}; +#else boost::unordered_set x1 = {2, 10, 45, -5}; +#endif + BOOST_TEST(x1.find(10) != x1.end()); BOOST_TEST(x1.find(46) == x1.end()); } From 3582ac91d7cec52a7a45a71fb28ee554925f9b92 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 13:45:51 -0700 Subject: [PATCH 049/279] Silence conversion warning in foa --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3ca8095b..25d2dd75 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -719,7 +719,7 @@ public: table(const table& x,const Allocator& al_): h{x.h},pred{x.pred},al{al_},size_{0}, - arrays{new_arrays(std::size_t(std::ceil(x.size()/mlf)))}, + arrays{new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))}, ml{max_load()} { BOOST_TRY{ From 71b64139da61e0b5702738da432b98209bbb02fc Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 13:46:03 -0700 Subject: [PATCH 050/279] Add copy_tests --- .../boost/unordered/unordered_flat_map.hpp | 10 ++++ .../boost/unordered/unordered_flat_set.hpp | 10 ++++ test/Jamfile.v2 | 1 + test/unordered/copy_tests.cpp | 59 +++++++++++++------ 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 3bb3122b..b7106e24 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -79,6 +79,16 @@ namespace boost { this->insert(first, last); } + unordered_flat_map(unordered_flat_map const& other) : table_(other.table_) + { + } + + unordered_flat_map( + unordered_flat_map const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + unordered_flat_map(std::initializer_list ilist, size_type n = 0, hasher const& h = hasher(), key_equal const& pred = key_equal(), diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index c7bed6fc..3a1f5178 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -78,6 +78,16 @@ namespace boost { this->insert(first, last); } + unordered_flat_set(unordered_flat_set const& other) : table_(other.table_) + { + } + + unordered_flat_set( + unordered_flat_set const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + unordered_flat_set(std::initializer_list ilist, size_type n = 0, hasher const& h = hasher(), key_equal const& pred = key_equal(), diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b07b2313..ca746a62 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -50,6 +50,7 @@ run unordered/equivalent_keys_tests.cpp ; run unordered/constructor_tests.cpp ; run unordered/constructor_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; run unordered/copy_tests.cpp ; +run unordered/copy_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; run unordered/move_tests.cpp ; run unordered/assign_tests.cpp ; run unordered/insert_tests.cpp ; diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index f7c0ddd8..f8be49b7 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -1,14 +1,18 @@ // Copyright 2006-2009 Daniel James. +// Copyright (C) 2022 Christian Mazakas // 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) -// clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" -// clang-format on #include "../helpers/test.hpp" #include "../objects/test.hpp" @@ -229,6 +233,38 @@ namespace copy_tests { } } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map >* test_map; + + boost::unordered_flat_set >* + test_set_select_copy; + boost::unordered_flat_map >* + test_map_select_copy; + + boost::unordered_flat_set >* + test_set_no_select_copy; + boost::unordered_flat_map >* + test_map_no_select_copy; + + UNORDERED_TEST(copy_construct_tests1, + ((test_set)(test_map)(test_set_select_copy)(test_map_select_copy)(test_set_no_select_copy)(test_map_no_select_copy))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(copy_construct_tests2, + ((test_set)(test_map)(test_set_select_copy)(test_map_select_copy)(test_set_no_select_copy)(test_map_no_select_copy))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_set >* test_set; boost::unordered_multiset >* test_multimap_no_select_copy; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_TEST(copy_construct_tests1, - ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)( - test_multiset_select_copy)(test_map_select_copy)( - test_multimap_select_copy)(test_set_no_select_copy)( - test_multiset_no_select_copy)(test_map_no_select_copy)( - test_multimap_no_select_copy))( + ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy))( (default_generator)(generate_collisions)(limited_range))) UNORDERED_TEST(copy_construct_tests2, - ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)( - test_multiset_select_copy)(test_map_select_copy)( - test_multimap_select_copy)(test_set_no_select_copy)( - test_multiset_no_select_copy)(test_map_no_select_copy)( - test_multimap_no_select_copy))( + ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy))( (default_generator)(generate_collisions)(limited_range))) -} +#endif +} // namespace copy_tests RUN_TESTS() From 6110a0827c3096315387a691af6623324aa53abb Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 29 Sep 2022 13:57:16 -0700 Subject: [PATCH 051/279] Fix default initialiation warning for clang-3.7, clang-3.8 --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 25d2dd75..d6e18c62 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1021,7 +1021,7 @@ private: static group_type* dummy_groups()noexcept { - static constexpr group_type::dummy_group_type storage[size_policy::min_size()]; + static constexpr group_type::dummy_group_type storage[size_policy::min_size()]{}; return reinterpret_cast( const_cast(storage)); } From b1449ca5022fcee1c43dd05d9f99116c1c3fa62b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 30 Sep 2022 12:27:10 +0200 Subject: [PATCH 052/279] added unaligned load of __m128i --- include/boost/unordered/detail/foa.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d6e18c62..10879524 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -112,7 +112,8 @@ struct group15 inline int match(std::size_t hash)const { return _mm_movemask_epi8( - _mm_cmpeq_epi8(m,_mm_set1_epi32(match_word(hash))))&0x7FFF; + _mm_cmpeq_epi8( + _mm_loadu_si128(&m),_mm_set1_epi32(match_word(hash))))&0x7FFF; } inline bool is_not_overflowed(std::size_t hash)const @@ -130,7 +131,7 @@ struct group15 inline int match_available()const { return _mm_movemask_epi8( - _mm_cmpeq_epi8(m,_mm_setzero_si128()))&0x7FFF; + _mm_cmpeq_epi8(_mm_loadu_si128(&m),_mm_setzero_si128()))&0x7FFF; } inline int match_occupied()const @@ -213,7 +214,7 @@ private: return at(N); } - __m128i m; + alignas(16) __m128i m; }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) From 364cd86191b5bd256186e8072e3e0547906af047 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 30 Sep 2022 13:52:25 +0200 Subject: [PATCH 053/279] temporarily omitted alignas specifier --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 10879524..dcdf7b80 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -214,7 +214,7 @@ private: return at(N); } - alignas(16) __m128i m; + /*alignas(16)*/ __m128i m; }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) From 5f21e3964e513cdca46ad093ac2898e889f7e7a5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 30 Sep 2022 13:57:49 +0200 Subject: [PATCH 054/279] temporarily omitted _mm_loadu_si128 --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index dcdf7b80..b04b20ad 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -113,7 +113,7 @@ struct group15 { return _mm_movemask_epi8( _mm_cmpeq_epi8( - _mm_loadu_si128(&m),_mm_set1_epi32(match_word(hash))))&0x7FFF; + m/*_mm_loadu_si128(&m)*/,_mm_set1_epi32(match_word(hash))))&0x7FFF; } inline bool is_not_overflowed(std::size_t hash)const @@ -131,7 +131,7 @@ struct group15 inline int match_available()const { return _mm_movemask_epi8( - _mm_cmpeq_epi8(_mm_loadu_si128(&m),_mm_setzero_si128()))&0x7FFF; + _mm_cmpeq_epi8(m/*_mm_loadu_si128(&m)*/,_mm_setzero_si128()))&0x7FFF; } inline int match_occupied()const From ac41bf6e864d513e5b5c0316749581011e6bd375 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 30 Sep 2022 16:09:14 +0200 Subject: [PATCH 055/279] temporarily reverted 6110a0827c3096315387a691af6623324aa53abb --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index b04b20ad..eb9bdb65 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1022,7 +1022,7 @@ private: static group_type* dummy_groups()noexcept { - static constexpr group_type::dummy_group_type storage[size_policy::min_size()]{}; + static constexpr group_type::dummy_group_type storage[size_policy::min_size()]; return reinterpret_cast( const_cast(storage)); } From 984cf13afd0e6072deed13142d79b348e68aa26e Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 30 Sep 2022 16:15:11 +0200 Subject: [PATCH 056/279] reintroduced 6110a0827c3096315387a691af6623324aa53abb with a slightly different syntax (prior caused ICEs on GCC11) --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index eb9bdb65..29aab28e 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1022,7 +1022,7 @@ private: static group_type* dummy_groups()noexcept { - static constexpr group_type::dummy_group_type storage[size_policy::min_size()]; + static constexpr group_type::dummy_group_type storage[size_policy::min_size()]={}; return reinterpret_cast( const_cast(storage)); } From d9dcaf8ba10bc2c4ad73ca8c4023c904b8531087 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 30 Sep 2022 16:17:40 +0200 Subject: [PATCH 057/279] tried different formulation of prior --- include/boost/unordered/detail/foa.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 29aab28e..e94b2e60 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1022,7 +1022,8 @@ private: static group_type* dummy_groups()noexcept { - static constexpr group_type::dummy_group_type storage[size_policy::min_size()]={}; + static constexpr group_type::dummy_group_type storage[size_policy::min_size()]= + {group_type::dummy_group_type(),}; return reinterpret_cast( const_cast(storage)); } From 36a42116e8a3e9e6e553f3d9c27a64de37f58aa0 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 30 Sep 2022 17:06:31 +0200 Subject: [PATCH 058/279] supported unaligned metadata access where potentially happening, plus fixed some superfluous alignas specifiers --- include/boost/unordered/detail/foa.hpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index e94b2e60..30e40ee1 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -72,13 +72,18 @@ namespace foa{ #if defined(BOOST_UNORDERED_SSE2) +template +using has_extended_align= + std::integral_constant alignof(std::max_align_t))>; + struct group15 { static constexpr int N=15; struct dummy_group_type { - alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; + alignas(__m128i) unsigned char storage[N+1]= + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; }; inline void set(std::size_t pos,std::size_t hash) @@ -112,8 +117,7 @@ struct group15 inline int match(std::size_t hash)const { return _mm_movemask_epi8( - _mm_cmpeq_epi8( - m/*_mm_loadu_si128(&m)*/,_mm_set1_epi32(match_word(hash))))&0x7FFF; + _mm_cmpeq_epi8(load(),_mm_set1_epi32(match_word(hash))))&0x7FFF; } inline bool is_not_overflowed(std::size_t hash)const @@ -131,7 +135,7 @@ struct group15 inline int match_available()const { return _mm_movemask_epi8( - _mm_cmpeq_epi8(m/*_mm_loadu_si128(&m)*/,_mm_setzero_si128()))&0x7FFF; + _mm_cmpeq_epi8(load(),_mm_setzero_si128()))&0x7FFF; } inline int match_occupied()const @@ -148,6 +152,10 @@ private: static constexpr unsigned char available_=0, sentinel_=1; + inline __m128i load()const{return load(has_extended_align<__m128i>());} + inline __m128i load(std::true_type)const{return _mm_loadu_si128(&m);} + inline __m128i load(std::false_type)const{return m;} + inline static int match_word(std::size_t hash) { static constexpr boost::uint32_t word[]= @@ -214,7 +222,7 @@ private: return at(N); } - /*alignas(16)*/ __m128i m; + __m128i m; }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) @@ -225,7 +233,8 @@ struct group15 struct dummy_group_type { - alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; + alignas(int8x16_t) unsigned char storage[N+1]= + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; }; inline void set(std::size_t pos,std::size_t hash) @@ -366,7 +375,7 @@ struct group15 struct dummy_group_type { - alignas(16) boost::uint64_t m[2]= + alignas(boost::uint64_t) boost::uint64_t m[2]= {0x0000000000004000ull,0x0000000000000000ull}; }; @@ -520,7 +529,7 @@ private: return y&0x7FFF; } - alignas(16) boost::uint64_t m[2]; + boost::uint64_t m[2]; }; #endif From cec09e1c61ed3cf222f2f5f5d20888eedb84aed5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 1 Oct 2022 12:44:33 +0200 Subject: [PATCH 059/279] fixed alignment issues apparent 32bit builds --- include/boost/unordered/detail/foa.hpp | 270 +++++++++++++++++-------- 1 file changed, 188 insertions(+), 82 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 30e40ee1..a2da0c0a 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -72,18 +72,13 @@ namespace foa{ #if defined(BOOST_UNORDERED_SSE2) -template -using has_extended_align= - std::integral_constant alignof(std::max_align_t))>; - struct group15 { static constexpr int N=15; struct dummy_group_type { - alignas(__m128i) unsigned char storage[N+1]= - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; + alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; }; inline void set(std::size_t pos,std::size_t hash) @@ -117,7 +112,7 @@ struct group15 inline int match(std::size_t hash)const { return _mm_movemask_epi8( - _mm_cmpeq_epi8(load(),_mm_set1_epi32(match_word(hash))))&0x7FFF; + _mm_cmpeq_epi8(m,_mm_set1_epi32(match_word(hash))))&0x7FFF; } inline bool is_not_overflowed(std::size_t hash)const @@ -135,7 +130,7 @@ struct group15 inline int match_available()const { return _mm_movemask_epi8( - _mm_cmpeq_epi8(load(),_mm_setzero_si128()))&0x7FFF; + _mm_cmpeq_epi8(m,_mm_setzero_si128()))&0x7FFF; } inline int match_occupied()const @@ -152,10 +147,6 @@ private: static constexpr unsigned char available_=0, sentinel_=1; - inline __m128i load()const{return load(has_extended_align<__m128i>());} - inline __m128i load(std::true_type)const{return _mm_loadu_si128(&m);} - inline __m128i load(std::false_type)const{return m;} - inline static int match_word(std::size_t hash) { static constexpr boost::uint32_t word[]= @@ -222,7 +213,7 @@ private: return at(N); } - __m128i m; + alignas(16) __m128i m; }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) @@ -233,8 +224,7 @@ struct group15 struct dummy_group_type { - alignas(int8x16_t) unsigned char storage[N+1]= - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; + alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; }; inline void set(std::size_t pos,std::size_t hash) @@ -364,7 +354,7 @@ private: return at(N); } - int8x16_t m; + alignas(16) int8x16_t m; }; #else /* non-SIMD */ @@ -375,7 +365,7 @@ struct group15 struct dummy_group_type { - alignas(boost::uint64_t) boost::uint64_t m[2]= + alignas(16) boost::uint64_t m[2]= {0x0000000000004000ull,0x0000000000000000ull}; }; @@ -483,7 +473,7 @@ private: set_impl(m[1],pos,n>>4); } - static inline void set_impl(boost::uint64_t& x,unsigned pos,unsigned n) + static inline void set_impl(boost::uint64_t& x,std::size_t pos,std::size_t n) { static constexpr boost::uint64_t mask[]= { @@ -529,7 +519,7 @@ private: return y&0x7FFF; } - boost::uint64_t m[2]; + alignas(16) boost::uint64_t m[2]; }; #endif @@ -670,6 +660,169 @@ private: Value *p=nullptr; }; +template +struct table_arrays_base +{ + template + static Arrays new_(Allocator& al,std::size_t n) + { + using group_type=typename Arrays::group_type; + static constexpr auto N=group_type::N; + using size_policy=typename Arrays::size_policy; + using alloc_traits=std::allocator_traits; + + auto groups_size_index=size_policy::size_index(n/N+1); + auto groups_size=size_policy::size(groups_size_index); + Arrays arrays{groups_size_index,groups_size-1}; + + if(!n){ + static constexpr typename group_type::dummy_group_type + storage[size_policy::min_size()]= + {typename group_type::dummy_group_type(),}; + + arrays.groups=reinterpret_cast( + const_cast(storage)); + } + else{ + arrays.allocate_groups(al,groups_size); + // TODO: explain why memset + std::memset( + arrays.groups,0,sizeof(group_type)*groups_size); + arrays.groups[groups_size-1].set_sentinel(); + BOOST_TRY{ + arrays.elements= + boost::to_address(alloc_traits::allocate(al,groups_size*N-1)); + } + BOOST_CATCH(...){ + arrays.deallocate_groups(al,groups_size); + BOOST_RETHROW; + } + BOOST_CATCH_END + } + return arrays; + } + + template + static void delete_(Allocator& al,Arrays& arrays)noexcept + { + using group_type=typename Arrays::group_type; + static constexpr auto N=group_type::N; + using alloc_traits=std::allocator_traits; + + if(arrays.elements){ + auto groups_size=arrays.groups_size_mask+1; + alloc_traits::deallocate(al,arrays.elements,groups_size*N-1); + arrays.deallocate_groups(al,groups_size); + } + } +}; + +template +struct aligned_table_arrays: + table_arrays_base> +{ + using group_type=Group; + using value_type=Value; + using size_policy=SizePolicy; + + aligned_table_arrays( + std::size_t groups_size_index_,std::size_t groups_size_mask_): + groups_size_index{groups_size_index_},groups_size_mask{groups_size_mask_} + {} + + template + void allocate_groups(Allocator& al,std::size_t groups_size) + { + using alloc_traits=std::allocator_traits; + using group_allocator= + typename alloc_traits::template rebind_alloc; + using group_alloc_traits=std::allocator_traits; + + group_allocator gal=al; + groups=boost::to_address(group_alloc_traits::allocate(gal,groups_size)); + } + + template + void deallocate_groups(Allocator& al,std::size_t groups_size) + { + using alloc_traits=std::allocator_traits; + using group_allocator= + typename alloc_traits::template rebind_alloc; + using group_alloc_traits=std::allocator_traits; + + group_allocator gal=al; + group_alloc_traits::deallocate(gal,groups,groups_size); + } + + std::size_t groups_size_index; + std::size_t groups_size_mask; + group_type *groups=nullptr; + value_type *elements=nullptr; +}; + +template +struct subaligned_table_arrays: + table_arrays_base> +{ + using group_type=Group; + using value_type=Value; + using size_policy=SizePolicy; + + subaligned_table_arrays( + std::size_t groups_size_index_,std::size_t groups_size_mask_): + groups_size_index{groups_size_index_},groups_size_mask{groups_size_mask_} + {} + + template + void allocate_groups(Allocator& al,std::size_t groups_size) + { + using alloc_traits=std::allocator_traits; + using byte_allocator= + typename alloc_traits::template rebind_alloc; + using byte_alloc_traits=std::allocator_traits; + + byte_allocator bal=al; + auto p=boost::to_address( + byte_alloc_traits::allocate(bal,sizeof(group_type)*(groups_size+1)-1)); + groups_offset= + (uintptr_t(sizeof(group_type))-reinterpret_cast(p))% + sizeof(group_type); + groups=reinterpret_cast(p+groups_offset); + } + + template + void deallocate_groups(Allocator& al,std::size_t groups_size) + { + using alloc_traits=std::allocator_traits; + using byte_allocator= + typename alloc_traits::template rebind_alloc; + using byte_alloc_traits=std::allocator_traits; + + byte_allocator bal=al; + byte_alloc_traits::deallocate( + bal,reinterpret_cast(groups)-groups_offset, + sizeof(group_type)*(groups_size+1)-1); + } + + std::size_t groups_size_index; + std::size_t groups_size_mask; + group_type *groups=nullptr; + value_type *elements=nullptr; + unsigned char groups_offset=0; +}; + +template +using table_arrays=typename std::conditional< + +#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) + sizeof(Group)<=__STDCPP_DEFAULT_NEW_ALIGNMENT__, +#else + sizeof(Group)<=alignof(std::max_align_t), +#endif + + aligned_table_arrays, + subaligned_table_arrays>::type; + template class table { @@ -729,7 +882,8 @@ public: table(const table& x,const Allocator& al_): h{x.h},pred{x.pred},al{al_},size_{0}, - arrays{new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))}, + arrays{ + new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))}, ml{max_load()} { BOOST_TRY{ @@ -986,65 +1140,16 @@ public: } private: - using group_allocator= - typename alloc_traits::template rebind_alloc; - using group_alloc_traits=std::allocator_traits; + using arrays_type=table_arrays; - struct arrays_info{ - std::size_t groups_size_index; - std::size_t groups_size_mask; - group_type *groups; - value_type *elements; - }; - - arrays_info new_arrays(std::size_t n) + arrays_type new_arrays(std::size_t n) { - auto groups_size_index=size_policy::size_index(n/N+1); - auto groups_size=size_policy::size(groups_size_index); - arrays_info new_arrays_{ - groups_size_index, - groups_size-1, - nullptr, - nullptr - }; - if(!n){ - new_arrays_.groups=dummy_groups(); - } - else{ - group_allocator gal=al; - new_arrays_.groups=boost::to_address(group_alloc_traits::allocate(gal,groups_size)); - // TODO: explain why memset - std::memset( - new_arrays_.groups,0,sizeof(group_type)*groups_size); - new_arrays_.groups[groups_size-1].set_sentinel(); - BOOST_TRY{ - new_arrays_.elements=boost::to_address(alloc_traits::allocate(al,groups_size*N-1)); - } - BOOST_CATCH(...){ - group_alloc_traits::deallocate(gal,new_arrays_.groups,groups_size); - BOOST_RETHROW; - } - BOOST_CATCH_END - } - return new_arrays_; + return arrays_type::new_(al,n); } - static group_type* dummy_groups()noexcept + void delete_arrays(arrays_type& arrays_)noexcept { - static constexpr group_type::dummy_group_type storage[size_policy::min_size()]= - {group_type::dummy_group_type(),}; - return reinterpret_cast( - const_cast(storage)); - } - - void delete_arrays(const arrays_info& arrays_)noexcept - { - if(arrays_.elements){ - auto groups_size=arrays_.groups_size_mask+1; - alloc_traits::deallocate(al,arrays_.elements,groups_size*N-1); - group_allocator gal=al; - group_alloc_traits::deallocate(gal,arrays_.groups,groups_size); - } + arrays_type::delete_(al,arrays_); } template @@ -1092,7 +1197,7 @@ private: } static inline std::size_t position_for( - std::size_t hash,const arrays_info& arrays_) + std::size_t hash,const arrays_type& arrays_) { return size_policy::position(hash,arrays_.groups_size_index); } @@ -1150,7 +1255,8 @@ private: return {it,false}; } else if(BOOST_UNLIKELY(size_>=ml)){ - unchecked_rehash(std::size_t(std::ceil(static_cast(size_+1)/mlf))); + unchecked_rehash( + std::size_t(std::ceil(static_cast(size_+1)/mlf))); pos0=position_for(hash); } return { @@ -1202,7 +1308,7 @@ private: unchecked_emplace_at(position_for(hash),hash,std::forward(x)); } - void nosize_transfer_element(value_type* p,const arrays_info& arrays_) + void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { auto hash=h(key_from(*p)); nosize_unchecked_emplace_at( @@ -1223,7 +1329,7 @@ private: #if 0 template iterator nosize_unchecked_emplace_at( - const arrays_info& arrays_,std::size_t pos0,std::size_t hash, + const arrays_type& arrays_,std::size_t pos0,std::size_t hash, Args&&... args) { auto pn=insert_position(arrays_,pos0,hash); @@ -1238,7 +1344,7 @@ private: std::pair static insert_position( - const arrays_info& arrays_,std::size_t pos0,std::size_t hash) + const arrays_type& arrays_,std::size_t pos0,std::size_t hash) { for(prober pb(pos0);;pb.next(arrays_.groups_size_mask)){ auto pos=pb.get(); @@ -1253,7 +1359,7 @@ private: #else template iterator nosize_unchecked_emplace_at( - const arrays_info& arrays_,std::size_t pos0,std::size_t hash, + const arrays_type& arrays_,std::size_t pos0,std::size_t hash, Args&&... args) { for(prober pb(pos0);;pb.next(arrays_.groups_size_mask)){ @@ -1279,7 +1385,7 @@ private: } template - static void for_all_elements(const arrays_info& arrays_,F f) + static void for_all_elements(const arrays_type& arrays_,F f) { auto pg=arrays_.groups; auto p=arrays_.elements; @@ -1299,7 +1405,7 @@ private: Allocator al; static constexpr float mlf=0.875; std::size_t size_; - arrays_info arrays; + arrays_type arrays; std::size_t ml; }; From 29f2f1db2cd6678de02bf4d803ebb01d15f7324a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 1 Oct 2022 12:58:37 +0200 Subject: [PATCH 060/279] added missing BOOST_RETHROWs --- include/boost/unordered/detail/foa.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index a2da0c0a..2e4ca497 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -695,7 +695,7 @@ struct table_arrays_base } BOOST_CATCH(...){ arrays.deallocate_groups(al,groups_size); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END } @@ -894,6 +894,7 @@ public: BOOST_CATCH(...){ clear(); delete_arrays(arrays); + BOOST_RETHROW } BOOST_CATCH_END } @@ -924,6 +925,7 @@ public: clear(); delete_arrays(arrays); x.clear(); + BOOST_RETHROW } BOOST_CATCH_END x.clear(); @@ -987,6 +989,7 @@ public: } BOOST_CATCH(...){ x.clear(); + BOOST_RETHROW } BOOST_CATCH_END x.clear(); @@ -1293,7 +1296,7 @@ private: destroy_element(p); }); delete_arrays(new_arrays_); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END delete_arrays(arrays); From f2e4b25615566c737ed93a76089fa480733c4c8c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 1 Oct 2022 17:33:55 +0200 Subject: [PATCH 061/279] silenced conversion warning --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2e4ca497..20f3f7d1 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -784,9 +784,9 @@ struct subaligned_table_arrays: byte_allocator bal=al; auto p=boost::to_address( byte_alloc_traits::allocate(bal,sizeof(group_type)*(groups_size+1)-1)); - groups_offset= + groups_offset=static_cast( (uintptr_t(sizeof(group_type))-reinterpret_cast(p))% - sizeof(group_type); + sizeof(group_type)); groups=reinterpret_cast(p+groups_offset); } From b244b3340227ea53832c589f7c1ff11da7efba50 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 1 Oct 2022 19:34:33 +0200 Subject: [PATCH 062/279] EBO-optimized table --- include/boost/unordered/detail/foa.hpp | 112 +++++++++++++++++-------- 1 file changed, 76 insertions(+), 36 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 20f3f7d1..cafeb0da 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -823,9 +824,41 @@ using table_arrays=typename std::conditional< aligned_table_arrays, subaligned_table_arrays>::type; -template -class table +template +struct ebo_base { + T& get(){return x;} + const T& get()const{return x;} + + T x; +}; + +template +struct ebo_base< + I,T, + typename std::enable_if< + std::is_class::value&&!boost::is_final::value>::type +>:T +{ + template + ebo_base(Arg&& x):T{std::forward(x)}{} + + T& get(){return *this;} + const T& get()const{return *this;} +}; + +template +class + +#if defined(_MSC_VER)&&_MSC_FULL_VER>=190023918 +__declspec(empty_bases) +#endif + +table:ebo_base<0,Hash>,ebo_base<1,Pred>,ebo_base<2,Allocator> +{ + using hash_base=ebo_base<0,Hash>; + using pred_base=ebo_base<1,Pred>; + using allocator_base=ebo_base<2,Allocator>; using type_policy=TypePolicy; using group_type=group15; static constexpr auto N=group_type::N; @@ -860,11 +893,12 @@ public: table( std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(), const Allocator& al_=Allocator()): - h{h_},pred{pred_},al{al_},size_{0},arrays{new_arrays(n)},ml{max_load()} + hash_base{h_},pred_base{pred_},allocator_base{al_}, + size_{0},arrays{new_arrays(n)},ml{max_load()} {} table(const table& x): - table(x,alloc_traits::select_on_container_copy_construction(x.al)){} + table(x,alloc_traits::select_on_container_copy_construction(x.al())){} table(table&& x) noexcept( @@ -872,8 +906,8 @@ public: std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value): // TODO verify if we should copy or move copy hash, pred and al - h{std::move(x.h)},pred{std::move(x.pred)},al{std::move(x.al)}, - size_{x.size_},arrays{x.arrays},ml{x.ml} + hash_base{std::move(x.h())},pred_base{std::move(x.pred())}, + allocator_base{std::move(x.al())},size_{x.size_},arrays{x.arrays},ml{x.ml} { x.size_=0; x.arrays=x.new_arrays(0); @@ -881,7 +915,7 @@ public: } table(const table& x,const Allocator& al_): - h{x.h},pred{x.pred},al{al_},size_{0}, + hash_base{x.h()},pred_base{x.pred()},allocator_base{al_},size_{0}, arrays{ new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))}, ml{max_load()} @@ -900,9 +934,9 @@ public: } table(table&& x,const Allocator& al_): - table{0,std::move(x.h),std::move(x.pred),al_} + table{0,std::move(x.h()),std::move(x.pred()),al_} { - if(al==x.al){ + if(al()==x.al()){ size_=x.size_; arrays=x.arrays; ml=x.ml; @@ -942,11 +976,11 @@ public: { if(this!=&x){ clear(); - h=x.h; - pred=x.pred; + h()=x.h(); + pred()=x.pred(); if(alloc_traits::propagate_on_container_copy_assignment::value){ - if(al!=x.al)reserve(0); - al=x.al; + if(al()!=x.al())reserve(0); + al()=x.al(); } // TODO may shrink arrays and miss an opportunity for memory reuse reserve(x.size()); @@ -967,14 +1001,14 @@ public: // TODO explain why not constexpr auto pocma=alloc_traits::propagate_on_container_move_assignment::value; clear(); - h=std::move(x.h); - pred=std::move(x.pred); - if(pocma||al==x.al){ + h()=std::move(x.h()); + pred()=std::move(x.pred()); + if(pocma||al()==x.al()){ using std::swap; reserve(0); swap(arrays,x.arrays); swap(ml,x.ml); - if(pocma)al=std::move(x.al); + if(pocma)al()=std::move(x.al()); } else{ reserve(x.size()); @@ -998,7 +1032,7 @@ public: return *this; } - allocator_type get_allocator()const noexcept{return al;} + allocator_type get_allocator()const noexcept{return al();} iterator begin()noexcept { @@ -1076,10 +1110,10 @@ public: boost::is_nothrow_swappable::value) { using std::swap; - swap(h,x.h); - swap(pred,x.pred); - if(alloc_traits::propagate_on_container_swap::value)swap(al,x.al); - else BOOST_ASSERT(al==x.al); + swap(h(),x.h()); + swap(pred(),x.pred()); + if(alloc_traits::propagate_on_container_swap::value)swap(al(),x.al()); + else BOOST_ASSERT(al()==x.al()); swap(size_,x.size_); swap(arrays,x.arrays); swap(ml,x.ml); @@ -1104,13 +1138,13 @@ public: size_=0; } - hasher hash_function()const{return h;} - key_equal key_eq()const{return pred;} + hasher hash_function()const{return h();} + key_equal key_eq()const{return pred();} template BOOST_FORCEINLINE iterator find(const Key& x) { - auto hash=h(x); + auto hash=h()(x); return find_impl(x,position_for(hash),hash); } @@ -1145,25 +1179,34 @@ public: private: using arrays_type=table_arrays; + Hash& h(){return static_cast(this)->get();} + const Hash& h()const{return static_cast(this)->get();} + Pred& pred(){return static_cast(this)->get();} + const Pred& pred()const + {return static_cast(this)->get();} + Allocator& al(){return static_cast(this)->get();} + const Allocator& al()const + {return static_cast(this)->get();} + arrays_type new_arrays(std::size_t n) { - return arrays_type::new_(al,n); + return arrays_type::new_(al(),n); } void delete_arrays(arrays_type& arrays_)noexcept { - arrays_type::delete_(al,arrays_); + arrays_type::delete_(al(),arrays_); } template void construct_element(value_type* p,Args&&... args) { - alloc_traits::construct(al,p,std::forward(args)...); + alloc_traits::construct(al(),p,std::forward(args)...); } void destroy_element(value_type* p)noexcept { - alloc_traits::destroy(al,p); + alloc_traits::destroy(al(),p); } std::size_t max_load()const @@ -1232,7 +1275,7 @@ private: prefetch_elements(p); do{ auto n=unchecked_countr_zero(mask); - if(BOOST_LIKELY(pred(x,key_from(p[n])))){ + if(BOOST_LIKELY(pred()(x,key_from(p[n])))){ return {pg,n,p+n}; } mask&=mask-1; @@ -1250,7 +1293,7 @@ private: BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { const auto &k=key_from(std::forward(args)...); - auto hash=h(k); + auto hash=h()(k); auto pos0=position_for(hash); auto it=find_impl(k,pos0,hash); @@ -1307,13 +1350,13 @@ private: template void unchecked_insert(Value&& x) { - auto hash=h(key_from(x)); + auto hash=h()(key_from(x)); unchecked_emplace_at(position_for(hash),hash,std::forward(x)); } void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { - auto hash=h(key_from(*p)); + auto hash=h()(key_from(*p)); nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash,std::move(*p)); destroy_element(p); @@ -1403,9 +1446,6 @@ private: } } - Hash h; - Pred pred; - Allocator al; static constexpr float mlf=0.875; std::size_t size_; arrays_type arrays; From b926dbbbe9519a90e0a984c20f8c57f514b9dd9c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 1 Oct 2022 19:37:16 +0200 Subject: [PATCH 063/279] eliminated shadowed declaration --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index cafeb0da..52a1bfb6 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1255,7 +1255,7 @@ private: // TODO: check if this is 128 in current benchmark machine const char *p0=reinterpret_cast(p), *p1=p0+sizeof(value_type)*N/2; - for(auto p=p0;p Date: Sun, 2 Oct 2022 11:13:04 +0200 Subject: [PATCH 064/279] shut down unavoidable GCC shadowing warnings --- include/boost/unordered/detail/foa.hpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 52a1bfb6..6085ea77 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -847,6 +847,28 @@ struct ebo_base< const T& get()const{return *this;} }; +#if defined(BOOST_GCC) +/* GCC's -Wshadow triggers at scenarios like this: + * + * struct foo{}; + * template + * struct derived:Base + * { + * void f(){int foo;} + * }; + * + * derivedx; + * x.f(); // declaration of "foo" in derived::f shadows base type "foo" + * + * This makes shadowing warnings unavoidable in general when a class template + * derives from user-provided classes, as is the case with table and + * ebo_base's below. + */ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#endif + template class @@ -1452,6 +1474,10 @@ private: std::size_t ml; }; +#if defined(BOOST_GCC) +#pragma GCC diagnostic pop /* ignored "-Wshadow" */ +#endif + } /* namespace foa */ } /* namespace detail */ } /* namespace unordered */ From 4dbc83ccbf5709b884376747fd3426084681c17b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 2 Oct 2022 11:13:49 +0200 Subject: [PATCH 065/279] documented VS specific bit --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 6085ea77..c7603ee2 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -873,7 +873,7 @@ template class #if defined(_MSC_VER)&&_MSC_FULL_VER>=190023918 -__declspec(empty_bases) +__declspec(empty_bases) /* activate EBO with multiple inheritance */ #endif table:ebo_base<0,Hash>,ebo_base<1,Pred>,ebo_base<2,Allocator> From 621b5b4ec1f48ee22eb17c87f9a8a9b5c833e54a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 2 Oct 2022 11:14:19 +0200 Subject: [PATCH 066/279] shut down bogus VS warning --- include/boost/unordered/detail/foa.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c7603ee2..1f4ec897 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1013,6 +1013,11 @@ public: return *this; } +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4297) /* throw inside noexcept function */ +#endif + table& operator=(table&& x) noexcept( alloc_traits::is_always_equal::value&& @@ -1054,6 +1059,10 @@ public: return *this; } +#if defined(BOOST_MSVC) +#pragma warning(pop) /* C4297 */ +#endif + allocator_type get_allocator()const noexcept{return al();} iterator begin()noexcept From 5c48ad9a7992dee4629968b1804bbcc8d89da9ea Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 3 Oct 2022 08:08:02 -0700 Subject: [PATCH 067/279] Update test Jamfile to use cxx14_constexpr as a requirement for targets so msvc gets run --- test/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ca746a62..888e3b7d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -7,7 +7,7 @@ import testing ; import ../../config/checks/config : requires ; -CPP14 = [ requires cxx14 ] ; +CPP14 = [ requires cxx14_constexpr ] ; # Adding -Wundef is blocked on (at least) # https://github.com/boostorg/type_traits/issues/165 From d370ae1095e3b889dbf0cf4e15395f472e9377a4 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 3 Oct 2022 18:49:24 +0200 Subject: [PATCH 068/279] stopped relying on __STDCPP_DEFAULT_NEW_ALIGNMENT__ for now --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 1f4ec897..3da7554f 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -815,7 +815,7 @@ struct subaligned_table_arrays: template using table_arrays=typename std::conditional< -#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) +#if 0&&defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) sizeof(Group)<=__STDCPP_DEFAULT_NEW_ALIGNMENT__, #else sizeof(Group)<=alignof(std::max_align_t), From 357eed44a105e39e67259676386236376d0d31a1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 3 Oct 2022 19:36:53 +0200 Subject: [PATCH 069/279] replaced homegrown ebo_base with boost::empty_value --- include/boost/unordered/detail/foa.hpp | 63 +++++++++----------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3da7554f..7a53c38f 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -14,11 +14,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -824,29 +824,6 @@ using table_arrays=typename std::conditional< aligned_table_arrays, subaligned_table_arrays>::type; -template -struct ebo_base -{ - T& get(){return x;} - const T& get()const{return x;} - - T x; -}; - -template -struct ebo_base< - I,T, - typename std::enable_if< - std::is_class::value&&!boost::is_final::value>::type ->:T -{ - template - ebo_base(Arg&& x):T{std::forward(x)}{} - - T& get(){return *this;} - const T& get()const{return *this;} -}; - #if defined(BOOST_GCC) /* GCC's -Wshadow triggers at scenarios like this: * @@ -862,7 +839,7 @@ struct ebo_base< * * This makes shadowing warnings unavoidable in general when a class template * derives from user-provided classes, as is the case with table and - * ebo_base's below. + * empty_value's below. */ #pragma GCC diagnostic push @@ -876,11 +853,11 @@ class __declspec(empty_bases) /* activate EBO with multiple inheritance */ #endif -table:ebo_base<0,Hash>,ebo_base<1,Pred>,ebo_base<2,Allocator> +table:empty_value,empty_value,empty_value { - using hash_base=ebo_base<0,Hash>; - using pred_base=ebo_base<1,Pred>; - using allocator_base=ebo_base<2,Allocator>; + using hash_base=empty_value; + using pred_base=empty_value; + using allocator_base=empty_value; using type_policy=TypePolicy; using group_type=group15; static constexpr auto N=group_type::N; @@ -915,8 +892,9 @@ public: table( std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(), const Allocator& al_=Allocator()): - hash_base{h_},pred_base{pred_},allocator_base{al_}, - size_{0},arrays{new_arrays(n)},ml{max_load()} + hash_base{empty_init,h_},pred_base{empty_init,pred_}, + allocator_base{empty_init,al_},size_{0},arrays{new_arrays(n)}, + ml{max_load()} {} table(const table& x): @@ -928,8 +906,10 @@ public: std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value): // TODO verify if we should copy or move copy hash, pred and al - hash_base{std::move(x.h())},pred_base{std::move(x.pred())}, - allocator_base{std::move(x.al())},size_{x.size_},arrays{x.arrays},ml{x.ml} + hash_base{empty_init,std::move(x.h())}, + pred_base{empty_init,std::move(x.pred())}, + allocator_base{empty_init,std::move(x.al())}, + size_{x.size_},arrays{x.arrays},ml{x.ml} { x.size_=0; x.arrays=x.new_arrays(0); @@ -937,7 +917,8 @@ public: } table(const table& x,const Allocator& al_): - hash_base{x.h()},pred_base{x.pred()},allocator_base{al_},size_{0}, + hash_base{empty_init,x.h()},pred_base{empty_init,x.pred()}, + allocator_base{empty_init,al_},size_{0}, arrays{ new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))}, ml{max_load()} @@ -1210,14 +1191,12 @@ public: private: using arrays_type=table_arrays; - Hash& h(){return static_cast(this)->get();} - const Hash& h()const{return static_cast(this)->get();} - Pred& pred(){return static_cast(this)->get();} - const Pred& pred()const - {return static_cast(this)->get();} - Allocator& al(){return static_cast(this)->get();} - const Allocator& al()const - {return static_cast(this)->get();} + Hash& h(){return hash_base::get();} + const Hash& h()const{return hash_base::get();} + Pred& pred(){return pred_base::get();} + const Pred& pred()const{return pred_base::get();} + Allocator& al(){return allocator_base::get();} + const Allocator& al()const{return allocator_base::get();} arrays_type new_arrays(std::size_t n) { From 2e3a8a0fc01c739211e532633bbbf223ad567189 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 3 Oct 2022 21:05:48 +0200 Subject: [PATCH 070/279] avoided VS warning C4706 --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 7a53c38f..f82e89c5 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -643,7 +643,7 @@ private: pc+=sizeof(Group); p+=Group::N; } - while(!(mask=reinterpret_cast(pc)->match_occupied())); + while((mask=reinterpret_cast(pc)->match_occupied())!=0); } auto n=unchecked_countr_zero(mask); From b0097982af4af66536de73fc0b263d877aec8ef6 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 3 Oct 2022 12:17:46 -0700 Subject: [PATCH 071/279] Remove config checks, just rotely disable tests for unsupported C++ versions --- test/Jamfile.v2 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 888e3b7d..ebe96439 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -5,9 +5,6 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) import testing ; -import ../../config/checks/config : requires ; - -CPP14 = [ requires cxx14_constexpr ] ; # Adding -Wundef is blocked on (at least) # https://github.com/boostorg/type_traits/issues/165 @@ -48,13 +45,10 @@ run unordered/incomplete_test.cpp ; run unordered/simple_tests.cpp ; run unordered/equivalent_keys_tests.cpp ; run unordered/constructor_tests.cpp ; -run unordered/constructor_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; run unordered/copy_tests.cpp ; -run unordered/copy_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; run unordered/move_tests.cpp ; run unordered/assign_tests.cpp ; run unordered/insert_tests.cpp ; -run unordered/insert_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; run unordered/insert_stable_tests.cpp ; run unordered/insert_hint_tests.cpp ; run unordered/emplace_tests.cpp ; @@ -69,7 +63,6 @@ compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTIM compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_SET : insert_node_type_fail_set ; compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ; run unordered/find_tests.cpp ; -run unordered/find_tests.cpp : : : $(CPP14) BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; run unordered/at_tests.cpp ; run unordered/bucket_tests.cpp ; run unordered/load_factor_tests.cpp ; @@ -102,3 +95,8 @@ run exception/swap_exception_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD run exception/merge_exception_tests.cpp ; run quick.cpp ; + +run unordered/constructor_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; +run unordered/copy_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; +run unordered/insert_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; +run unordered/find_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; From d5fcc77579f12796f449ac98d47596ca8935e25e Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 3 Oct 2022 14:45:02 -0700 Subject: [PATCH 072/279] Add assign_tests --- test/Jamfile.v2 | 1 + test/unordered/assign_tests.cpp | 63 ++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ebe96439..3137d16a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -98,5 +98,6 @@ run quick.cpp ; run unordered/constructor_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; run unordered/copy_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; +run unordered/assign_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_assign_tests ; run unordered/insert_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; run unordered/find_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index fddb40c3..ef54b01e 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -5,8 +5,13 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -201,6 +206,54 @@ namespace assign_tests { } } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + template bool is_propagate(T*) + { + return T::allocator_type::is_propagate_on_assign; + } + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map >* test_map_std_alloc; + + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map >* test_map; + + boost::unordered_flat_set >* + test_set_prop_assign; + boost::unordered_flat_map >* + test_map_prop_assign; + + boost::unordered_flat_set >* + test_set_no_prop_assign; + boost::unordered_flat_map >* + test_map_no_prop_assign; + + UNORDERED_AUTO_TEST (check_traits) { + BOOST_TEST(!is_propagate(test_set)); + BOOST_TEST(is_propagate(test_set_prop_assign)); + BOOST_TEST(!is_propagate(test_set_no_prop_assign)); + } + + UNORDERED_TEST(assign_tests1, + ((test_map_std_alloc)(test_set)(test_map)(test_set_prop_assign)(test_map_prop_assign)(test_set_no_prop_assign)(test_map_no_prop_assign))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(assign_tests2, + ((test_set)(test_map)(test_set_prop_assign)(test_map_prop_assign)(test_set_no_prop_assign)(test_map_no_prop_assign))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_map >* test_map_std_alloc; @@ -241,15 +294,6 @@ namespace assign_tests { test::cxx11_allocator >* test_multimap_no_prop_assign; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - - template bool is_propagate(T*) - { - return T::allocator_type::is_propagate_on_assign; - } - UNORDERED_AUTO_TEST (check_traits) { BOOST_TEST(!is_propagate(test_set)); BOOST_TEST(is_propagate(test_set_prop_assign)); @@ -271,6 +315,7 @@ namespace assign_tests { test_set_no_prop_assign)(test_multiset_no_prop_assign)( test_map_no_prop_assign)(test_multimap_no_prop_assign))( (default_generator)(generate_collisions)(limited_range))) +#endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) From bf6e381ff286d23531dbaf4f7a83fd4ca5ca9147 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 3 Oct 2022 14:45:42 -0700 Subject: [PATCH 073/279] Add expliicit destructors, copy assignment operators --- include/boost/unordered/unordered_flat_map.hpp | 10 ++++++++++ include/boost/unordered/unordered_flat_set.hpp | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index b7106e24..64df3a33 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -97,6 +97,16 @@ namespace boost { { } + ~unordered_flat_map() = default; + + unordered_flat_map& operator=(unordered_flat_map const& other) + { + if (this != &other) { + table_ = other.table_; + } + return *this; + } + allocator_type get_allocator() const noexcept { return table_.get_allocator(); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 3a1f5178..96aaf699 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -96,6 +96,16 @@ namespace boost { { } + ~unordered_flat_set() = default; + + unordered_flat_set& operator=(unordered_flat_set const& other) + { + if (this != &other) { + table_ = other.table_; + } + return *this; + } + allocator_type get_allocator() const noexcept { return table_.get_allocator(); From b0c03844016437595bf1b124b62d1ffe41c36586 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 3 Oct 2022 14:46:19 -0700 Subject: [PATCH 074/279] Fix small typo in `increment()` function to silence VS warnings --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f82e89c5..c5e48819 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -643,7 +643,7 @@ private: pc+=sizeof(Group); p+=Group::N; } - while((mask=reinterpret_cast(pc)->match_occupied())!=0); + while((mask=reinterpret_cast(pc)->match_occupied())==0); } auto n=unchecked_countr_zero(mask); From ddb9f370af0420be5f380e7e0f54bcd909edc740 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 3 Oct 2022 14:46:45 -0700 Subject: [PATCH 075/279] Update load_factor() impl to handle the case when capacity() is zero --- include/boost/unordered/detail/foa.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c5e48819..7f3b7dde 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1171,7 +1171,12 @@ public: return arrays.elements?(arrays.groups_size_mask+1)*N-1:0; } - float load_factor()const noexcept{return float(size())/float(capacity());} + float load_factor()const noexcept + { + if (capacity() == 0) { return 0; } + return float(size())/float(capacity()); + } + float max_load_factor()const noexcept{return mlf;} void rehash(std::size_t n) From bdfe294e61ff9442495a56c89d1050cdbab8601f Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 3 Oct 2022 14:47:41 -0700 Subject: [PATCH 076/279] Add temporary polyfill for foa table's assignment operator so that the definition of the allocator copy-assignment operator isn't required --- include/boost/unordered/detail/foa.hpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 7f3b7dde..1ea4b3e0 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -975,16 +975,31 @@ public: delete_arrays(arrays); } + template + typename std::enable_if< + !AllocTraits::propagate_on_container_copy_assignment::value, + void + >::type + copy_assign_helper(const table&) {} + + template + typename std::enable_if< + AllocTraits::propagate_on_container_copy_assignment::value, + void + >::type + copy_assign_helper(const table& x) + { + if(al()!=x.al())reserve(0); + al()=x.al(); + } + table& operator=(const table& x) { if(this!=&x){ clear(); h()=x.h(); pred()=x.pred(); - if(alloc_traits::propagate_on_container_copy_assignment::value){ - if(al()!=x.al())reserve(0); - al()=x.al(); - } + copy_assign_helper(x); // TODO may shrink arrays and miss an opportunity for memory reuse reserve(x.size()); x.for_all_elements([this](value_type* p){ From 06512a00e18e3d348d88113ac30a4a499271258b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 4 Oct 2022 11:24:21 +0200 Subject: [PATCH 077/279] refactored bdfe294e61ff9442495a56c89d1050cdbab8601f and expanded to move assign and swap --- include/boost/unordered/detail/foa.hpp | 70 +++++++++++++++++--------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 1ea4b3e0..2ec0892f 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -824,6 +824,32 @@ using table_arrays=typename std::conditional< aligned_table_arrays, subaligned_table_arrays>::type; +struct if_constexpr_void_else{void operator()()const{}}; + +template +void if_constexpr(F f,G g={}) +{ + std::get(std::forward_as_tuple(f,g))(); +} + +template::type* =nullptr> +void copy_assign_if(T& x,const T& y){x=y;} + +template::type* =nullptr> +void copy_assign_if(T& x,const T& y){} + +template::type* =nullptr> +void move_assign_if(T& x,T& y){x=std::move(y);} + +template::type* =nullptr> +void move_assign_if(T& x,T& y){} + +template::type* =nullptr> +void swap_if(T& x,T& y){using std::swap; swap(x,y);} + +template::type* =nullptr> +void swap_if(T& x,T& y){} + #if defined(BOOST_GCC) /* GCC's -Wshadow triggers at scenarios like this: * @@ -975,31 +1001,19 @@ public: delete_arrays(arrays); } - template - typename std::enable_if< - !AllocTraits::propagate_on_container_copy_assignment::value, - void - >::type - copy_assign_helper(const table&) {} - - template - typename std::enable_if< - AllocTraits::propagate_on_container_copy_assignment::value, - void - >::type - copy_assign_helper(const table& x) - { - if(al()!=x.al())reserve(0); - al()=x.al(); - } - table& operator=(const table& x) { + static constexpr auto pocca= + alloc_traits::propagate_on_container_copy_assignment::value; + if(this!=&x){ clear(); h()=x.h(); pred()=x.pred(); - copy_assign_helper(x); + if_constexpr([&,this]{ + if(al()!=x.al())reserve(0); + copy_assign_if(al(),x.al()); + }); // TODO may shrink arrays and miss an opportunity for memory reuse reserve(x.size()); x.for_all_elements([this](value_type* p){ @@ -1020,9 +1034,10 @@ public: std::is_nothrow_move_assignable::value&& std::is_nothrow_move_assignable::value) { + static constexpr auto pocma= + alloc_traits::propagate_on_container_move_assignment::value; + if(this!=&x){ - // TODO explain why not constexpr - auto pocma=alloc_traits::propagate_on_container_move_assignment::value; clear(); h()=std::move(x.h()); pred()=std::move(x.pred()); @@ -1031,7 +1046,7 @@ public: reserve(0); swap(arrays,x.arrays); swap(ml,x.ml); - if(pocma)al()=std::move(x.al()); + move_assign_if(al(),x.al()); } else{ reserve(x.size()); @@ -1136,11 +1151,18 @@ public: boost::is_nothrow_swappable::value&& boost::is_nothrow_swappable::value) { + static constexpr auto pocs= + alloc_traits::propagate_on_container_swap::value; + using std::swap; swap(h(),x.h()); swap(pred(),x.pred()); - if(alloc_traits::propagate_on_container_swap::value)swap(al(),x.al()); - else BOOST_ASSERT(al()==x.al()); + if_constexpr([&,this]{ + swap_if(al(),x.al()); + }, + [&,this]{ /* else */ + BOOST_ASSERT(al()==x.al()); + }); swap(size_,x.size_); swap(arrays,x.arrays); swap(ml,x.ml); From e69bb3aece736b24b60880cc37a9d61f02df1b38 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 4 Oct 2022 13:46:27 +0200 Subject: [PATCH 078/279] unnamed unused parameters --- include/boost/unordered/detail/foa.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2ec0892f..5d8d81b2 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -836,19 +836,19 @@ template::type* =nullptr> void copy_assign_if(T& x,const T& y){x=y;} template::type* =nullptr> -void copy_assign_if(T& x,const T& y){} +void copy_assign_if(T&,const T&){} template::type* =nullptr> void move_assign_if(T& x,T& y){x=std::move(y);} template::type* =nullptr> -void move_assign_if(T& x,T& y){} +void move_assign_if(T&,T&){} template::type* =nullptr> void swap_if(T& x,T& y){using std::swap; swap(x,y);} template::type* =nullptr> -void swap_if(T& x,T& y){} +void swap_if(T&,T&){} #if defined(BOOST_GCC) /* GCC's -Wshadow triggers at scenarios like this: From b7e021ffc66d5003b86d00ee16ea6af36c777ab1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 4 Oct 2022 18:47:23 +0200 Subject: [PATCH 079/279] silenced VS warning C4714 --- include/boost/unordered/detail/foa.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 5d8d81b2..755c8cca 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -872,6 +872,11 @@ void swap_if(T&,T&){} #pragma GCC diagnostic ignored "-Wshadow" #endif +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4714) /* marked as __forceinline not inlined */ +#endif + template class @@ -1504,6 +1509,10 @@ private: std::size_t ml; }; +#if defined(BOOST_MSVC) +#pragma warning(pop) /* C4714 */ +#endif + #if defined(BOOST_GCC) #pragma GCC diagnostic pop /* ignored "-Wshadow" */ #endif From 21872edf83688e3751ec5d2cffe1c8e2d65c6776 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 10:47:03 -0700 Subject: [PATCH 080/279] Disable FOA tests for C++98 --- test/Jamfile.v2 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3137d16a..efd9ad63 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -96,8 +96,8 @@ run exception/merge_exception_tests.cpp ; run quick.cpp ; -run unordered/constructor_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; -run unordered/copy_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; -run unordered/assign_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_assign_tests ; -run unordered/insert_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; -run unordered/find_tests.cpp : : : 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; +run unordered/constructor_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; +run unordered/copy_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; +run unordered/assign_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_assign_tests ; +run unordered/insert_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; +run unordered/find_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; From 9280e136971f67c1a40e1e96f65aa4717fe84829 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 10:56:26 -0700 Subject: [PATCH 081/279] Add erase_tests --- test/Jamfile.v2 | 1 + test/unordered/erase_tests.cpp | 44 ++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index efd9ad63..c16d4b26 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -100,4 +100,5 @@ run unordered/constructor_tests.cpp : : : 98:no 03:98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; run unordered/assign_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_assign_tests ; run unordered/insert_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; +run unordered/erase_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_erase_tests ; run unordered/find_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index fecb7dc0..e79d83e9 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -5,8 +5,13 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -27,7 +32,9 @@ namespace erase_tests { template void erase_tests1(Container*, test::random_generator generator) { +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename Container::iterator iterator; +#endif typedef typename Container::const_iterator c_iterator; BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase by key.\n"; @@ -61,9 +68,13 @@ namespace erase_tests { while (size > 0 && !x.empty()) { typename Container::key_type key = test::get_key(*x.begin()); std::size_t count = x.count(key); +#ifdef BOOST_UNORDERED_FOA_TESTS + x.erase(x.begin()); +#else iterator pos = x.erase(x.begin()); - --size; BOOST_TEST(pos == x.begin()); +#endif + --size; BOOST_TEST(x.count(key) == count - 1); BOOST_TEST(x.size() == size); if (++iterations % 20 == 0) @@ -93,10 +104,15 @@ namespace erase_tests { typename Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); BOOST_TEST(count > 0); +#ifdef BOOST_UNORDERED_FOA_TESTS + x.erase(pos); + --size; +#else BOOST_TEST(next == x.erase(pos)); --size; if (size > 0) BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev)); +#endif BOOST_TEST(x.count(key) == count - 1); if (x.count(key) != count - 1) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => " << x.count(key) @@ -185,7 +201,11 @@ namespace erase_tests { while (size > 0 && !x.empty()) { typename Container::key_type key = test::get_key(*x.begin()); std::size_t count = x.count(key); +#ifdef BOOST_UNORDERED_FOA_TESTS + x.erase(x.begin()); +#else x.quick_erase(x.begin()); +#endif --size; BOOST_TEST(x.count(key) == count - 1); BOOST_TEST(x.size() == size); @@ -216,7 +236,11 @@ namespace erase_tests { typename Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); BOOST_TEST(count > 0); +#ifdef BOOST_UNORDERED_FOA_TESTS + x.erase(pos); +#else x.quick_erase(pos); +#endif --size; if (size > 0) BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev)); @@ -246,6 +270,20 @@ namespace erase_tests { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map >* test_map; + + UNORDERED_TEST( + erase_tests1, ((test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_set >* test_set; boost::unordered_multiset >* test_multimap; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; UNORDERED_TEST( erase_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) +#endif } RUN_TESTS() From 4cdfb2537a3b02537e3a9dab1e5c898dc46c6a5d Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 10:57:48 -0700 Subject: [PATCH 082/279] Implement erase(), get erase_tests passing --- include/boost/unordered/detail/foa.hpp | 5 +++++ include/boost/unordered/unordered_flat_map.hpp | 8 ++++++++ include/boost/unordered/unordered_flat_set.hpp | 8 ++++++++ 3 files changed, 21 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 755c8cca..f885e82b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -590,6 +590,8 @@ private: template class table; +class const_iterator_cast_tag {}; + template class table_iterator { @@ -604,6 +606,9 @@ public: template::type* =nullptr> table_iterator(const table_iterator& x): pc{x.pc},p{x.p}{} + table_iterator( + 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;} diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 64df3a33..e1633364 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -239,6 +239,14 @@ namespace boost { void erase(iterator pos) { table_.erase(pos); } void erase(const_iterator pos) { return table_.erase(pos); } + iterator erase(const_iterator first, const_iterator last) + { + while (first != last) { + this->erase(first++); + } + return iterator{detail::foa::const_iterator_cast_tag{}, last}; + } + size_type erase(key_type const& key) { return table_.erase(key); } /// Lookup diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 96aaf699..3f075185 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -176,6 +176,14 @@ namespace boost { } void erase(const_iterator pos) { return table_.erase(pos); } + iterator erase(const_iterator first, const_iterator last) + { + while (first != last) { + this->erase(first++); + } + return iterator{detail::foa::const_iterator_cast_tag{}, last}; + } + size_type erase(key_type const& key) { return table_.erase(key); } /// Lookup From 9ad7096851c25986306e545a70ba8f2659eb6d8e Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 10:58:06 -0700 Subject: [PATCH 083/279] Add missing assign_test cases --- test/unordered/assign_tests.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index ef54b01e..e38f6e87 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -322,7 +322,11 @@ namespace assign_tests { UNORDERED_AUTO_TEST (assign_default_initializer_list) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; std::initializer_list > init; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map x1; +#else boost::unordered_map x1; +#endif x1[25] = 3; x1[16] = 10; BOOST_TEST(!x1.empty()); @@ -336,7 +340,11 @@ namespace assign_tests { UNORDERED_AUTO_TEST (assign_initializer_list) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set x; +#else boost::unordered_set x; +#endif x.insert(10); x.insert(20); x = {1, 2, -10}; From 7dfcdc6da836bad57e9874728a43b2190f0333e6 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 14:38:31 -0700 Subject: [PATCH 084/279] Split move_tests into post_move_tests so testing with the new FOA containers is feasible --- test/Jamfile.v2 | 1 + test/unordered/move_tests.cpp | 519 ------------------------ test/unordered/post_move_tests.cpp | 627 +++++++++++++++++++++++++++++ 3 files changed, 628 insertions(+), 519 deletions(-) create mode 100644 test/unordered/post_move_tests.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c16d4b26..7e267e07 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -47,6 +47,7 @@ run unordered/equivalent_keys_tests.cpp ; run unordered/constructor_tests.cpp ; run unordered/copy_tests.cpp ; run unordered/move_tests.cpp ; +run unordered/post_move_tests.cpp ; run unordered/assign_tests.cpp ; run unordered/insert_tests.cpp ; run unordered/insert_stable_tests.cpp ; diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 21b2e90c..66b8e264 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -344,519 +344,6 @@ namespace move_tests { } } - template T const& get_key(T const& t) { return t; } - - template K const& get_key(std::pair const& kv) - { - return kv.first; - } - - template T const& get_value(T const& t) { return t; } - - template K const& get_value(std::pair const& kv) - { - return kv.second; - } - - template - static void insert_range(T& y, test::random_values const& v) - { - y.insert(v.begin(), v.end()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void insert_single(T& y, test::random_values const& v) - { - y.insert(*v.begin()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void insert_single_hint(T& y, test::random_values const& v) - { - y.insert(y.end(), *v.begin()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template struct insert_or_assign_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct insert_or_assign_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - - y.insert_or_assign(get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void insert_or_assign(T& y, test::random_values const& v) - { - insert_or_assign_invoker()(y, v); - } - - template struct insert_or_assign_hint_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct insert_or_assign_hint_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y.insert_or_assign(y.end(), get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void insert_or_assign_hint(T& y, test::random_values const& v) - { - insert_or_assign_hint_invoker()(y, v); - } - - template struct try_emplace_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct try_emplace_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y.try_emplace(get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void try_emplace(T& y, test::random_values const& v) - { - try_emplace_invoker()(y, v); - } - - template struct try_emplace_hint_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct try_emplace_hint_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y.try_emplace(y.end(), get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void try_emplace_hint(T& y, test::random_values const& v) - { - try_emplace_hint_invoker()(y, v); - } - - template struct at_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct at_invoker > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - BOOST_TRY { y.at(get_key(*v.begin())); } - BOOST_CATCH(...) {} - BOOST_CATCH_END - } - }; - - template static void at(T& y, test::random_values const& v) - { - at_invoker()(y, v); - } - - template struct index_operator_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct index_operator_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y[get_key(*v.begin())] = get_value(*v.begin()); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void index_operator(T& y, test::random_values const& v) - { - index_operator_invoker()(y, v); - } - - template static void clear(T& y, test::random_values const&) - { - y.clear(); - BOOST_TEST(y.empty()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void capacity(T& y, test::random_values const&) - { - (void)y.empty(); - (void)y.size(); - (void)y.max_size(); - (void)y.load_factor(); - (void)y.max_load_factor(); - (void)y.hash_function(); - (void)y.key_eq(); - (void)y.get_allocator(); - } - - template static void iterators(T& y, test::random_values const&) - { - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void erase_range(T& y, test::random_values const&) - { - y.erase(y.begin(), y.end()); - BOOST_TEST(y.empty()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void erase_key(T& y, test::random_values const& v) - { - y.erase(get_key(*v.begin())); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void lookup(T& y, test::random_values const& v) - { - (void)y.count(get_key(*v.begin())); - (void)y.find(get_key(*v.begin())); - (void)y.contains(get_key(*v.begin())); - (void)y.equal_range(get_key(*v.begin())); - } - - template static void reserve(T& y, test::random_values const&) - { - y.reserve(1337); - BOOST_TEST_GT(y.bucket_count(), 1337u); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void copy_assignment(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - y = x; - BOOST_TEST_EQ(y.size(), x.size()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void move_assignment(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - std::size_t const size = x.size(); - y = boost::move(x); - BOOST_TEST_GE(y.size(), size); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void equal(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - (void)(y == x); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void extract(T& y, test::random_values const& v) - { - (void)y.extract(get_key(*v.begin())); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void merge(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - if (y.get_allocator() == x.get_allocator()) { - y.merge(x); - } - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template bool pred(X const&) { return true; } - - template - static void erase_with_pred(T& y, test::random_values const&) - { - erase_if(y, pred); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void container_swap(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - if (boost::allocator_propagate_on_container_swap< - typename T::allocator_type>::type::value || - x.get_allocator() == y.get_allocator()) { - y.swap(x); - } - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void buckets(T& y, test::random_values const& v) - { - (void)y.begin(0); - (void)y.end(0); - (void)y.bucket_count(); - (void)y.max_bucket_count(); - (void)y.bucket_size(0); - (void)y.bucket(get_key(*v.begin())); - } - - template - static void double_move_construct(T& y, test::random_values const&) - { - T x = boost::move(y); - x.clear(); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - BOOST_TEST_EQ(x.size(), - static_cast(std::distance(x.begin(), x.end()))); - } - - template - static void double_move_assign(T& y, test::random_values const&) - { - T x; - x = boost::move(y); - x.clear(); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - BOOST_TEST_EQ(x.size(), - static_cast(std::distance(x.begin(), x.end()))); - } - - template - static void post_move_tests(T* ptr, test::random_generator const& generator) - { - // clang-format off - void (*fps[])(T&, test::random_values const&) = { - insert_range, - insert_single, - insert_single_hint, - insert_or_assign, - insert_or_assign_hint, - try_emplace, - try_emplace_hint, - at, - index_operator, - clear, - capacity, - iterators, - erase_range, - erase_key, - lookup, - reserve, - copy_assignment, - move_assignment, - equal, - extract, - merge, - erase_with_pred, - container_swap, - buckets, - double_move_construct, - double_move_assign - }; - // clang-format on - - std::size_t const len = (sizeof(fps) / sizeof(*(fps))); - - for (std::size_t i = 0; i < len; ++i) { - test::check_instances check_; - - test::random_values const v(1000, generator); - test::object_count count; - T y(create(v, count)); - - unsigned num_allocs = test::detail::tracker.count_allocations; - (void)num_allocs; - - T x(boost::move(y)); - -#if defined(BOOST_UNORDERED_USE_MOVE) || \ - !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - BOOST_TEST(y.empty()); - BOOST_TEST(y.begin() == y.end()); - BOOST_TEST_EQ(y.bucket_count(), 0u); - BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); -#endif - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - - for (std::size_t i = 0; i < len; ++i) { - typename T::hasher hf(1); - typename T::key_equal eq(1); - typename T::allocator_type al1(1); - typename T::allocator_type al2(2); - - test::check_instances check_; - - test::random_values v(1000, generator); - test::object_count count; - T y(v.begin(), v.end(), 0, hf, eq, al1); - T x(boost::move(y), al2); - - BOOST_TEST_NOT(y.empty()); - BOOST_TEST(y.begin() != y.end()); - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - - for (std::size_t i = 0; i < len; ++i) { - test::check_instances check_; - - test::random_values v(1000, generator); - test::object_count count; - T y(create(v, count)); - - unsigned num_allocs = test::detail::tracker.count_allocations; - (void)num_allocs; - - T x(empty(ptr)); - x = boost::move(y); - -#if defined(BOOST_UNORDERED_USE_MOVE) || \ - !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - BOOST_TEST(y.empty()); - BOOST_TEST(y.begin() == y.end()); - BOOST_TEST_EQ(y.bucket_count(), 0u); - BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); -#endif - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - - for (std::size_t i = 0; i < len; ++i) { - typename T::hasher hf(1); - typename T::key_equal eq(1); - typename T::allocator_type al1(1); - typename T::allocator_type al2(2); - - test::check_instances check_; - - test::random_values v(1000, generator); - test::object_count count; - T y(v.begin(), v.end(), 0, hf, eq, al1); - - unsigned num_allocs = test::detail::tracker.count_allocations; - (void)num_allocs; - - T x(al2); - x = boost::move(y); - - bool b = boost::allocator_propagate_on_container_move_assignment< - typename T::allocator_type>::type::value; - if (b) { -#if defined(BOOST_UNORDERED_USE_MOVE) || \ - !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - BOOST_TEST(y.empty()); - BOOST_TEST(y.begin() == y.end()); - BOOST_TEST_EQ(y.bucket_count(), 0u); - BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); -#else - BOOST_TEST_NOT(y.empty()); - BOOST_TEST(y.begin() != y.end()); - -#endif - } else { - BOOST_TEST_NOT(y.empty()); - BOOST_TEST(y.begin() != y.end()); - } - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - } - boost::unordered_map > >* test_map_std_alloc; @@ -930,12 +417,6 @@ namespace move_tests { test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( test_multimap_no_prop_move))( (default_generator)(generate_collisions)(limited_range))) - UNORDERED_TEST(post_move_tests, - ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)( - test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)( - test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( - test_multimap_no_prop_move))( - (default_generator)(generate_collisions)(limited_range))) } RUN_TESTS() diff --git a/test/unordered/post_move_tests.cpp b/test/unordered/post_move_tests.cpp new file mode 100644 index 00000000..5184a3a0 --- /dev/null +++ b/test/unordered/post_move_tests.cpp @@ -0,0 +1,627 @@ + +// Copyright (C) 2022 Christian Mazakas +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) + +// clang-format off +#include "../helpers/prefix.hpp" +#include +#include +#include "../helpers/postfix.hpp" +// clang-format on + +#include "../helpers/test.hpp" +#include "../objects/test.hpp" +#include "../objects/cxx11_allocator.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/invariants.hpp" + +#include +#include + +#if defined(BOOST_MSVC) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +namespace move_tests { + test::seed_t initialize_seed(98624); +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#define BOOST_UNORDERED_TEST_MOVING 1 +#else +#define BOOST_UNORDERED_TEST_MOVING 0 +#endif + + template T empty(T*) { return T(); } + + template + T create(test::random_values const& v, test::object_count& count) + { + T x(v.begin(), v.end()); + count = test::global_object_count; + return x; + } + + template + T create(test::random_values const& v, test::object_count& count, + typename T::hasher hf, typename T::key_equal eq, + typename T::allocator_type al, float mlf) + { + T x(0, hf, eq, al); + x.max_load_factor(mlf); + x.insert(v.begin(), v.end()); + count = test::global_object_count; + return x; + } + + template T const& get_key(T const& t) { return t; } + + template K const& get_key(std::pair const& kv) + { + return kv.first; + } + + template T const& get_value(T const& t) { return t; } + + template K const& get_value(std::pair const& kv) + { + return kv.second; + } + + template + static void insert_range(T& y, test::random_values const& v) + { + y.insert(v.begin(), v.end()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void insert_single(T& y, test::random_values const& v) + { + y.insert(*v.begin()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void insert_single_hint(T& y, test::random_values const& v) + { + y.insert(y.end(), *v.begin()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template struct insert_or_assign_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct insert_or_assign_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + + y.insert_or_assign(get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void insert_or_assign(T& y, test::random_values const& v) + { + insert_or_assign_invoker()(y, v); + } + + template struct insert_or_assign_hint_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct insert_or_assign_hint_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y.insert_or_assign(y.end(), get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void insert_or_assign_hint(T& y, test::random_values const& v) + { + insert_or_assign_hint_invoker()(y, v); + } + + template struct try_emplace_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct try_emplace_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y.try_emplace(get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void try_emplace(T& y, test::random_values const& v) + { + try_emplace_invoker()(y, v); + } + + template struct try_emplace_hint_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct try_emplace_hint_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y.try_emplace(y.end(), get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void try_emplace_hint(T& y, test::random_values const& v) + { + try_emplace_hint_invoker()(y, v); + } + + template struct at_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct at_invoker > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + BOOST_TRY { y.at(get_key(*v.begin())); } + BOOST_CATCH(...) {} + BOOST_CATCH_END + } + }; + + template static void at(T& y, test::random_values const& v) + { + at_invoker()(y, v); + } + + template struct index_operator_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct index_operator_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y[get_key(*v.begin())] = get_value(*v.begin()); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void index_operator(T& y, test::random_values const& v) + { + index_operator_invoker()(y, v); + } + + template static void clear(T& y, test::random_values const&) + { + y.clear(); + BOOST_TEST(y.empty()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void capacity(T& y, test::random_values const&) + { + (void)y.empty(); + (void)y.size(); + (void)y.max_size(); + (void)y.load_factor(); + (void)y.max_load_factor(); + (void)y.hash_function(); + (void)y.key_eq(); + (void)y.get_allocator(); + } + + template static void iterators(T& y, test::random_values const&) + { + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void erase_range(T& y, test::random_values const&) + { + y.erase(y.begin(), y.end()); + BOOST_TEST(y.empty()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void erase_key(T& y, test::random_values const& v) + { + y.erase(get_key(*v.begin())); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void lookup(T& y, test::random_values const& v) + { + (void)y.count(get_key(*v.begin())); + (void)y.find(get_key(*v.begin())); + (void)y.contains(get_key(*v.begin())); + (void)y.equal_range(get_key(*v.begin())); + } + + template static void reserve(T& y, test::random_values const&) + { + y.reserve(1337); + BOOST_TEST_GT(y.bucket_count(), 1337u); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void copy_assignment(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + y = x; + BOOST_TEST_EQ(y.size(), x.size()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void move_assignment(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + std::size_t const size = x.size(); + y = boost::move(x); + BOOST_TEST_GE(y.size(), size); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void equal(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + (void)(y == x); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void extract(T& y, test::random_values const& v) + { + (void)y.extract(get_key(*v.begin())); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void merge(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + if (y.get_allocator() == x.get_allocator()) { + y.merge(x); + } + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template bool pred(X const&) { return true; } + + template + static void erase_with_pred(T& y, test::random_values const&) + { + erase_if(y, pred); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void container_swap(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + if (boost::allocator_propagate_on_container_swap< + typename T::allocator_type>::type::value || + x.get_allocator() == y.get_allocator()) { + y.swap(x); + } + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void buckets(T& y, test::random_values const& v) + { + (void)y.begin(0); + (void)y.end(0); + (void)y.bucket_count(); + (void)y.max_bucket_count(); + (void)y.bucket_size(0); + (void)y.bucket(get_key(*v.begin())); + } + + template + static void double_move_construct(T& y, test::random_values const&) + { + T x = boost::move(y); + x.clear(); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + BOOST_TEST_EQ(x.size(), + static_cast(std::distance(x.begin(), x.end()))); + } + + template + static void double_move_assign(T& y, test::random_values const&) + { + T x; + x = boost::move(y); + x.clear(); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + BOOST_TEST_EQ(x.size(), + static_cast(std::distance(x.begin(), x.end()))); + } + + template + static void post_move_tests(T* ptr, test::random_generator const& generator) + { + // clang-format off + void (*fps[])(T&, test::random_values const&) = { + insert_range, + insert_single, + insert_single_hint, + insert_or_assign, + insert_or_assign_hint, + try_emplace, + try_emplace_hint, + at, + index_operator, + clear, + capacity, + iterators, + erase_range, + erase_key, + lookup, + reserve, + copy_assignment, + move_assignment, + equal, + extract, + merge, + erase_with_pred, + container_swap, + buckets, + double_move_construct, + double_move_assign + }; + // clang-format on + + std::size_t const len = (sizeof(fps) / sizeof(*(fps))); + + for (std::size_t i = 0; i < len; ++i) { + test::check_instances check_; + + test::random_values const v(1000, generator); + test::object_count count; + T y(create(v, count)); + + unsigned num_allocs = test::detail::tracker.count_allocations; + (void)num_allocs; + + T x(boost::move(y)); + +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); + BOOST_TEST_EQ(y.bucket_count(), 0u); + BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); +#endif + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + for (std::size_t i = 0; i < len; ++i) { + typename T::hasher hf(1); + typename T::key_equal eq(1); + typename T::allocator_type al1(1); + typename T::allocator_type al2(2); + + test::check_instances check_; + + test::random_values v(1000, generator); + test::object_count count; + T y(v.begin(), v.end(), 0, hf, eq, al1); + T x(boost::move(y), al2); + + BOOST_TEST_NOT(y.empty()); + BOOST_TEST(y.begin() != y.end()); + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + for (std::size_t i = 0; i < len; ++i) { + test::check_instances check_; + + test::random_values v(1000, generator); + test::object_count count; + T y(create(v, count)); + + unsigned num_allocs = test::detail::tracker.count_allocations; + (void)num_allocs; + + T x(empty(ptr)); + x = boost::move(y); + +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); + BOOST_TEST_EQ(y.bucket_count(), 0u); + BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); +#endif + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + for (std::size_t i = 0; i < len; ++i) { + typename T::hasher hf(1); + typename T::key_equal eq(1); + typename T::allocator_type al1(1); + typename T::allocator_type al2(2); + + test::check_instances check_; + + test::random_values v(1000, generator); + test::object_count count; + T y(v.begin(), v.end(), 0, hf, eq, al1); + + unsigned num_allocs = test::detail::tracker.count_allocations; + (void)num_allocs; + + T x(al2); + x = boost::move(y); + + bool b = boost::allocator_propagate_on_container_move_assignment< + typename T::allocator_type>::type::value; + if (b) { +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); + BOOST_TEST_EQ(y.bucket_count(), 0u); + BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); +#else + BOOST_TEST_NOT(y.empty()); + BOOST_TEST(y.begin() != y.end()); + +#endif + } else { + BOOST_TEST_NOT(y.empty()); + BOOST_TEST(y.begin() != y.end()); + } + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + } + + boost::unordered_map > >* + test_map_std_alloc; + + boost::unordered_set >* test_set; + boost::unordered_multiset >* test_multiset; + boost::unordered_map > >* test_map; + boost::unordered_multimap > >* + test_multimap; + + boost::unordered_set >* + test_set_prop_move; + boost::unordered_multiset >* + test_multiset_prop_move; + boost::unordered_map, + test::propagate_move> >* test_map_prop_move; + boost::unordered_multimap, + test::propagate_move> >* test_multimap_prop_move; + + boost::unordered_set >* + test_set_no_prop_move; + boost::unordered_multiset >* + test_multiset_no_prop_move; + boost::unordered_map, + test::no_propagate_move> >* test_map_no_prop_move; + boost::unordered_multimap, + test::no_propagate_move> >* test_multimap_no_prop_move; + + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + UNORDERED_TEST(post_move_tests, + ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)( + test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)( + test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( + test_multimap_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) +} + +RUN_TESTS() From e9c3ed1531edb9ecff86ed309c4fbd5e4e1e549a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 14:49:40 -0700 Subject: [PATCH 085/279] Remove unnecessary self-alias checks in copy-assignment operators --- include/boost/unordered/unordered_flat_map.hpp | 4 +--- include/boost/unordered/unordered_flat_set.hpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index e1633364..c7b0b3ec 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -101,9 +101,7 @@ namespace boost { unordered_flat_map& operator=(unordered_flat_map const& other) { - if (this != &other) { - table_ = other.table_; - } + table_ = other.table_; return *this; } diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 3f075185..b1caed49 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -100,9 +100,7 @@ namespace boost { unordered_flat_set& operator=(unordered_flat_set const& other) { - if (this != &other) { - table_ = other.table_; - } + table_ = other.table_; return *this; } From bf6643844b6435c0f0caaf38b671487199a7f5ca Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 14:51:03 -0700 Subject: [PATCH 086/279] Add foa_move_tests --- test/Jamfile.v2 | 1 + test/unordered/move_tests.cpp | 91 +++++++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7e267e07..1d4e1423 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -99,6 +99,7 @@ run quick.cpp ; run unordered/constructor_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; run unordered/copy_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; +run unordered/move_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_move_tests ; run unordered/assign_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_assign_tests ; run unordered/insert_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; run unordered/erase_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_erase_tests ; diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 66b8e264..31b78f81 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -5,8 +5,13 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -71,7 +76,11 @@ namespace move_tests { BOOST_TEST(test::equivalent(y.hash_function(), hf)); BOOST_TEST(test::equivalent(y.key_eq(), eq)); BOOST_TEST(test::equivalent(y.get_allocator(), al)); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 1.0); +#endif test::check_equivalent_keys(y); #if defined(BOOST_UNORDERED_USE_MOVE) || \ !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -146,7 +155,11 @@ namespace move_tests { BOOST_TEST(test::equivalent(y.hash_function(), hf)); BOOST_TEST(test::equivalent(y.key_eq(), eq)); BOOST_TEST(test::equivalent(y.get_allocator(), al)); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 0.5); // Not necessarily required. +#endif test::check_equivalent_keys(y); } @@ -162,7 +175,11 @@ namespace move_tests { BOOST_TEST(test::equivalent(y.hash_function(), hf)); BOOST_TEST(test::equivalent(y.key_eq(), eq)); BOOST_TEST(test::equivalent(y.get_allocator(), al2)); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required. +#endif test::check_equivalent_keys(y); } @@ -192,7 +209,11 @@ namespace move_tests { BOOST_TEST(test::equivalent(y.hash_function(), hf)); BOOST_TEST(test::equivalent(y.key_eq(), eq)); BOOST_TEST(test::equivalent(y.get_allocator(), al)); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required. +#endif test::check_equivalent_keys(y); } } @@ -215,7 +236,11 @@ namespace move_tests { BOOST_TEST(y.empty()); test::check_container(y, v2); test::check_equivalent_keys(y); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 2.0); +#endif #if defined(BOOST_HAS_NRVO) if (BOOST_UNORDERED_TEST_MOVING @@ -240,7 +265,11 @@ namespace move_tests { #endif test::check_container(y, v); test::check_equivalent_keys(y); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 0.5); +#endif #if defined(BOOST_HAS_NRVO) if (BOOST_UNORDERED_TEST_MOVING @@ -268,7 +297,11 @@ namespace move_tests { #endif test::check_container(y, v); test::check_equivalent_keys(y); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 0.25); +#endif if (BOOST_UNORDERED_TEST_MOVING ? (bool)allocator_type::is_propagate_on_move @@ -296,7 +329,11 @@ namespace move_tests { } test::check_container(y, v); test::check_equivalent_keys(y); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 0.25); +#endif if (BOOST_UNORDERED_TEST_MOVING ? (bool)allocator_type::is_propagate_on_move @@ -332,7 +369,11 @@ namespace move_tests { test::check_container(y, v2); test::check_equivalent_keys(y); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.max_load_factor() == 0.875); +#else BOOST_TEST(y.max_load_factor() == 0.5); +#endif if (BOOST_UNORDERED_TEST_MOVING ? (bool)allocator_type::is_propagate_on_move @@ -344,6 +385,51 @@ namespace move_tests { } } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map > >* + test_map_std_alloc; + + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map > >* test_map; + + boost::unordered_flat_set >* + test_set_prop_move; + boost::unordered_flat_map, + test::propagate_move> >* test_map_prop_move; + + boost::unordered_flat_set >* + test_set_no_prop_move; + boost::unordered_flat_map, + test::no_propagate_move> >* test_map_no_prop_move; + + UNORDERED_TEST(move_construct_tests1, + ((test_map_std_alloc)(test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(move_assign_tests1, + ((test_map_std_alloc)(test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(move_construct_tests2, + ((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(move_assign_tests2, + ((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_map > >* test_map_std_alloc; @@ -387,10 +473,6 @@ namespace move_tests { test::cxx11_allocator, test::no_propagate_move> >* test_multimap_no_prop_move; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_TEST(move_construct_tests1, ((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap)( test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)( @@ -417,6 +499,7 @@ namespace move_tests { test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( test_multimap_no_prop_move))( (default_generator)(generate_collisions)(limited_range))) +#endif } RUN_TESTS() From 8e9b7cf2598773013db2b6e7d3b8d9d6dd4418da Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 14:51:45 -0700 Subject: [PATCH 087/279] Add move semantics to FOA containers --- .../boost/unordered/unordered_flat_map.hpp | 23 +++++++++++++++++++ .../boost/unordered/unordered_flat_set.hpp | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index c7b0b3ec..2add8d34 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -89,6 +89,19 @@ namespace boost { { } + unordered_flat_map(unordered_flat_map&& other) + noexcept(std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value) + : table_(std::move(other.table_)) + { + } + + unordered_flat_map(unordered_flat_map&& other, allocator_type const& al) + : table_(std::move(other.table_), al) + { + } + unordered_flat_map(std::initializer_list ilist, size_type n = 0, hasher const& h = hasher(), key_equal const& pred = key_equal(), @@ -105,6 +118,16 @@ namespace boost { return *this; } + unordered_flat_map& operator=(unordered_flat_map&& other) + noexcept(std::allocator_traits::is_always_equal::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_assignable::value) + { + table_ = std::move(other.table_); + return *this; + } + + allocator_type get_allocator() const noexcept { return table_.get_allocator(); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index b1caed49..1ac629f0 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -88,6 +88,19 @@ namespace boost { { } + unordered_flat_set(unordered_flat_set&& other) + noexcept(std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_constructible::value) + : table_(std::move(other.table_)) + { + } + + unordered_flat_set(unordered_flat_set&& other, allocator_type const& al) + : table_(std::move(other.table_), al) + { + } + unordered_flat_set(std::initializer_list ilist, size_type n = 0, hasher const& h = hasher(), key_equal const& pred = key_equal(), @@ -104,6 +117,16 @@ namespace boost { return *this; } + unordered_flat_set& operator=(unordered_flat_set&& other) + noexcept(std::allocator_traits::is_always_equal::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_assignable::value) + { + table_ = std::move(other.table_); + return *this; + } + + allocator_type get_allocator() const noexcept { return table_.get_allocator(); From 1a89b0aa1460704eb3e88430a2df403265e7df62 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 14:52:18 -0700 Subject: [PATCH 088/279] Add missing size swap() call to move-assign operator for foa::table --- include/boost/unordered/detail/foa.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f885e82b..2205d887 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1056,6 +1056,7 @@ public: reserve(0); swap(arrays,x.arrays); swap(ml,x.ml); + swap(size_,x.size_); move_assign_if(al(),x.al()); } else{ From fdbc79d2a8901400e3d1c86d2309d4ba1ff5df26 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 14:52:38 -0700 Subject: [PATCH 089/279] Silence -Werror=terminate warning in move assignment --- include/boost/unordered/detail/foa.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2205d887..e969e67b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -11,6 +11,8 @@ #ifndef BOOST_UNORDERED_DETAIL_FOA_HPP #define BOOST_UNORDERED_DETAIL_FOA_HPP +#include + #include #include #include @@ -1036,6 +1038,11 @@ public: #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable:4297) /* throw inside noexcept function */ +#endif + +#if defined(BOOST_GCC) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wterminate" #endif table& operator=(table&& x) @@ -1081,6 +1088,10 @@ public: return *this; } +#if defined(BOOST_GCC) +#pragma GCC diagnostic pop +#endif + #if defined(BOOST_MSVC) #pragma warning(pop) /* C4297 */ #endif From 4d0f69893760396768e91876826795c46a54dc9d Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 5 Oct 2022 09:34:21 +0200 Subject: [PATCH 090/279] stylistic --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index e969e67b..e6ece045 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1061,10 +1061,10 @@ public: if(pocma||al()==x.al()){ using std::swap; reserve(0); + move_assign_if(al(),x.al()); + swap(size_,x.size_); swap(arrays,x.arrays); swap(ml,x.ml); - swap(size_,x.size_); - move_assign_if(al(),x.al()); } else{ reserve(x.size()); From 48816135df30a7246fdd7e1e8f851a319755200e Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 5 Oct 2022 10:05:10 +0200 Subject: [PATCH 091/279] refactored move assignment to silence warnings --- include/boost/unordered/detail/foa.hpp | 27 +++++++------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index e6ece045..08a60d76 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1035,16 +1035,6 @@ public: return *this; } -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4297) /* throw inside noexcept function */ -#endif - -#if defined(BOOST_GCC) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wterminate" -#endif - table& operator=(table&& x) noexcept( alloc_traits::is_always_equal::value&& @@ -1066,7 +1056,12 @@ public: swap(arrays,x.arrays); swap(ml,x.ml); } - else{ + else if_constexpr([&,this]{ + /* The check above is redundant: we're setting up a compile-time + * barrier so that the compiler is convinced we're not throwing + * under noexcept(true) conditions. + */ + reserve(x.size()); BOOST_TRY{ /* This works because subsequent x.clear() does not depend on the @@ -1083,19 +1078,11 @@ public: } BOOST_CATCH_END x.clear(); - } + }); } return *this; } -#if defined(BOOST_GCC) -#pragma GCC diagnostic pop -#endif - -#if defined(BOOST_MSVC) -#pragma warning(pop) /* C4297 */ -#endif - allocator_type get_allocator()const noexcept{return al();} iterator begin()noexcept From 886b1b4deda5c59d118d70e628e9eed6fe6e9c94 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 5 Oct 2022 13:54:28 +0200 Subject: [PATCH 092/279] refactored table_arrays to solve alignment issues without an extra data member --- include/boost/unordered/detail/foa.hpp | 175 +++++++------------------ 1 file changed, 49 insertions(+), 126 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 08a60d76..cf5e82c7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -668,22 +668,31 @@ private: Value *p=nullptr; }; -template -struct table_arrays_base +template +struct table_arrays { + using value_type=Value; + using group_type=Group; + static constexpr auto N=group_type::N; + using size_policy=SizePolicy; + template - static Arrays new_(Allocator& al,std::size_t n) + static table_arrays new_(Allocator& al,std::size_t n) { - using group_type=typename Arrays::group_type; - static constexpr auto N=group_type::N; - using size_policy=typename Arrays::size_policy; using alloc_traits=std::allocator_traits; - auto groups_size_index=size_policy::size_index(n/N+1); - auto groups_size=size_policy::size(groups_size_index); - Arrays arrays{groups_size_index,groups_size-1}; + /* n/N+1 == ceil(n+1/N) (extra +1 for the sentinel) */ + auto groups_size_index=size_policy::size_index(n/N+1); + auto groups_size=size_policy::size(groups_size_index); + table_arrays arrays{groups_size_index,groups_size-1,nullptr,nullptr}; if(!n){ + /* We make groups point to dummy storage initialized as if in an empty + * container. This allows us to implement find() etc. without checking + * groups==nullptr. This space won't ever be used for insertion as + * container capacity is properly tuned to avoid that. + */ + static constexpr typename group_type::dummy_group_type storage[size_policy::min_size()]= {typename group_type::dummy_group_type(),}; @@ -692,145 +701,59 @@ struct table_arrays_base const_cast(storage)); } else{ - arrays.allocate_groups(al,groups_size); - // TODO: explain why memset - std::memset( - arrays.groups,0,sizeof(group_type)*groups_size); + arrays.elements= + boost::to_address(alloc_traits::allocate(al,buffer_size(groups_size))); + + /* Align arrays.groups to sizeof(group_type). table_iterator critically + * depends on such alignment for its increment operation. + */ + + auto p=reinterpret_cast(arrays.elements+groups_size*N-1); + p+=(uintptr_t(sizeof(group_type))- + reinterpret_cast(p))%sizeof(group_type); + arrays.groups=reinterpret_cast(p); + + /* memset is faster/not slower than using group_type default ctor. + * This assumes all zeros is group_type's default layout. + */ + + std::memset(arrays.groups,0,sizeof(group_type)*groups_size); arrays.groups[groups_size-1].set_sentinel(); - BOOST_TRY{ - arrays.elements= - boost::to_address(alloc_traits::allocate(al,groups_size*N-1)); - } - BOOST_CATCH(...){ - arrays.deallocate_groups(al,groups_size); - BOOST_RETHROW - } - BOOST_CATCH_END } return arrays; } template - static void delete_(Allocator& al,Arrays& arrays)noexcept + static void delete_(Allocator& al,table_arrays& arrays)noexcept { - using group_type=typename Arrays::group_type; - static constexpr auto N=group_type::N; using alloc_traits=std::allocator_traits; if(arrays.elements){ - auto groups_size=arrays.groups_size_mask+1; - alloc_traits::deallocate(al,arrays.elements,groups_size*N-1); - arrays.deallocate_groups(al,groups_size); + alloc_traits::deallocate( + al,arrays.elements,buffer_size(arrays.groups_size_mask+1)); } } -}; -template -struct aligned_table_arrays: - table_arrays_base> -{ - using group_type=Group; - using value_type=Value; - using size_policy=SizePolicy; + /* combined space for elements and groups measured in sizeof(value_type)s */ - aligned_table_arrays( - std::size_t groups_size_index_,std::size_t groups_size_mask_): - groups_size_index{groups_size_index_},groups_size_mask{groups_size_mask_} - {} - - template - void allocate_groups(Allocator& al,std::size_t groups_size) + static std::size_t buffer_size(std::size_t groups_size) { - using alloc_traits=std::allocator_traits; - using group_allocator= - typename alloc_traits::template rebind_alloc; - using group_alloc_traits=std::allocator_traits; + auto buffer_bytes= + /* space for elements (we subtract 1 because of the sentinel) */ + sizeof(value_type)*(groups_size*N-1)+ + /* space for groups + padding for group alignment */ + sizeof(group_type)*(groups_size+1)-1; - group_allocator gal=al; - groups=boost::to_address(group_alloc_traits::allocate(gal,groups_size)); - } - - template - void deallocate_groups(Allocator& al,std::size_t groups_size) - { - using alloc_traits=std::allocator_traits; - using group_allocator= - typename alloc_traits::template rebind_alloc; - using group_alloc_traits=std::allocator_traits; - - group_allocator gal=al; - group_alloc_traits::deallocate(gal,groups,groups_size); + /* ceil(buffer_bytes/sizeof(value_type)) */ + return (buffer_bytes+sizeof(value_type)-1)/sizeof(value_type); } std::size_t groups_size_index; std::size_t groups_size_mask; - group_type *groups=nullptr; - value_type *elements=nullptr; + group_type *groups; + value_type *elements; }; -template -struct subaligned_table_arrays: - table_arrays_base> -{ - using group_type=Group; - using value_type=Value; - using size_policy=SizePolicy; - - subaligned_table_arrays( - std::size_t groups_size_index_,std::size_t groups_size_mask_): - groups_size_index{groups_size_index_},groups_size_mask{groups_size_mask_} - {} - - template - void allocate_groups(Allocator& al,std::size_t groups_size) - { - using alloc_traits=std::allocator_traits; - using byte_allocator= - typename alloc_traits::template rebind_alloc; - using byte_alloc_traits=std::allocator_traits; - - byte_allocator bal=al; - auto p=boost::to_address( - byte_alloc_traits::allocate(bal,sizeof(group_type)*(groups_size+1)-1)); - groups_offset=static_cast( - (uintptr_t(sizeof(group_type))-reinterpret_cast(p))% - sizeof(group_type)); - groups=reinterpret_cast(p+groups_offset); - } - - template - void deallocate_groups(Allocator& al,std::size_t groups_size) - { - using alloc_traits=std::allocator_traits; - using byte_allocator= - typename alloc_traits::template rebind_alloc; - using byte_alloc_traits=std::allocator_traits; - - byte_allocator bal=al; - byte_alloc_traits::deallocate( - bal,reinterpret_cast(groups)-groups_offset, - sizeof(group_type)*(groups_size+1)-1); - } - - std::size_t groups_size_index; - std::size_t groups_size_mask; - group_type *groups=nullptr; - value_type *elements=nullptr; - unsigned char groups_offset=0; -}; - -template -using table_arrays=typename std::conditional< - -#if 0&&defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) - sizeof(Group)<=__STDCPP_DEFAULT_NEW_ALIGNMENT__, -#else - sizeof(Group)<=alignof(std::max_align_t), -#endif - - aligned_table_arrays, - subaligned_table_arrays>::type; - struct if_constexpr_void_else{void operator()()const{}}; template From df0c375541be8ac8d6c0f2c161664c3a0076448d Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 5 Oct 2022 13:58:31 +0200 Subject: [PATCH 093/279] s/std::allocator_traits/boost::allocator_traits --- include/boost/unordered/detail/foa.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index cf5e82c7..1744798a 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -679,7 +679,7 @@ struct table_arrays template static table_arrays new_(Allocator& al,std::size_t n) { - using alloc_traits=std::allocator_traits; + using alloc_traits=boost::allocator_traits; /* n/N+1 == ceil(n+1/N) (extra +1 for the sentinel) */ auto groups_size_index=size_policy::size_index(n/N+1); @@ -726,7 +726,7 @@ struct table_arrays template static void delete_(Allocator& al,table_arrays& arrays)noexcept { - using alloc_traits=std::allocator_traits; + using alloc_traits=boost::allocator_traits; if(arrays.elements){ alloc_traits::deallocate( @@ -824,7 +824,7 @@ table:empty_value,empty_value,empty_value static constexpr auto N=group_type::N; using size_policy=pow2_size_policy; using prober=pow2_quadratic_prober; - using alloc_traits=std::allocator_traits; + using alloc_traits=boost::allocator_traits; public: using key_type=typename type_policy::key_type; From d233d838114634d38e183d1d32feaccc2528e42a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 5 Oct 2022 14:49:42 +0200 Subject: [PATCH 094/279] allow 100% fillup for small capacities --- include/boost/unordered/detail/foa.hpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 1744798a..1777da49 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1195,10 +1195,15 @@ private: std::size_t max_load()const { - float fml=mlf*(float)(capacity()); - auto res=(std::numeric_limits::max)(); - if(res>(std::size_t)fml)res=(std::size_t)fml; - return res; + static constexpr std::size_t small_capacity=2*N-1; + + auto capacity_=capacity(); + if(capacity_<=small_capacity){ + return capacity_; /* we allow 100% usage */ + } + else{ + return (std::size_t)(mlf*(float)(capacity_)); + } } static inline auto key_from(const value_type& x) From c15bd0092dbd6f55eb796cad16e51f2d3f0a2419 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 5 Oct 2022 18:09:57 +0200 Subject: [PATCH 095/279] introduced init_type/value_type --- include/boost/unordered/detail/foa.hpp | 25 ++++++++++++++++--- .../boost/unordered/unordered_flat_map.hpp | 8 ++++++ .../boost/unordered/unordered_flat_set.hpp | 4 +++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 1777da49..81698d09 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -828,6 +828,7 @@ table:empty_value,empty_value,empty_value public: using key_type=typename type_policy::key_type; + using init_type=typename type_policy::value_type; using value_type=typename type_policy::value_type; private: @@ -1042,12 +1043,12 @@ public: std::forward_as_tuple(std::forward(args)...)); } - BOOST_FORCEINLINE std::pair insert(const value_type& x) + BOOST_FORCEINLINE std::pair insert(const init_type& x) { return emplace_impl(x); } - BOOST_FORCEINLINE std::pair insert(value_type&& x) + BOOST_FORCEINLINE std::pair insert(init_type&& x) { return emplace_impl(std::move(x)); } @@ -1346,8 +1347,9 @@ private: void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { auto hash=h()(key_from(*p)); - nosize_unchecked_emplace_at( - arrays_,position_for(hash,arrays_),hash,std::move(*p)); + type_policy::move_parts_to( + *p, + bind_unchecked_emplace_at{this,arrays_,position_for(hash,arrays_),hash}); destroy_element(p); } @@ -1413,6 +1415,21 @@ private: } #endif + struct bind_unchecked_emplace_at + { + template + iterator operator()(Args&&... args)const + { + return this_->nosize_unchecked_emplace_at( + arrays,pos0,hash,std::forward(args)...); + } + + table* this_; + const arrays_type& arrays; + std::size_t pos0; + std::size_t hash; + }; + template void for_all_elements(F f)const { diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 2add8d34..864a33b8 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -28,8 +28,16 @@ namespace boost { struct map_types { using key_type = Key; + using init_type = std::pair; using value_type = std::pair; static Key const& extract(value_type const& kv) { return kv.first; } + + template + static void move_parts_to(value_type& x,F f) + { + // TODO: we probably need to launder here + f(std::move(const_cast(x.first)), std::move(x.second)); + } }; using table_type = detail::foa::table + static void move_parts_to(value_type& x,F f) { f(std::move(x)); } }; using table_type = detail::foa::table Date: Wed, 5 Oct 2022 18:46:38 +0200 Subject: [PATCH 096/279] fixed init_type machinery --- include/boost/unordered/detail/foa.hpp | 15 ++++++++++++++- include/boost/unordered/unordered_flat_map.hpp | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 81698d09..abcf800a 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -828,12 +828,14 @@ table:empty_value,empty_value,empty_value public: using key_type=typename type_policy::key_type; - using init_type=typename type_policy::value_type; + using init_type=typename type_policy::init_type; using value_type=typename type_policy::value_type; private: static constexpr bool has_mutable_iterator= !std::is_same::value; + static constexpr bool has_different_init_type= + !std::is_same::value; public: using hasher=Hash; @@ -1207,6 +1209,17 @@ private: } } + template< + bool dependent_value=false, + typename std::enable_if< + has_different_init_type||dependent_value>::type* =nullptr + > + static inline auto key_from(const init_type& x) + ->decltype(type_policy::extract(x)) + { + return type_policy::extract(x); + } + static inline auto key_from(const value_type& x) ->decltype(type_policy::extract(x)) { diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 864a33b8..c58ba91a 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -30,6 +30,7 @@ namespace boost { using key_type = Key; using init_type = std::pair; using value_type = std::pair; + static Key const& extract(init_type const& kv) { return kv.first; } static Key const& extract(value_type const& kv) { return kv.first; } template From b86143de4649f81a9f333d183a92bbfd58377200 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 5 Oct 2022 20:38:51 +0200 Subject: [PATCH 097/279] made one overload of insert generic so that value_type is accepted --- include/boost/unordered/detail/foa.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index abcf800a..209f063b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1045,9 +1045,10 @@ public: std::forward_as_tuple(std::forward(args)...)); } - BOOST_FORCEINLINE std::pair insert(const init_type& x) + template + BOOST_FORCEINLINE std::pair insert(T&& x) { - return emplace_impl(x); + return emplace_impl(std::forward(x)); } BOOST_FORCEINLINE std::pair insert(init_type&& x) From 2134116cbc248f60f1f14c0f8e5bb59278850791 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 5 Oct 2022 13:24:54 -0700 Subject: [PATCH 098/279] Update test jamfile to use a build_foa command --- test/Jamfile.v2 | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1d4e1423..c76a5b6d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -97,10 +97,15 @@ run exception/merge_exception_tests.cpp ; run quick.cpp ; -run unordered/constructor_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_tests ; -run unordered/copy_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_copy_tests ; -run unordered/move_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_move_tests ; -run unordered/assign_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_assign_tests ; -run unordered/insert_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_insert_tests ; -run unordered/erase_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_erase_tests ; -run unordered/find_tests.cpp : : : 98:no 03:no 11:no BOOST_UNORDERED_FOA_TESTS : foa_find_tests ; +rule build_foa ( name ) +{ + run unordered/$(name).cpp : : : 98:no 03:no 0x:no 11:no 1y:no BOOST_UNORDERED_FOA_TESTS : foa_$(name) ; +} + +build_foa constructor_tests ; +build_foa copy_tests ; +build_foa move_tests ; +build_foa assign_tests ; +build_foa insert_tests ; +build_foa erase_tests ; +build_foa find_tests ; From 7501eefd878ade72d185eade1d23c29aacd40398 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 5 Oct 2022 13:29:48 -0700 Subject: [PATCH 099/279] Updated unordered flat container to use declval instead of allocator_traits as old versions of clang don't have is_always_equal --- include/boost/unordered/unordered_flat_map.hpp | 7 ++----- include/boost/unordered/unordered_flat_set.hpp | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index c58ba91a..5734e6c9 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -127,16 +127,13 @@ namespace boost { return *this; } - unordered_flat_map& operator=(unordered_flat_map&& other) - noexcept(std::allocator_traits::is_always_equal::value&& - std::is_nothrow_move_assignable::value&& - std::is_nothrow_move_assignable::value) + unordered_flat_map& operator=(unordered_flat_map&& other) noexcept( + noexcept(std::declval() = std::declval())) { table_ = std::move(other.table_); return *this; } - allocator_type get_allocator() const noexcept { return table_.get_allocator(); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 12ffd982..7c586503 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -121,16 +121,13 @@ namespace boost { return *this; } - unordered_flat_set& operator=(unordered_flat_set&& other) - noexcept(std::allocator_traits::is_always_equal::value&& - std::is_nothrow_move_assignable::value&& - std::is_nothrow_move_assignable::value) + unordered_flat_set& operator=(unordered_flat_set&& other) noexcept( + noexcept(std::declval() = std::declval())) { table_ = std::move(other.table_); return *this; } - allocator_type get_allocator() const noexcept { return table_.get_allocator(); From a3c6235f3a980ec9dbfcdc6af6b64745dd8985f3 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 5 Oct 2022 13:30:59 -0700 Subject: [PATCH 100/279] Add insert_hint_tests --- include/boost/unordered/unordered_flat_map.hpp | 4 ++-- include/boost/unordered/unordered_flat_set.hpp | 7 +++++-- test/Jamfile.v2 | 1 + test/unordered/insert_hint_tests.cpp | 17 ++++++++++++++++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 5734e6c9..c98cb48d 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -33,8 +34,7 @@ namespace boost { static Key const& extract(init_type const& kv) { return kv.first; } static Key const& extract(value_type const& kv) { return kv.first; } - template - static void move_parts_to(value_type& x,F f) + template static void move_parts_to(value_type& x, F f) { // TODO: we probably need to launder here f(std::move(const_cast(x.first)), std::move(x.second)); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 7c586503..76fd3222 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -32,8 +33,10 @@ namespace boost { using value_type = Key; static Key const& extract(value_type const& key) { return key; } - template - static void move_parts_to(value_type& x,F f) { f(std::move(x)); } + template static void move_parts_to(value_type& x, F f) + { + f(std::move(x)); + } }; using table_type = detail::foa::table +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -17,6 +23,7 @@ #include namespace insert_hint { +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (insert_hint_empty) { typedef boost::unordered_multiset container; container x; @@ -90,9 +97,13 @@ namespace insert_hint { } } } - +#endif UNORDERED_AUTO_TEST (insert_hint_unique) { +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set container; +#else typedef boost::unordered_set container; +#endif container x; x.insert(x.cbegin(), 10); BOOST_TEST_EQ(x.size(), 1u); @@ -101,7 +112,11 @@ namespace insert_hint { } UNORDERED_AUTO_TEST (insert_hint_unique_single) { +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set container; +#else typedef boost::unordered_set container; +#endif container x; x.insert(10); From f3803fc0712d2f62865143b46e54122581a14ef5 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 5 Oct 2022 13:31:10 -0700 Subject: [PATCH 101/279] Add emplace_tests --- .../boost/unordered/unordered_flat_map.hpp | 6 + .../boost/unordered/unordered_flat_set.hpp | 6 + test/Jamfile.v2 | 1 + test/unordered/emplace_tests.cpp | 117 +++++++++++++++++- 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index c98cb48d..82fdd479 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -239,6 +239,12 @@ namespace boost { return table_.emplace(std::forward(args)...); } + template + iterator emplace_hint(const_iterator, Args&&... args) + { + return this->emplace(std::forward(args)...).first; + } + template std::pair try_emplace(key_type const& key, Args&&... args) { diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 76fd3222..f01ea751 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -200,6 +200,12 @@ namespace boost { return table_.emplace(std::forward(args)...); } + template + iterator emplace_hint(const_iterator, Args&&... args) + { + return this->emplace(std::forward(args)...).first; + } + void erase(const_iterator pos) { return table_.erase(pos); } iterator erase(const_iterator first, const_iterator last) { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b40724e2..71b8ff7b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -108,5 +108,6 @@ build_foa move_tests ; build_foa assign_tests ; build_foa insert_tests ; build_foa insert_hint_tests ; +build_foa emplace_tests ; build_foa erase_tests ; build_foa find_tests ; diff --git a/test/unordered/emplace_tests.cpp b/test/unordered/emplace_tests.cpp index 7f7a5d71..c2681152 100644 --- a/test/unordered/emplace_tests.cpp +++ b/test/unordered/emplace_tests.cpp @@ -5,8 +5,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -162,16 +168,29 @@ namespace emplace_tests { return true; } +#ifdef BOOST_UNORDERED_FOA_TESTS + emplace_value() = delete; + emplace_value(emplace_value const&) = default; + emplace_value(emplace_value&&) = default; +#else private: emplace_value(); emplace_value(emplace_value const&); +#endif + }; UNORDERED_AUTO_TEST (emplace_set) { test::check_instances check_; +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set > + container; +#else typedef boost::unordered_set > container; +#endif typedef container::iterator iterator; typedef std::pair return_type; container x(10); @@ -187,7 +206,15 @@ namespace emplace_tests { BOOST_TEST(*r1.first == v1); BOOST_TEST(r1.first == x.find(v1)); BOOST_TEST_EQ(check_.instances(), 2); +#ifdef BOOST_UNORDERED_FOA_TESTS + // 1 from v1 + // 1 from constructing the value_type() so we can pluck the key + // 1 from move-constructing which invokes the counted_object base + // constructor + BOOST_TEST_EQ(check_.constructions(), 3); +#else BOOST_TEST_EQ(check_.constructions(), 2); +#endif // 3 args @@ -198,7 +225,11 @@ namespace emplace_tests { BOOST_TEST(*r1.first == v2); BOOST_TEST(r1.first == x.find(v2)); BOOST_TEST_EQ(check_.instances(), 4); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST_EQ(check_.constructions(), 6); +#else BOOST_TEST_EQ(check_.constructions(), 4); +#endif // 7 args with hint + duplicate @@ -208,7 +239,11 @@ namespace emplace_tests { BOOST_TEST(*i1 == v3); BOOST_TEST(i1 == x.find(v3)); BOOST_TEST_EQ(check_.instances(), 6); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST_EQ(check_.constructions(), 9); +#else BOOST_TEST_EQ(check_.constructions(), 6); +#endif r2 = x.emplace(25, "something", 'z', 4, 5, 6, 7); BOOST_TEST_EQ(x.size(), 3u); @@ -218,7 +253,11 @@ namespace emplace_tests { // whether it can emplace, so there's an extra construction // here. BOOST_TEST_EQ(check_.instances(), 6); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST_EQ(check_.constructions(), 10); +#else BOOST_TEST_EQ(check_.constructions(), 7); +#endif // 10 args + hint duplicate @@ -230,7 +269,11 @@ namespace emplace_tests { BOOST_TEST(*r1.first == v4); BOOST_TEST(r1.first == x.find(v4)); BOOST_TEST_EQ(check_.instances(), 8); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST_EQ(check_.constructions(), 13); +#else BOOST_TEST_EQ(check_.constructions(), 9); +#endif BOOST_TEST( r1.first == x.emplace_hint(r1.first, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10)); @@ -239,7 +282,11 @@ namespace emplace_tests { BOOST_TEST( r1.first == x.emplace_hint(x.end(), 10, "", 'a', 4, 5, 6, 7, 8, 9, 10)); BOOST_TEST_EQ(check_.instances(), 8); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST_EQ(check_.constructions(), 16); +#else BOOST_TEST_EQ(check_.constructions(), 12); +#endif BOOST_TEST_EQ(x.size(), 4u); BOOST_TEST(x.count(v1) == 1); @@ -248,6 +295,7 @@ namespace emplace_tests { BOOST_TEST(x.count(v4) == 1); } +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (emplace_multiset) { test::check_instances check_; @@ -325,20 +373,79 @@ namespace emplace_tests { BOOST_TEST_EQ(x.count(v2), 2u); BOOST_TEST_EQ(x.count(v3), 2u); } +#endif UNORDERED_AUTO_TEST (emplace_map) { test::check_instances check_; - +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_map > + container; +#else typedef boost::unordered_map > container; +#endif typedef container::iterator iterator; typedef std::pair return_type; container x(10); return_type r1, r2; +#ifdef BOOST_UNORDERED_FOA_TESTS // 5/8 args + duplicate + emplace_value k1(5, "", 'b', 4, 5); + emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8); + r1 = x.emplace(std::piecewise_construct, std::make_tuple(5, "", 'b', 4, 5), + std::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8)); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST(r1.second); + BOOST_TEST(x.find(k1) == r1.first); + BOOST_TEST(x.find(k1)->second == m1); + BOOST_TEST_EQ(check_.instances(), 4); + BOOST_TEST_EQ(check_.constructions(), 6); + r2 = x.emplace(std::piecewise_construct, std::make_tuple(5, "", 'b', 4, 5), + std::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8)); + BOOST_TEST_EQ(x.size(), 1u); + BOOST_TEST(!r2.second); + BOOST_TEST(r1.first == r2.first); + BOOST_TEST(x.find(k1)->second == m1); + BOOST_TEST_EQ(check_.instances(), 4); + // constructions could possibly be 5 if the implementation only + // constructed the key. + BOOST_TEST_EQ(check_.constructions(), 8); + + // 9/3 args + duplicates with hints, different mapped value. + + emplace_value k2(9, "", 'b', 4, 5, 6, 7, 8, 9); + emplace_value m2(3, "aaa", 'm'); + r1 = x.emplace(std::piecewise_construct, + std::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9), + std::make_tuple(3, "aaa", 'm')); + BOOST_TEST_EQ(x.size(), 2u); + BOOST_TEST(r1.second); + BOOST_TEST(r1.first->first.arg_count == 9); + BOOST_TEST(r1.first->second.arg_count == 3); + BOOST_TEST(x.find(k2) == r1.first); + BOOST_TEST(x.find(k2)->second == m2); + BOOST_TEST_EQ(check_.instances(), 8); + BOOST_TEST_EQ(check_.constructions(), 14); + + BOOST_TEST(r1.first == x.emplace_hint(r1.first, std::piecewise_construct, + std::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9), + std::make_tuple(15, "jkjk"))); + BOOST_TEST(r1.first == x.emplace_hint(r2.first, std::piecewise_construct, + std::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9), + std::make_tuple(275, "xxx", 'm', 6))); + BOOST_TEST(r1.first == x.emplace_hint(x.end(), std::piecewise_construct, + std::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9), + std::make_tuple(-10, "blah blah", '\0'))); + BOOST_TEST_EQ(x.size(), 2u); + BOOST_TEST(x.find(k2)->second == m2); + BOOST_TEST_EQ(check_.instances(), 8); + BOOST_TEST_EQ(check_.constructions(), 20); +#else + // 5/8 args + duplicate emplace_value k1(5, "", 'b', 4, 5); emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8); r1 = x.emplace(boost::unordered::piecewise_construct, @@ -395,8 +502,10 @@ namespace emplace_tests { BOOST_TEST(x.find(k2)->second == m2); BOOST_TEST_EQ(check_.instances(), 8); BOOST_TEST_EQ(check_.constructions(), 16); +#endif } +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (emplace_multimap) { test::check_instances check_; @@ -461,11 +570,15 @@ namespace emplace_tests { BOOST_TEST_EQ(check_.instances(), 20); BOOST_TEST_EQ(check_.constructions(), 20); } +#endif UNORDERED_AUTO_TEST (try_emplace) { test::check_instances check_; - +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_map container; +#else typedef boost::unordered_map container; +#endif typedef container::iterator iterator; typedef std::pair return_type; container x(10); From 2cf9d5ac4cf549882482e97096b36fc5e04e0c77 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 5 Oct 2022 14:56:49 -0700 Subject: [PATCH 102/279] Add extra value_type() construction in range-based iterator insertion so implicitly convertible types are supported, i.e. test::proxy --- include/boost/unordered/unordered_flat_map.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 82fdd479..85c919d8 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -189,7 +189,7 @@ namespace boost { void insert(InputIterator first, InputIterator last) { for (auto pos = first; pos != last; ++pos) { - table_.insert(*pos); + table_.insert(value_type(*pos)); } } From d02b12c9a1dafd0d1d2513bc3e1e0dbc5f9cc8a9 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Thu, 6 Oct 2022 17:50:30 +0200 Subject: [PATCH 103/279] redesigned init_type/value_type machinery --- include/boost/unordered/detail/foa.hpp | 38 +++++++++---------- .../boost/unordered/unordered_flat_map.hpp | 6 ++- .../boost/unordered/unordered_flat_set.hpp | 7 +--- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 209f063b..82ebc4cb 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -829,6 +829,11 @@ table:empty_value,empty_value,empty_value public: using key_type=typename type_policy::key_type; using init_type=typename type_policy::init_type; + +private: + using moved_type=typename type_policy::moved_type; + +public: using value_type=typename type_policy::value_type; private: @@ -995,7 +1000,7 @@ public: */ x.for_all_elements([this](value_type* p){ - unchecked_insert(std::move(*p)); + unchecked_insert(type_policy::move(*p)); }); } BOOST_CATCH(...){ @@ -1221,6 +1226,17 @@ private: return type_policy::extract(x); } + template< + bool dependent_value=false, + typename std::enable_if< + has_different_init_type||dependent_value>::type* =nullptr + > + static inline auto key_from(const moved_type& x) + ->decltype(type_policy::extract(x)) + { + return type_policy::extract(x); + } + static inline auto key_from(const value_type& x) ->decltype(type_policy::extract(x)) { @@ -1361,9 +1377,8 @@ private: void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { auto hash=h()(key_from(*p)); - type_policy::move_parts_to( - *p, - bind_unchecked_emplace_at{this,arrays_,position_for(hash,arrays_),hash}); + nosize_unchecked_emplace_at( + arrays_,position_for(hash,arrays_),hash,type_policy::move(*p)); destroy_element(p); } @@ -1429,21 +1444,6 @@ private: } #endif - struct bind_unchecked_emplace_at - { - template - iterator operator()(Args&&... args)const - { - return this_->nosize_unchecked_emplace_at( - arrays,pos0,hash,std::forward(args)...); - } - - table* this_; - const arrays_type& arrays; - std::size_t pos0; - std::size_t hash; - }; - template void for_all_elements(F f)const { diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 85c919d8..64175639 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -30,14 +30,16 @@ namespace boost { { using key_type = Key; using init_type = std::pair; + using moved_type = std::pair; using value_type = std::pair; static Key const& extract(init_type const& kv) { return kv.first; } static Key const& extract(value_type const& kv) { return kv.first; } + static Key const& extract(moved_type const& kv) { return kv.first; } - template static void move_parts_to(value_type& x, F f) + static moved_type move(value_type& x) { // TODO: we probably need to launder here - f(std::move(const_cast(x.first)), std::move(x.second)); + return {std::move(const_cast(x.first)), std::move(x.second)}; } }; diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index f01ea751..9b7f366d 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -30,13 +30,10 @@ namespace boost { { using key_type = Key; using init_type = Key; + using moved_type = Key; using value_type = Key; static Key const& extract(value_type const& key) { return key; } - - template static void move_parts_to(value_type& x, F f) - { - f(std::move(x)); - } + static Key&& move(value_type& x) { return std::move(x); } }; using table_type = detail::foa::table Date: Thu, 6 Oct 2022 09:53:49 -0700 Subject: [PATCH 104/279] Enable C++11 builds --- test/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 71b8ff7b..5e3b82ed 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -99,7 +99,7 @@ run quick.cpp ; rule build_foa ( name ) { - run unordered/$(name).cpp : : : 98:no 03:no 0x:no 11:no 1y:no BOOST_UNORDERED_FOA_TESTS : foa_$(name) ; + run unordered/$(name).cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_$(name) ; } build_foa constructor_tests ; From ad248ab76a4049cf334fad85814b9cf40e3a8e64 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 6 Oct 2022 09:54:33 -0700 Subject: [PATCH 105/279] Fix maybe-uninitialized warning in emplace_tests by explicitly initializing all data members of emplace_value --- test/unordered/emplace_tests.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/test/unordered/emplace_tests.cpp b/test/unordered/emplace_tests.cpp index c2681152..ad1245d3 100644 --- a/test/unordered/emplace_tests.cpp +++ b/test/unordered/emplace_tests.cpp @@ -52,47 +52,56 @@ namespace emplace_tests { A8 a8; A9 a9; - emplace_value(A0 const& b0, A1 const& b1) : arg_count(2), a0(b0), a1(b1) {} + emplace_value(A0 const& b0, A1 const& b1) + : arg_count(2), a0(b0), a1(b1), a2('\0'), a3(-1), a4(-1), a5(-1), + a6(-1), a7(-1), a8(-1), a9(-1) + { + } emplace_value(A0 const& b0, A1 const& b1, A2 const& b2) - : arg_count(3), a0(b0), a1(b1), a2(b2) + : arg_count(3), a0(b0), a1(b1), a2(b2), a3(-1), a4(-1), a5(-1), a6(-1), + a7(-1), a8(-1), a9(-1) { } emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3) - : arg_count(4), a0(b0), a1(b1), a2(b2), a3(b3) + : arg_count(4), a0(b0), a1(b1), a2(b2), a3(b3), a4(-1), a5(-1), a6(-1), + a7(-1), a8(-1), a9(-1) { } emplace_value( A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3, A4 const& b4) - : arg_count(5), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4) + : arg_count(5), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(-1), a6(-1), + a7(-1), a8(-1), a9(-1) { } emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3, A4 const& b4, A5 const& b5) - : arg_count(6), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5) + : arg_count(6), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(-1), + a7(-1), a8(-1), a9(-1) { } emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3, A4 const& b4, A5 const& b5, A6 const& b6) - : arg_count(7), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6) + : arg_count(7), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6), + a7(-1), a8(-1), a9(-1) { } emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3, A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7) : arg_count(8), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6), - a7(b7) + a7(b7), a8(-1), a9(-1) { } emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3, A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7, A8 const& b8) : arg_count(9), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6), - a7(b7), a8(b8) + a7(b7), a8(b8), a9(-1) { } From f1eb5d2106d666bb7fd620430e4ce48c257605e2 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 6 Oct 2022 09:55:00 -0700 Subject: [PATCH 106/279] Workaround visibility bug in gcc-6 by un-nesting lambdas --- include/boost/unordered/detail/foa.hpp | 59 ++++++++++++++++---------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 82ebc4cb..66026009 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -975,6 +975,40 @@ public: static constexpr auto pocma= alloc_traits::propagate_on_container_move_assignment::value; + /* Avoid using nested lambdas with a `this` capture as it seems to trigger + * a bug in GCC: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 + * + * Rather than directly attempting to manipulate the visibility of the + * table class, it's easier to work around the bug by simply un-nesting the + * lambdas + */ + auto const move_element=[this](value_type* p){ + unchecked_insert(std::move(*p)); + }; + + auto const elementwise_move=[&,this]{ + /* The check above is redundant: we're setting up a compile-time + * barrier so that the compiler is convinced we're not throwing + * under noexcept(true) conditions. + */ + + reserve(x.size()); + BOOST_TRY{ + /* This works because subsequent x.clear() does not depend on the + * elements' values. + */ + + x.for_all_elements(move_element); + } + BOOST_CATCH(...){ + x.clear(); + BOOST_RETHROW + } + BOOST_CATCH_END + x.clear(); + }; + if(this!=&x){ clear(); h()=std::move(x.h()); @@ -987,29 +1021,8 @@ public: swap(arrays,x.arrays); swap(ml,x.ml); } - else if_constexpr([&,this]{ - /* The check above is redundant: we're setting up a compile-time - * barrier so that the compiler is convinced we're not throwing - * under noexcept(true) conditions. - */ - - reserve(x.size()); - BOOST_TRY{ - /* This works because subsequent x.clear() does not depend on the - * elements' values. - */ - - x.for_all_elements([this](value_type* p){ - unchecked_insert(type_policy::move(*p)); - }); - } - BOOST_CATCH(...){ - x.clear(); - BOOST_RETHROW - } - BOOST_CATCH_END - x.clear(); - }); + else if_constexpr( + elementwise_move); } return *this; } From 6b1379a99266d3c4c8a602d5a28460e71e5ded4a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 6 Oct 2022 10:45:49 -0700 Subject: [PATCH 107/279] Update SFINAE to handle the case of the init_type and moved_type being the same --- include/boost/unordered/detail/foa.hpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 66026009..4be574ee 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1229,22 +1229,13 @@ private: } template< - bool dependent_value=false, + class T, typename std::enable_if< - has_different_init_type||dependent_value>::type* =nullptr + has_different_init_type&&( + std::is_same::value||std::is_same::value + )>::type* =nullptr > - static inline auto key_from(const init_type& x) - ->decltype(type_policy::extract(x)) - { - return type_policy::extract(x); - } - - template< - bool dependent_value=false, - typename std::enable_if< - has_different_init_type||dependent_value>::type* =nullptr - > - static inline auto key_from(const moved_type& x) + static inline auto key_from(const T& x) ->decltype(type_policy::extract(x)) { return type_policy::extract(x); From c57470e0d3421bab82f7d4d4899f2216e99e3893 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Thu, 6 Oct 2022 20:02:03 +0200 Subject: [PATCH 108/279] SFINAED out third key_from overload and fixed insert accepted arg types --- include/boost/unordered/detail/foa.hpp | 52 ++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 4be574ee..7d8a15c9 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1063,10 +1063,14 @@ public: std::forward_as_tuple(std::forward(args)...)); } - template + template< + typename T, + typename std::enable_if< + std::is_constructible::value>* =nullptr + > BOOST_FORCEINLINE std::pair insert(T&& x) { - return emplace_impl(std::forward(x)); + return emplace_impl(value_from(std::forward(x))); } BOOST_FORCEINLINE std::pair insert(init_type&& x) @@ -1228,12 +1232,42 @@ private: } } + template + using is_init_or_value_type=std::integral_constant< + bool, + std::is_same< + init_type, + typename std::remove_cv::type>::type + >::value|| + std::is_same< + value_type, + typename std::remove_cv::type>::type + >::value + >; + template< - class T, + typename T, + typename std::enable_if::value>::type* =nullptr + > + static inline auto value_from(T&& x)->decltype(std::forward(x)) + { + return std::forward(x); + } + + template< + typename T, + typename std::enable_if::value>::type* =nullptr + > + static inline init_type value_from(T&& x) + { + return {std::forward(x)}; + } + + template< + typename T, typename std::enable_if< - has_different_init_type&&( - std::is_same::value||std::is_same::value - )>::type* =nullptr + has_different_init_type&& + is_init_or_value_type::value>::type* =nullptr > static inline auto key_from(const T& x) ->decltype(type_policy::extract(x)) @@ -1247,7 +1281,10 @@ private: return type_policy::extract(x); } - template + template< + typename Key, + typename std::enable_if::value>::type* =nullptr + > static inline const Key& key_from(const Key& x) { return x; @@ -1498,3 +1535,4 @@ private: #undef BOOST_UNORDERED_SSE2 #endif #endif + From 2b7e9d826d9e38bd182e32629f3fda8cbb2322dd Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 6 Oct 2022 12:03:59 -0700 Subject: [PATCH 109/279] Fix warning in msvc-14.3 with C++20 about multiple implicit conversions being applied --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 7d8a15c9..06eb2538 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1260,7 +1260,7 @@ private: > static inline init_type value_from(T&& x) { - return {std::forward(x)}; + return init_type{std::forward(x)}; } template< From dc7b8f3ff20daf0c2b601dbcdd88186741bf7cf3 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 6 Oct 2022 12:04:21 -0700 Subject: [PATCH 110/279] Remove extraneous overloads of key_from --- include/boost/unordered/detail/foa.hpp | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 06eb2538..7bf192a5 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1264,32 +1264,13 @@ private: } template< - typename T, - typename std::enable_if< - has_different_init_type&& - is_init_or_value_type::value>::type* =nullptr - > + typename T> static inline auto key_from(const T& x) ->decltype(type_policy::extract(x)) { return type_policy::extract(x); } - static inline auto key_from(const value_type& x) - ->decltype(type_policy::extract(x)) - { - return type_policy::extract(x); - } - - template< - typename Key, - typename std::enable_if::value>::type* =nullptr - > - static inline const Key& key_from(const Key& x) - { - return x; - } - template static inline auto key_from( std::piecewise_construct_t,const Arg1& k,const Arg2&) From 2057ccaeb5be7f6eedc30229a4af4b4168a8d3d1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 10:44:28 +0200 Subject: [PATCH 111/279] stylistic --- include/boost/unordered/detail/foa.hpp | 30 ++++++++++++-------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 7bf192a5..223fd60d 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -976,28 +976,23 @@ public: alloc_traits::propagate_on_container_move_assignment::value; /* Avoid using nested lambdas with a `this` capture as it seems to trigger - * a bug in GCC: - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 - * - * Rather than directly attempting to manipulate the visibility of the - * table class, it's easier to work around the bug by simply un-nesting the - * lambdas - */ + * a bug in GCC: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 + * + * Rather than directly attempting to manipulate the visibility of the + * table class, it's easier to work around the bug by simply un-nesting the + * lambdas + */ auto const move_element=[this](value_type* p){ unchecked_insert(std::move(*p)); }; auto const elementwise_move=[&,this]{ - /* The check above is redundant: we're setting up a compile-time - * barrier so that the compiler is convinced we're not throwing - * under noexcept(true) conditions. - */ - reserve(x.size()); BOOST_TRY{ /* This works because subsequent x.clear() does not depend on the - * elements' values. - */ + * elements' values. + */ x.for_all_elements(move_element); } @@ -1022,6 +1017,10 @@ public: swap(ml,x.ml); } else if_constexpr( + /* The check above is redundant: we're setting up a compile-time + * barrier so that the compiler is convinced we're not throwing + * under noexcept(true) conditions. + */ elementwise_move); } return *this; @@ -1263,8 +1262,7 @@ private: return init_type{std::forward(x)}; } - template< - typename T> + template static inline auto key_from(const T& x) ->decltype(type_policy::extract(x)) { From 3aaf8955141eaf9db324edbf5c9e0095b90a1641 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 11:19:20 +0200 Subject: [PATCH 112/279] restricted erase generic arg as per C++23 requirements (hopefully fixes test errors in VS2015) --- include/boost/unordered/detail/foa.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 223fd60d..27d48d57 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1091,8 +1091,13 @@ public: --size_; } - template - std::size_t erase(const Key& x) + template< + typename Key, + typename std::enable_if< + !std::is_convertible::value&& + !std::is_convertible::value>::type* =nullptr + > + std::size_t erase(Key&& x) { auto it=find(x); if(it!=end()){ From 5fc929b829ab73cbed06702b035c1b8085cce057 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 11:23:05 +0200 Subject: [PATCH 113/279] initialized ml at ctor body (GCC 4.8/4.9 complains otherwise) --- include/boost/unordered/detail/foa.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 27d48d57..33c53c27 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -862,9 +862,11 @@ public: std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(), const Allocator& al_=Allocator()): hash_base{empty_init,h_},pred_base{empty_init,pred_}, - allocator_base{empty_init,al_},size_{0},arrays{new_arrays(n)}, - ml{max_load()} - {} + allocator_base{empty_init,al_},size_{0},arrays{new_arrays(n)} + { + /* GCC 4.8/4.9 emits funky errors if cted at initializer list */ + ml=max_load(); + } table(const table& x): table(x,alloc_traits::select_on_container_copy_construction(x.al())){} @@ -889,9 +891,11 @@ public: hash_base{empty_init,x.h()},pred_base{empty_init,x.pred()}, allocator_base{empty_init,al_},size_{0}, arrays{ - new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))}, - ml{max_load()} + new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))} { + /* GCC 4.8/4.9 emits funky errors if cted at initializer list */ + ml=max_load(); + BOOST_TRY{ x.for_all_elements([this](value_type* p){ unchecked_insert(*p); From 74ca1e50f3eabc0997c0b7504d828a7cd92822d7 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 11:27:54 +0200 Subject: [PATCH 114/279] return one lambda expression back in place (related to f1eb5d2106d666bb7fd620430e4ce48c257605e2) --- include/boost/unordered/detail/foa.hpp | 41 +++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 33c53c27..39da1f26 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -979,35 +979,19 @@ public: static constexpr auto pocma= alloc_traits::propagate_on_container_move_assignment::value; - /* Avoid using nested lambdas with a `this` capture as it seems to trigger + /* Avoid using nested lambdas with a `this` capture as it seems to trigger * a bug in GCC: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 * * Rather than directly attempting to manipulate the visibility of the * table class, it's easier to work around the bug by simply un-nesting the - * lambdas + * lambda. */ + auto const move_element=[this](value_type* p){ unchecked_insert(std::move(*p)); }; - auto const elementwise_move=[&,this]{ - reserve(x.size()); - BOOST_TRY{ - /* This works because subsequent x.clear() does not depend on the - * elements' values. - */ - - x.for_all_elements(move_element); - } - BOOST_CATCH(...){ - x.clear(); - BOOST_RETHROW - } - BOOST_CATCH_END - x.clear(); - }; - if(this!=&x){ clear(); h()=std::move(x.h()); @@ -1020,12 +1004,27 @@ public: swap(arrays,x.arrays); swap(ml,x.ml); } - else if_constexpr( + else if_constexpr([&,this]{ /* The check above is redundant: we're setting up a compile-time * barrier so that the compiler is convinced we're not throwing * under noexcept(true) conditions. */ - elementwise_move); + + reserve(x.size()); + BOOST_TRY{ + /* This works because subsequent x.clear() does not depend on the + * elements' values. + */ + + x.for_all_elements(move_element); + } + BOOST_CATCH(...){ + x.clear(); + BOOST_RETHROW + } + BOOST_CATCH_END + x.clear(); + }); } return *this; } From 74c2ae627a8694ce6c3922cbd7fce8b7db998814 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 11:34:13 +0200 Subject: [PATCH 115/279] avoided VS constant conditional expression warning --- include/boost/unordered/detail/foa.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 39da1f26..c4024ee5 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -976,7 +976,8 @@ public: std::is_nothrow_move_assignable::value&& std::is_nothrow_move_assignable::value) { - static constexpr auto pocma= + /* not constexpr to avoid constant conditional expression warnings in VS */ + const auto pocma= alloc_traits::propagate_on_container_move_assignment::value; /* Avoid using nested lambdas with a `this` capture as it seems to trigger From b61ec3a65a3e43dce2631619e2e9c9a5afbd952e Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 12:10:14 +0200 Subject: [PATCH 116/279] removed moved_type import (not used explicitly) --- include/boost/unordered/detail/foa.hpp | 5 ----- include/boost/unordered/unordered_flat_set.hpp | 1 - 2 files changed, 6 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c4024ee5..95f92395 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -829,11 +829,6 @@ table:empty_value,empty_value,empty_value public: using key_type=typename type_policy::key_type; using init_type=typename type_policy::init_type; - -private: - using moved_type=typename type_policy::moved_type; - -public: using value_type=typename type_policy::value_type; private: diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 9b7f366d..612c8b2e 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -30,7 +30,6 @@ namespace boost { { using key_type = Key; using init_type = Key; - using moved_type = Key; using value_type = Key; static Key const& extract(value_type const& key) { return key; } static Key&& move(value_type& x) { return std::move(x); } From 8a9aab57c046217f93a4eba353b3ce383aaa57aa Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 12:15:24 +0200 Subject: [PATCH 117/279] s/std::move/type_policy::move in a couple of places --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 95f92395..a48e777f 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -923,7 +923,7 @@ public: */ x.for_all_elements([this](value_type* p){ - unchecked_insert(std::move(*p)); + unchecked_insert(type_policy::move(*p)); }); } BOOST_CATCH(...){ @@ -985,7 +985,7 @@ public: */ auto const move_element=[this](value_type* p){ - unchecked_insert(std::move(*p)); + unchecked_insert(type_policy::move(*p)); }; if(this!=&x){ From 38f9cb750aa45b9b69125ea3387b517f5f60cc15 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 12:17:16 +0200 Subject: [PATCH 118/279] s/value_type/init_type --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index a48e777f..6fcd38e8 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1048,7 +1048,7 @@ public: template BOOST_FORCEINLINE std::pair emplace(Args&&... args) { - return emplace_impl(value_type(std::forward(args)...)); + return emplace_impl(init_type(std::forward(args)...)); } template From 7441be730e5a8f5d9d8133e5abe84c5009dac360 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 13:47:54 +0200 Subject: [PATCH 119/279] removed spurious #include --- include/boost/unordered/detail/foa.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 6fcd38e8..8a7ecd78 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -11,8 +11,6 @@ #ifndef BOOST_UNORDERED_DETAIL_FOA_HPP #define BOOST_UNORDERED_DETAIL_FOA_HPP -#include - #include #include #include From b3754b10c885cc396d36ce7440a9e02adc6275c2 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 13:50:02 +0200 Subject: [PATCH 120/279] extended 5fc929b829ab73cbed06702b035c1b8085cce057 to member arrays --- include/boost/unordered/detail/foa.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 8a7ecd78..d88f559e 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -855,9 +855,10 @@ public: std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(), const Allocator& al_=Allocator()): hash_base{empty_init,h_},pred_base{empty_init,pred_}, - allocator_base{empty_init,al_},size_{0},arrays{new_arrays(n)} + allocator_base{empty_init,al_},size_{0} { /* GCC 4.8/4.9 emits funky errors if cted at initializer list */ + arrays=new_arrays(n); ml=max_load(); } @@ -882,11 +883,11 @@ public: table(const table& x,const Allocator& al_): hash_base{empty_init,x.h()},pred_base{empty_init,x.pred()}, - allocator_base{empty_init,al_},size_{0}, - arrays{ - new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))} + allocator_base{empty_init,al_},size_{0} { /* GCC 4.8/4.9 emits funky errors if cted at initializer list */ + arrays= + new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf))); ml=max_load(); BOOST_TRY{ From 049a1ec8f6ce7faf4d7135a0dfecd02b59a1d751 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 16:32:57 +0200 Subject: [PATCH 121/279] reverted b3754b10c885cc396d36ce7440a9e02adc6275c2 and 5fc929b829ab73cbed06702b035c1b8085cce057 and s/{}/() in arrays initialization --- include/boost/unordered/detail/foa.hpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d88f559e..595fdf3e 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -855,12 +855,9 @@ public: std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(), const Allocator& al_=Allocator()): hash_base{empty_init,h_},pred_base{empty_init,pred_}, - allocator_base{empty_init,al_},size_{0} - { - /* GCC 4.8/4.9 emits funky errors if cted at initializer list */ - arrays=new_arrays(n); - ml=max_load(); - } + allocator_base{empty_init,al_},size_{0},arrays(new_arrays(n)), + ml{max_load()} + {} table(const table& x): table(x,alloc_traits::select_on_container_copy_construction(x.al())){} @@ -874,7 +871,7 @@ public: hash_base{empty_init,std::move(x.h())}, pred_base{empty_init,std::move(x.pred())}, allocator_base{empty_init,std::move(x.al())}, - size_{x.size_},arrays{x.arrays},ml{x.ml} + size_{x.size_},arrays(x.arrays),ml{x.ml} { x.size_=0; x.arrays=x.new_arrays(0); @@ -883,13 +880,11 @@ public: table(const table& x,const Allocator& al_): hash_base{empty_init,x.h()},pred_base{empty_init,x.pred()}, - allocator_base{empty_init,al_},size_{0} + allocator_base{empty_init,al_},size_{0}, + arrays( + new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))), + ml{max_load()} { - /* GCC 4.8/4.9 emits funky errors if cted at initializer list */ - arrays= - new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf))); - ml=max_load(); - BOOST_TRY{ x.for_all_elements([this](value_type* p){ unchecked_insert(*p); From 6be32f3ba4e7bf7f7f0e8181b9ff450978d1aa47 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 16:38:19 +0200 Subject: [PATCH 122/279] reverted 74c2ae627a8694ce6c3922cbd7fce8b7db998814 and explicitly silenced VS warning --- include/boost/unordered/detail/foa.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 595fdf3e..2d8f7363 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -959,14 +959,18 @@ public: return *this; } +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4127) /* conditional expression is constant */ +#endif + table& operator=(table&& x) noexcept( alloc_traits::is_always_equal::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_assignable::value) { - /* not constexpr to avoid constant conditional expression warnings in VS */ - const auto pocma= + static constexpr auto pocma= alloc_traits::propagate_on_container_move_assignment::value; /* Avoid using nested lambdas with a `this` capture as it seems to trigger @@ -1019,6 +1023,10 @@ public: return *this; } +#if defined(BOOST_MSVC) +#pragma warning(pop) /* C4127 */ +#endif + allocator_type get_allocator()const noexcept{return al();} iterator begin()noexcept From 7e479d62dc93d37b95b23bd005ee653bfe74b2dc Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 18:56:16 +0200 Subject: [PATCH 123/279] added foa_mixer.hpp --- include/boost/unordered/detail/foa_mixer.hpp | 175 +++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 include/boost/unordered/detail/foa_mixer.hpp diff --git a/include/boost/unordered/detail/foa_mixer.hpp b/include/boost/unordered/detail/foa_mixer.hpp new file mode 100644 index 00000000..6097275d --- /dev/null +++ b/include/boost/unordered/detail/foa_mixer.hpp @@ -0,0 +1,175 @@ +/* Hash mixer for boost::unordered::unordered_flat_[map|set]. + * + * Copyright 2022 Joaquin M Lopez Munoz. + * Copyright 2022 Peter Dimov. + * 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) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_DETAIL_FOA_MIXER_HPP +#define BOOST_UNORDERED_DETAIL_FOA_MIXER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace unordered{ +namespace detail{ +namespace foa{ + +/* mixer is functionally equivalent to Hash except if Hash is + * boost::hash for any of the Ts where boost::hash implements a + * trivial hashing function not fit for open-addressing hash container: + * in these cases, the result of boost::hash is post-mixed using + * + * - 64 bits: xmx (TODO: Peter Dimov to explain) + * - 32 bits: xmx33 (TODO: Peter Dimov to explain) + */ + +#if defined(BOOST_GCC) +/* GCC's -Wshadow triggers at scenarios like this: + * + * struct foo{}; + * template + * struct derived:Base + * { + * void f(){int foo;} + * }; + * + * derivedx; + * x.f(); // declaration of "foo" in derived::f shadows base type "foo" + * + * This makes shadowing warnings unavoidable in general when a class template + * derives from a user-provided class, as is the case with mixer_impl. + */ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#endif + +template +class mixer_impl:empty_value +{ +public: + using base=empty_value; + +#if BOOST_CXX_VERSION<201703L + using argument_type=typename Hash::argument_type; + using result_type=std::size_t; +#endif + + mixer_impl()=default; + template + mixer_impl(Args&&... args):base{empty_init,std::forward(args)...}{} + + Hash& get_base()noexcept{return base::get();} + const Hash& get_base()const noexcept{return base::get();} + + template< + typename Key, + std::enable_if< + std::is_same< + std::size_t, + decltype(std::declval()(std::declval())) + >::value + >::type* =nullptr + > + std::size_t operator()(const Key& x)const + noexcept(noexcept(std::declval()(x))) + { + return MixPolicy::mix(get_base()(x)); + } + + friend void swap(mixer_impl& x,mixer_impl& y) + { + using std::swap; + swap(x.get_base(),y.get_base()); + } +}; + +#if defined(BOOST_GCC) +#pragma GCC diagnostic pop /* ignored "-Wshadow" */ +#endif + +struct no_mix +{ + static inline std::size_t mix(std::size_t x)noexcept{return x;} +}; + +#if defined(SIZE_MAX) +#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0 +#define BOOST_UNORDERED_64B_ARCHITECTURE /* >64 bits assumed as 64 bits */ +#endif +#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */ +#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0 +#define BOOST_UNORDERED_64B_ARCHITECTURE +#endif +#endif + +struct xmx_mix +{ + static inline std::size_t mix(std::size_t x)noexcept + { +#if defined(BOOST_UNORDERED_64B_ARCHITECTURE) + + boost::uint64_t z=x; + + z^=z>> 23; + z*=0xff51afd7ed558ccdull; + z^=z>>23; + + return (std::size_t)z; + +#else /* 32 bits assumed */ + + x^=x>>18; + x*=0x56b5aaadu; + x^=x>>16; + + return x; + +#endif + } +}; + +#ifdef BOOST_UNORDERED_64B_ARCHITECTURE +#undef BOOST_UNORDERED_64B_ARCHITECTURE +#endif + +template struct is_boost_hash:std::false_type{}; +template struct is_boost_hash>:std::true_type{}; + +template struct boost_hash_key_impl{using type=void;}; +template struct boost_hash_key_impl> +{ + using type=Key; +}; +template using boost_hash_key= + typename boost_hash_key_impl::type; + +template +using mixer=typename std::conditional< + is_boost_hash::value&&( + std::is_integral>::value|| + std::is_enum>::value|| + std::is_floating_point>::value|| // TODO: not sure about this one + std::is_pointer>::value), + mixer_impl, + mixer_impl +>::type; + +} /* namespace foa */ +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#endif From d1982a664b711cc3c06effecd783bc7f3fa29f1c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 18:56:41 +0200 Subject: [PATCH 124/279] stylistic --- include/boost/unordered/detail/foa.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2d8f7363..35a1ad6f 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1520,4 +1520,3 @@ private: #undef BOOST_UNORDERED_SSE2 #endif #endif - From cde017f7911dc264d5689efd5876ac2725edaf4c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 7 Oct 2022 19:02:25 +0200 Subject: [PATCH 125/279] added missing typename --- include/boost/unordered/detail/foa_mixer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa_mixer.hpp b/include/boost/unordered/detail/foa_mixer.hpp index 6097275d..7d2f2ebe 100644 --- a/include/boost/unordered/detail/foa_mixer.hpp +++ b/include/boost/unordered/detail/foa_mixer.hpp @@ -76,7 +76,7 @@ public: template< typename Key, - std::enable_if< + typename std::enable_if< std::is_same< std::size_t, decltype(std::declval()(std::declval())) From b964fa777cde8ffd736a41a0b03bf10a4ad61e8b Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 08:41:30 -0700 Subject: [PATCH 126/279] Add at_tests --- .../boost/unordered/unordered_flat_map.hpp | 22 +++++++++++++++++++ test/Jamfile.v2 | 1 + test/unordered/at_tests.cpp | 10 +++++++++ 3 files changed, 33 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 64175639..de48a22d 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -287,6 +288,27 @@ namespace boost { /// Lookup /// + mapped_type& at(key_type const& key) + { + auto pos = table_.find(key); + if (pos != table_.end()) { + return pos->second; + } + // TODO: someday refactor this to conditionally serialize the key and + // include it in the error message + // + throw std::out_of_range("key was not found in unordered_flat_map"); + } + + mapped_type const& at(key_type const& key) const + { + auto pos = table_.find(key); + if (pos != table_.end()) { + return pos->second; + } + throw std::out_of_range("key was not found in unordered_flat_map"); + } + mapped_type& operator[](key_type const& key) { return table_.try_emplace(key).first->second; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 5e3b82ed..332b3a21 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -111,3 +111,4 @@ build_foa insert_hint_tests ; build_foa emplace_tests ; build_foa erase_tests ; build_foa find_tests ; +build_foa at_tests ; diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index 25b0951a..921bb8ee 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -5,7 +5,12 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -17,8 +22,13 @@ namespace at_tests { UNORDERED_AUTO_TEST (at_tests) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map x; + boost::unordered_flat_map const& x_const(x); +#else boost::unordered_map x; boost::unordered_map const& x_const(x); +#endif BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check empty container" << std::endl; From 86d623a0f499fa983ff0500697c87962ac3a1419 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 10:55:52 -0700 Subject: [PATCH 127/279] Pull mlf into detail::foa namespace for testing --- include/boost/unordered/detail/foa.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 35a1ad6f..0dbf230f 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -778,6 +778,11 @@ void swap_if(T& x,T& y){using std::swap; swap(x,y);} template::type* =nullptr> void swap_if(T&,T&){} +// we pull this out so the tests don't have to rely on a magic constant or +// instantiate the table class template as it can be quite gory +// +constexpr static float const mlf = 0.875f; + #if defined(BOOST_GCC) /* GCC's -Wshadow triggers at scenarios like this: * @@ -1492,7 +1497,6 @@ private: } } - static constexpr float mlf=0.875; std::size_t size_; arrays_type arrays; std::size_t ml; From d3ef0b9a4f6b6fffe913a5da9ffd40dbfe80492c Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 10:56:35 -0700 Subject: [PATCH 128/279] Add rehash tests --- .../boost/unordered/unordered_flat_map.hpp | 4 ++ .../boost/unordered/unordered_flat_set.hpp | 4 ++ test/Jamfile.v2 | 1 + test/unordered/rehash_tests.cpp | 66 +++++++++++++++++-- 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index de48a22d..644b1991 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -371,6 +371,10 @@ namespace boost { void max_load_factor(float) {} + void rehash(size_type count) { table_.rehash(count); } + + void reserve(size_type count) { table_.reserve(count); } + /// Observers /// diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 612c8b2e..45f19cd0 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -268,6 +268,10 @@ namespace boost { void max_load_factor(float) {} + void rehash(size_type count) { table_.rehash(count); } + + void reserve(size_type count) { table_.reserve(count); } + /// Observers /// diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 332b3a21..520ea811 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -112,3 +112,4 @@ build_foa emplace_tests ; build_foa erase_tests ; build_foa find_tests ; build_foa at_tests ; +build_foa rehash_tests ; diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 4eb5598b..6258e08c 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -5,8 +5,13 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -151,8 +156,13 @@ namespace rehash_tests { BOOST_TEST_EQ(x.size(), 0u); BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u); +#ifdef BOOST_UNORDERED_FOA_TESTS + float const mlf = boost::unordered::detail::foa::mlf; + x.max_load_factor(max_load_factors[i]); +#else float const mlf = max_load_factors[i]; x.max_load_factor(mlf); +#endif { BOOST_TEST_EQ(x.bucket_count(), 0u); @@ -419,6 +429,15 @@ namespace rehash_tests { X x; x.max_load_factor(0.25); +#ifdef BOOST_UNORDERED_FOA_TESTS + x.reserve(10000); + BOOST_TEST(x.bucket_count() >= 10000); + + x.reserve(0); + + x.reserve(10000000); + BOOST_TEST(x.bucket_count() >= 10000000); +#else x.reserve(10000); BOOST_TEST(x.bucket_count() >= 40000); @@ -426,6 +445,7 @@ namespace rehash_tests { x.reserve(10000000); BOOST_TEST(x.bucket_count() >= 40000000); +#endif } template void reserve_test1(X*, test::random_generator generator) @@ -486,6 +506,47 @@ namespace rehash_tests { } } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set* int_set_ptr; + boost::unordered_flat_map >* test_map_ptr; + + boost::unordered_flat_set >* test_set_tracking; + boost::unordered_flat_map > >* + test_map_tracking; + + UNORDERED_TEST(rehash_empty_test1, ((int_set_ptr)(test_map_ptr))) + UNORDERED_TEST(rehash_empty_test2, + ((int_set_ptr)(test_map_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(rehash_empty_test3, + ((int_set_ptr)(test_map_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST( + rehash_test1, ((int_set_ptr)(test_map_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(reserve_empty_test1, ((int_set_ptr)(test_map_ptr))) + UNORDERED_TEST(reserve_empty_test2, ((int_set_ptr)(test_map_ptr))) + UNORDERED_TEST( + reserve_test1, ((int_set_ptr)(test_map_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST( + reserve_test2, ((int_set_ptr)(test_map_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(rehash_empty_tracking, + ((test_set_tracking)(test_map_tracking))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(rehash_nonempty_tracking, + ((test_set_tracking)(test_map_tracking))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_set* int_set_ptr; boost::unordered_multiset >* test_multiset_ptr; @@ -505,10 +566,6 @@ namespace rehash_tests { test::allocator1 > >* test_multimap_tracking; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_TEST(rehash_empty_test1, ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))) UNORDERED_TEST(rehash_empty_test2, @@ -536,6 +593,7 @@ namespace rehash_tests { UNORDERED_TEST(rehash_nonempty_tracking, ((test_set_tracking)(test_multiset_tracking)(test_map_tracking)(test_multimap_tracking))( (default_generator)(generate_collisions)(limited_range))) +#endif } RUN_TESTS() From e0bb258b39ce49d26ca8bba8b70e3e66351b8c05 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 10:56:47 -0700 Subject: [PATCH 129/279] Add load_factor_tests --- test/Jamfile.v2 | 1 + test/unordered/load_factor_tests.cpp | 36 ++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 520ea811..b6a29d69 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -112,4 +112,5 @@ build_foa emplace_tests ; build_foa erase_tests ; build_foa find_tests ; build_foa at_tests ; +build_foa load_factor_tests ; build_foa rehash_tests ; diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 9006c1bd..bee0b1e0 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -5,8 +5,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -26,7 +32,17 @@ namespace load_factor_tests { template void set_load_factor_tests(X*) { X x; +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(x.max_load_factor() == boost::unordered::detail::foa::mlf); + BOOST_TEST(x.load_factor() == 0); + // A valid implementation could fail these tests, but I think they're + // reasonable. + x.max_load_factor(2.0); + BOOST_TEST(x.max_load_factor() == boost::unordered::detail::foa::mlf); + x.max_load_factor(0.5); + BOOST_TEST(x.max_load_factor() == boost::unordered::detail::foa::mlf); +#else BOOST_TEST(x.max_load_factor() == 1.0); BOOST_TEST(x.load_factor() == 0); @@ -36,6 +52,7 @@ namespace load_factor_tests { BOOST_TEST(x.max_load_factor() == 2.0); x.max_load_factor(0.5); BOOST_TEST(x.max_load_factor() == 0.5); +#endif } template @@ -72,21 +89,32 @@ namespace load_factor_tests { insert_test(ptr, std::numeric_limits::infinity(), generator); } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set* int_set_ptr; + boost::unordered_flat_map* int_map_ptr; + + UNORDERED_TEST(set_load_factor_tests, ((int_set_ptr)(int_map_ptr))) + + UNORDERED_TEST(load_factor_insert_tests, + ((int_set_ptr)(int_map_ptr))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_set* int_set_ptr; boost::unordered_multiset* int_multiset_ptr; boost::unordered_map* int_map_ptr; boost::unordered_multimap* int_multimap_ptr; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_TEST(set_load_factor_tests, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))) UNORDERED_TEST(load_factor_insert_tests, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))( (default_generator)(generate_collisions)(limited_range))) +#endif } RUN_TESTS() From e543818e3e38d260507588639c96971910afc041 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 14:15:32 -0700 Subject: [PATCH 130/279] Add equality_tests --- .../boost/unordered/unordered_flat_map.hpp | 33 ++++++++++++ .../boost/unordered/unordered_flat_set.hpp | 28 ++++++++++ test/Jamfile.v2 | 1 + test/unordered/equality_tests.cpp | 52 +++++++++++++++---- 4 files changed, 104 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 644b1991..ea24b167 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -332,6 +332,11 @@ namespace boost { return table_.find(key); } + bool contains(key_type const& key) const + { + return this->find(key) != this->end(); + } + std::pair equal_range(key_type const& key) { auto pos = table_.find(key); @@ -382,6 +387,34 @@ namespace boost { key_equal key_eq() const { return table_.key_eq(); } }; + + template + bool operator==( + unordered_flat_map const& lhs, + unordered_flat_map const& rhs) + { + if (&lhs == &rhs) { + return true; + } + + return (lhs.size() == rhs.size()) && ([&] { + for (auto const& kvp : lhs) { + auto pos = rhs.find(kvp.first); + if (pos != rhs.end() && (pos->second != kvp.second)) { + return false; + } + } + return true; + })(); + } + + template + bool operator!=( + unordered_flat_map const& lhs, + unordered_flat_map const& rhs) + { + return !(lhs == rhs); + } } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 45f19cd0..d0e7bc0e 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -279,6 +279,34 @@ namespace boost { key_equal key_eq() const { return table_.key_eq(); } }; + + template + bool operator==( + unordered_flat_set const& lhs, + unordered_flat_set const& rhs) + { + if (&lhs == &rhs) { + return true; + } + + return (lhs.size() == rhs.size()) && ([&] { + for (auto const& key : lhs) { + auto pos = rhs.find(key); + if (pos != rhs.end() && (key != *pos)) { + return false; + } + } + return true; + })(); + } + + template + bool operator!=( + unordered_flat_set const& lhs, + unordered_flat_set const& rhs) + { + return !(lhs == rhs); + } } // namespace unordered } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b6a29d69..40839d14 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -114,3 +114,4 @@ build_foa find_tests ; build_foa at_tests ; build_foa load_factor_tests ; build_foa rehash_tests ; +build_foa equality_tests ; diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index b1029af4..c1f0f561 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -5,8 +5,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -30,14 +36,27 @@ namespace equality_tests { } }; -#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ +#ifdef BOOST_UNORDERED_FOA_TESTS + using boost_unordered_set = + boost::unordered_flat_set; + + using boost_unordered_map = + boost::unordered_flat_map; + +#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ { \ - boost::unordered_set set1, set2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ - BOOST_TEST(set1 op set2); \ } +#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ + { \ + } +#else + typedef boost::unordered_set + boost_unordered_set; + + typedef boost::unordered_map + boost_unordered_map; + #define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ { \ boost::unordered_multiset set1, set2; \ @@ -46,17 +65,26 @@ namespace equality_tests { BOOST_TEST(set1 op set2); \ } -#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ +#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ { \ - boost::unordered_map map1, map2; \ + boost::unordered_multimap map1, map2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ BOOST_TEST(map1 op map2); \ } +#endif -#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ +#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ { \ - boost::unordered_multimap map1, map2; \ + boost_unordered_set set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_TEST(set1 op set2); \ + } + +#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ + { \ + boost_unordered_map map1, map2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ BOOST_TEST(map1 op map2); \ @@ -67,7 +95,11 @@ namespace equality_tests { map.insert(std::pair BOOST_PP_SEQ_TO_TUPLE(item)); UNORDERED_AUTO_TEST (equality_size_tests) { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set x1, x2; +#else boost::unordered_set x1, x2; +#endif BOOST_TEST(x1 == x2); BOOST_TEST(!(x1 != x2)); @@ -134,7 +166,7 @@ namespace equality_tests { // different hash functions but the same equality predicate. UNORDERED_AUTO_TEST (equality_different_hash_test) { - typedef boost::unordered_set set; + typedef boost_unordered_set set; set set1(0, mod_compare(false), mod_compare(false)); set set2(0, mod_compare(true), mod_compare(true)); BOOST_TEST(set1 == set2); From 9560d107718218858548c46ac974a3d0eea2f079 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 14:19:32 -0700 Subject: [PATCH 131/279] Fix shadowing warning in early gcc --- include/boost/unordered/unordered_flat_map.hpp | 4 ++-- include/boost/unordered/unordered_flat_set.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index ea24b167..111847c1 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -376,9 +376,9 @@ namespace boost { void max_load_factor(float) {} - void rehash(size_type count) { table_.rehash(count); } + void rehash(size_type n) { table_.rehash(n); } - void reserve(size_type count) { table_.reserve(count); } + void reserve(size_type n) { table_.reserve(n); } /// Observers /// diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index d0e7bc0e..4113ad73 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -268,9 +268,9 @@ namespace boost { void max_load_factor(float) {} - void rehash(size_type count) { table_.rehash(count); } + void rehash(size_type n) { table_.rehash(n); } - void reserve(size_type count) { table_.reserve(count); } + void reserve(size_type n) { table_.reserve(n); } /// Observers /// From 6e8e2112ba0e563e748c0e65de63a40ae9e3419d Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 14:51:40 -0700 Subject: [PATCH 132/279] Rearrange SFINAE to appease msvc-14.0 in erase() member function template --- include/boost/unordered/detail/foa.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 0dbf230f..ea8aabcf 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1097,13 +1097,11 @@ public: --size_; } - template< - typename Key, - typename std::enable_if< - !std::is_convertible::value&& - !std::is_convertible::value>::type* =nullptr - > - std::size_t erase(Key&& x) + template + auto erase(Key&& x) -> typename std::enable_if< + !boost::is_convertible::value&& + !boost::is_convertible::value, std::size_t>::type + erase(Key&& x) { auto it=find(x); if(it!=end()){ From 1fa823d815d656c188f96694e85807aacd292309 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 14:59:15 -0700 Subject: [PATCH 133/279] Fix erroneous usage of boost::is_convertible instead of std::is_convertible --- include/boost/unordered/detail/foa.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index ea8aabcf..60999b31 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1099,9 +1099,8 @@ public: template auto erase(Key&& x) -> typename std::enable_if< - !boost::is_convertible::value&& - !boost::is_convertible::value, std::size_t>::type - erase(Key&& x) + !std::is_convertible::value&& + !std::is_convertible::value, std::size_t>::type { auto it=find(x); if(it!=end()){ From 2907083b73426d7d3b719ff1d6f86b8d30de7c5b Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 7 Oct 2022 15:31:16 -0700 Subject: [PATCH 134/279] Fixup implementation of equality operator --- include/boost/unordered/unordered_flat_map.hpp | 2 +- include/boost/unordered/unordered_flat_set.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 111847c1..449dec0e 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -400,7 +400,7 @@ namespace boost { return (lhs.size() == rhs.size()) && ([&] { for (auto const& kvp : lhs) { auto pos = rhs.find(kvp.first); - if (pos != rhs.end() && (pos->second != kvp.second)) { + if ((pos == rhs.end()) || (*pos != kvp)) { return false; } } diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 4113ad73..6b1cbe69 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -292,7 +292,7 @@ namespace boost { return (lhs.size() == rhs.size()) && ([&] { for (auto const& key : lhs) { auto pos = rhs.find(key); - if (pos != rhs.end() && (key != *pos)) { + if ((pos == rhs.end()) || (key != *pos)) { return false; } } From 16f86b0770752d517942ddbdfc09c8db58d5c232 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 8 Oct 2022 10:18:20 +0200 Subject: [PATCH 135/279] relied on implicit conversion for second overload of value_from --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 60999b31..2a6c44bd 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1267,7 +1267,7 @@ private: > static inline init_type value_from(T&& x) { - return init_type{std::forward(x)}; + return std::forward(x); } template From 3913fce63855d70e417b6339e0931e0f44f023a2 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 8 Oct 2022 11:47:00 +0200 Subject: [PATCH 136/279] dropped foa_mixer in favor of internal mix policy governed by hash_traits --- include/boost/unordered/detail/foa.hpp | 34 +++- include/boost/unordered/detail/foa_mixer.hpp | 175 ------------------- include/boost/unordered/detail/xmx.hpp | 75 ++++++++ include/boost/unordered/hash_traits.hpp | 52 ++++++ 4 files changed, 157 insertions(+), 179 deletions(-) delete mode 100644 include/boost/unordered/detail/foa_mixer.hpp create mode 100644 include/boost/unordered/detail/xmx.hpp create mode 100644 include/boost/unordered/hash_traits.hpp diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2a6c44bd..4310e0e7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -752,6 +754,19 @@ struct table_arrays value_type *elements; }; +struct no_mix +{ + static inline std::size_t mix(std::size_t x)noexcept{return x;} +}; + +struct xmx_mix +{ + static inline std::size_t mix(std::size_t x)noexcept + { + return xmx(x); + } +}; + struct if_constexpr_void_else{void operator()()const{}}; template @@ -827,6 +842,11 @@ table:empty_value,empty_value,empty_value static constexpr auto N=group_type::N; using size_policy=pow2_size_policy; using prober=pow2_quadratic_prober; + using mix_policy=typename std::conditional< + hash_traits::is_avalanching::value, + no_mix, + xmx_mix + >::type; using alloc_traits=boost::allocator_traits; public: @@ -1158,7 +1178,7 @@ public: template BOOST_FORCEINLINE iterator find(const Key& x) { - auto hash=h()(x); + auto hash=hash_for(x); return find_impl(x,position_for(hash),hash); } @@ -1285,6 +1305,12 @@ private: return std::get<0>(k); } + template + inline std::size_t hash_for(const Key& x) + { + return mix_policy::mix(h()(x)); + } + inline std::size_t position_for(std::size_t hash)const { return position_for(hash,arrays); @@ -1341,7 +1367,7 @@ private: BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { const auto &k=key_from(std::forward(args)...); - auto hash=h()(k); + auto hash=hash_for(k); auto pos0=position_for(hash); auto it=find_impl(k,pos0,hash); @@ -1398,13 +1424,13 @@ private: template void unchecked_insert(Value&& x) { - auto hash=h()(key_from(x)); + auto hash=hash_for(key_from(x)); unchecked_emplace_at(position_for(hash),hash,std::forward(x)); } void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { - auto hash=h()(key_from(*p)); + auto hash=hash_for(key_from(*p)); nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash,type_policy::move(*p)); destroy_element(p); diff --git a/include/boost/unordered/detail/foa_mixer.hpp b/include/boost/unordered/detail/foa_mixer.hpp deleted file mode 100644 index 7d2f2ebe..00000000 --- a/include/boost/unordered/detail/foa_mixer.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/* Hash mixer for boost::unordered::unordered_flat_[map|set]. - * - * Copyright 2022 Joaquin M Lopez Munoz. - * Copyright 2022 Peter Dimov. - * 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) - * - * See https://www.boost.org/libs/unordered for library home page. - */ - -#ifndef BOOST_UNORDERED_DETAIL_FOA_MIXER_HPP -#define BOOST_UNORDERED_DETAIL_FOA_MIXER_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost{ -namespace unordered{ -namespace detail{ -namespace foa{ - -/* mixer is functionally equivalent to Hash except if Hash is - * boost::hash for any of the Ts where boost::hash implements a - * trivial hashing function not fit for open-addressing hash container: - * in these cases, the result of boost::hash is post-mixed using - * - * - 64 bits: xmx (TODO: Peter Dimov to explain) - * - 32 bits: xmx33 (TODO: Peter Dimov to explain) - */ - -#if defined(BOOST_GCC) -/* GCC's -Wshadow triggers at scenarios like this: - * - * struct foo{}; - * template - * struct derived:Base - * { - * void f(){int foo;} - * }; - * - * derivedx; - * x.f(); // declaration of "foo" in derived::f shadows base type "foo" - * - * This makes shadowing warnings unavoidable in general when a class template - * derives from a user-provided class, as is the case with mixer_impl. - */ - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" -#endif - -template -class mixer_impl:empty_value -{ -public: - using base=empty_value; - -#if BOOST_CXX_VERSION<201703L - using argument_type=typename Hash::argument_type; - using result_type=std::size_t; -#endif - - mixer_impl()=default; - template - mixer_impl(Args&&... args):base{empty_init,std::forward(args)...}{} - - Hash& get_base()noexcept{return base::get();} - const Hash& get_base()const noexcept{return base::get();} - - template< - typename Key, - typename std::enable_if< - std::is_same< - std::size_t, - decltype(std::declval()(std::declval())) - >::value - >::type* =nullptr - > - std::size_t operator()(const Key& x)const - noexcept(noexcept(std::declval()(x))) - { - return MixPolicy::mix(get_base()(x)); - } - - friend void swap(mixer_impl& x,mixer_impl& y) - { - using std::swap; - swap(x.get_base(),y.get_base()); - } -}; - -#if defined(BOOST_GCC) -#pragma GCC diagnostic pop /* ignored "-Wshadow" */ -#endif - -struct no_mix -{ - static inline std::size_t mix(std::size_t x)noexcept{return x;} -}; - -#if defined(SIZE_MAX) -#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0 -#define BOOST_UNORDERED_64B_ARCHITECTURE /* >64 bits assumed as 64 bits */ -#endif -#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */ -#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0 -#define BOOST_UNORDERED_64B_ARCHITECTURE -#endif -#endif - -struct xmx_mix -{ - static inline std::size_t mix(std::size_t x)noexcept - { -#if defined(BOOST_UNORDERED_64B_ARCHITECTURE) - - boost::uint64_t z=x; - - z^=z>> 23; - z*=0xff51afd7ed558ccdull; - z^=z>>23; - - return (std::size_t)z; - -#else /* 32 bits assumed */ - - x^=x>>18; - x*=0x56b5aaadu; - x^=x>>16; - - return x; - -#endif - } -}; - -#ifdef BOOST_UNORDERED_64B_ARCHITECTURE -#undef BOOST_UNORDERED_64B_ARCHITECTURE -#endif - -template struct is_boost_hash:std::false_type{}; -template struct is_boost_hash>:std::true_type{}; - -template struct boost_hash_key_impl{using type=void;}; -template struct boost_hash_key_impl> -{ - using type=Key; -}; -template using boost_hash_key= - typename boost_hash_key_impl::type; - -template -using mixer=typename std::conditional< - is_boost_hash::value&&( - std::is_integral>::value|| - std::is_enum>::value|| - std::is_floating_point>::value|| // TODO: not sure about this one - std::is_pointer>::value), - mixer_impl, - mixer_impl ->::type; - -} /* namespace foa */ -} /* namespace detail */ -} /* namespace unordered */ -} /* namespace boost */ - -#endif diff --git a/include/boost/unordered/detail/xmx.hpp b/include/boost/unordered/detail/xmx.hpp new file mode 100644 index 00000000..4b24fd80 --- /dev/null +++ b/include/boost/unordered/detail/xmx.hpp @@ -0,0 +1,75 @@ +/* 32b/64b xmx mix function. + * + * Copyright 2022 Peter Dimov. + * Copyright 2022 Joaquin M Lopez Munoz. + * 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) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_DETAIL_XMX_HPP +#define BOOST_UNORDERED_DETAIL_XMX_HPP + +#include +#include +#include + +namespace boost{ +namespace unordered{ +namespace detail{ + +/* Bit mixer for improvement of statistical properties of hash functions. + * The implementation is different on 64bit and 32bit architectures: + * + * - 64bit: same as xmx function in + * http://jonkagstrom.com/bit-mixer-construction/index.html + * - 32bit: generated by Hash Function Prospector + * (https://github.com/skeeto/hash-prospector) and selected as the + * best overall performer in benchmarks of Boost.Unordered flat containers. + * Score assigned by Hash Prospector: 333.7934929677524 + */ + +#if defined(SIZE_MAX) +#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0 +#define BOOST_UNORDERED_64B_ARCHITECTURE /* >64 bits assumed as 64 bits */ +#endif +#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */ +#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0 +#define BOOST_UNORDERED_64B_ARCHITECTURE +#endif +#endif + +static inline std::size_t xmx(std::size_t x)noexcept +{ +#if defined(BOOST_UNORDERED_64B_ARCHITECTURE) + + boost::uint64_t z=(boost::uint64_t)x; + + z^=z>>23; + z*=0xff51afd7ed558ccdull; + z^=z>>23; + + return (std::size_t)z; + +#else /* 32 bits assumed */ + + x^=x>>18; + x*=0x56b5aaadu; + x^=x>>16; + + return x; + +#endif +} + +#ifdef BOOST_UNORDERED_64B_ARCHITECTURE +#undef BOOST_UNORDERED_64B_ARCHITECTURE +#endif + +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#endif diff --git a/include/boost/unordered/hash_traits.hpp b/include/boost/unordered/hash_traits.hpp new file mode 100644 index 00000000..9409c02b --- /dev/null +++ b/include/boost/unordered/hash_traits.hpp @@ -0,0 +1,52 @@ +/* Hash function characterization. + * + * Copyright 2022 Joaquin M Lopez Munoz. + * 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) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_HASH_TRAITS_HPP +#define BOOST_UNORDERED_HASH_TRAITS_HPP + +#include +#include + +namespace boost{ +namespace unordered{ + +namespace detail{ + +template +struct hash_is_avalanching +{ + using type=std::false_type; +}; + +template +struct hash_is_avalanching> +{ + using type=std::true_type; +}; + +} /* namespace detail */ + +/* Partially specializable by users for concrete hash functions when + * actual characterization differs from default. + */ + +template +struct hash_traits +{ + /* std::true_type if the type Hash::is_avalanching is present, + * std::false_type otherwise. + */ + using is_avalanching=typename detail::hash_is_avalanching::type; +}; + +} /* namespace unordered */ +} /* namespace boost */ + +#endif From 32a7ed74e838ac4041683f1851af7365eba1fa9a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 8 Oct 2022 12:39:36 +0200 Subject: [PATCH 137/279] added missing const qualifier --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 4310e0e7..bd248b03 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1306,7 +1306,7 @@ private: } template - inline std::size_t hash_for(const Key& x) + inline std::size_t hash_for(const Key& x)const { return mix_policy::mix(h()(x)); } From 3fbaf21b8c4fc2dc152460738bee85bec6745772 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 9 Oct 2022 11:23:15 +0200 Subject: [PATCH 138/279] dropped hash_traits in favor of individual traits --- include/boost/unordered/detail/foa.hpp | 2 +- include/boost/unordered/hash_traits.hpp | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index bd248b03..d9faf56b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -843,7 +843,7 @@ table:empty_value,empty_value,empty_value using size_policy=pow2_size_policy; using prober=pow2_quadratic_prober; using mix_policy=typename std::conditional< - hash_traits::is_avalanching::value, + hash_is_avalanching::value, no_mix, xmx_mix >::type; diff --git a/include/boost/unordered/hash_traits.hpp b/include/boost/unordered/hash_traits.hpp index 9409c02b..5f501566 100644 --- a/include/boost/unordered/hash_traits.hpp +++ b/include/boost/unordered/hash_traits.hpp @@ -20,31 +20,28 @@ namespace unordered{ namespace detail{ template -struct hash_is_avalanching +struct hash_is_avalanching_impl { using type=std::false_type; }; template -struct hash_is_avalanching> +struct hash_is_avalanching_impl> { using type=std::true_type; }; } /* namespace detail */ -/* Partially specializable by users for concrete hash functions when - * actual characterization differs from default. +/* Each trait can be partially specialized by users for concrete hash functions + * when actual characterization differs from default. */ +/* Derived from std::true_type if the type Hash::is_avalanching is present, + * derived from std::false_type otherwise. + */ template -struct hash_traits -{ - /* std::true_type if the type Hash::is_avalanching is present, - * std::false_type otherwise. - */ - using is_avalanching=typename detail::hash_is_avalanching::type; -}; +struct hash_is_avalanching:detail::hash_is_avalanching_impl::type{}; } /* namespace unordered */ } /* namespace boost */ From 2955a966cf5a7b3445f5ed52da995cd0b9f102c5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 09:29:41 +0200 Subject: [PATCH 139/279] shut down unavoidable VS warning --- include/boost/unordered/detail/foa.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d9faf56b..a0ea22e8 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -825,6 +826,14 @@ constexpr static float const mlf = 0.875f; #pragma warning(disable:4714) /* marked as __forceinline not inlined */ #endif +#if BOOST_WORKAROUND(BOOST_MSVC,<=1900) +/* VS2015 marks as unreachable generic catch clauses around non-throwing + * code. + */ +#pragma warning(push) +#pragma warning(disable:4702) +#endif + template class @@ -1525,6 +1534,11 @@ private: std::size_t ml; }; + +#if BOOST_WORKAROUND(BOOST_MSVC,<=1900) +#pragma warning(pop) /* C4702 */ +#endif + #if defined(BOOST_MSVC) #pragma warning(pop) /* C4714 */ #endif From ad96ea632e0537683ad0658c0ae33c059aa3583f Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 09:34:10 +0200 Subject: [PATCH 140/279] stylistic --- include/boost/unordered/hash_traits.hpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/hash_traits.hpp b/include/boost/unordered/hash_traits.hpp index 5f501566..5ab4a556 100644 --- a/include/boost/unordered/hash_traits.hpp +++ b/include/boost/unordered/hash_traits.hpp @@ -20,16 +20,11 @@ namespace unordered{ namespace detail{ template -struct hash_is_avalanching_impl -{ - using type=std::false_type; -}; +struct hash_is_avalanching_impl:std::false_type{}; template -struct hash_is_avalanching_impl> -{ - using type=std::true_type; -}; +struct hash_is_avalanching_impl>: + std::true_type{}; } /* namespace detail */ From 889a81f034129ea7887c379552f034164fcf5609 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 09:36:12 +0200 Subject: [PATCH 141/279] stylistic --- include/boost/unordered/detail/foa.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index a0ea22e8..83977ed7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1534,7 +1534,6 @@ private: std::size_t ml; }; - #if BOOST_WORKAROUND(BOOST_MSVC,<=1900) #pragma warning(pop) /* C4702 */ #endif From a4c38c02c8373309ea69b45d1511c888c08433c1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 11:13:32 +0200 Subject: [PATCH 142/279] fixed empty_value index --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 83977ed7..f379e80e 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -841,11 +841,11 @@ class __declspec(empty_bases) /* activate EBO with multiple inheritance */ #endif -table:empty_value,empty_value,empty_value +table:empty_value,empty_value,empty_value { using hash_base=empty_value; using pred_base=empty_value; - using allocator_base=empty_value; + using allocator_base=empty_value; using type_policy=TypePolicy; using group_type=group15; static constexpr auto N=group_type::N; From f776ffa0085aa1e6602253d94fe026a1c17ea336 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 18:02:57 +0200 Subject: [PATCH 143/279] removed temporary const ref in emplace_impl --- include/boost/unordered/detail/foa.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f379e80e..64699571 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1375,10 +1375,9 @@ 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 hash=hash_for(key_from(args...)); + auto pos0=position_for(hash); + auto it=find_impl(key_from(args...),pos0,hash); if(it!=end()){ return {it,false}; From 505a08cf9561b70f28cd1fca5907e57ad7c5f335 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 18:34:45 +0200 Subject: [PATCH 144/279] temporarily reverted 16f86b0770752d517942ddbdfc09c8db58d5c232 --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 64699571..18b549a7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1296,7 +1296,7 @@ private: > static inline init_type value_from(T&& x) { - return std::forward(x); + return {std::forward(x)}; } template From 69aff6f776861490115f4035f8d627a45a528a40 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 18:55:03 +0200 Subject: [PATCH 145/279] restored 16f86b0770752d517942ddbdfc09c8db58d5c232 --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 18b549a7..64699571 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1296,7 +1296,7 @@ private: > static inline init_type value_from(T&& x) { - return {std::forward(x)}; + return std::forward(x); } template From 7caab660113c2c2d1b62024dadd21942ec5ef267 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 19:01:55 +0200 Subject: [PATCH 146/279] removed inline suggestion from hash_for --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 64699571..356f58ed 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1315,7 +1315,7 @@ private: } template - inline std::size_t hash_for(const Key& x)const + std::size_t hash_for(const Key& x)const { return mix_policy::mix(h()(x)); } From 1fa2e84774aaab1314c571be51eca17ca5ee5a36 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 19:24:14 +0200 Subject: [PATCH 147/279] reverted 7caab660113c2c2d1b62024dadd21942ec5ef267 and f776ffa0085aa1e6602253d94fe026a1c17ea336 --- include/boost/unordered/detail/foa.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 356f58ed..f379e80e 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1315,7 +1315,7 @@ private: } template - std::size_t hash_for(const Key& x)const + inline std::size_t hash_for(const Key& x)const { return mix_policy::mix(h()(x)); } @@ -1375,9 +1375,10 @@ private: template BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { - auto hash=hash_for(key_from(args...)); - auto pos0=position_for(hash); - auto it=find_impl(key_from(args...),pos0,hash); + 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); if(it!=end()){ return {it,false}; From 6bda46794212fc5e92765d26da6dd0c9eac155bb Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 19:52:14 +0200 Subject: [PATCH 148/279] temporarily disabled mix_policy --- include/boost/unordered/detail/foa.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f379e80e..f0729ddd 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1317,7 +1317,8 @@ private: template inline std::size_t hash_for(const Key& x)const { - return mix_policy::mix(h()(x)); + //return mix_policy::mix(h()(x)); + return h()(x); } inline std::size_t position_for(std::size_t hash)const From 77f265a678899fe654414e6bb684f72505246da0 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 20:19:39 +0200 Subject: [PATCH 149/279] reverted --- include/boost/unordered/detail/foa.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f0729ddd..f379e80e 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1317,8 +1317,7 @@ private: template inline std::size_t hash_for(const Key& x)const { - //return mix_policy::mix(h()(x)); - return h()(x); + return mix_policy::mix(h()(x)); } inline std::size_t position_for(std::size_t hash)const From 9e2bf3681f00bded93f37ebc351e696f8315b173 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 20:51:47 +0200 Subject: [PATCH 150/279] embedded hash into mixing policies --- include/boost/unordered/detail/foa.hpp | 33 +++++++++++++++----------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f379e80e..fca3b2c0 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -590,6 +590,24 @@ private: std::size_t pos,step=0; }; +struct no_mix +{ + template + static inline std::size_t mix(const Hash& h,const T& x) + { + return h(x); + } +}; + +struct xmx_mix +{ + template + static inline std::size_t mix(const Hash& h,const T& x) + { + return xmx(h(x)); + } +}; + template class table; @@ -755,19 +773,6 @@ struct table_arrays value_type *elements; }; -struct no_mix -{ - static inline std::size_t mix(std::size_t x)noexcept{return x;} -}; - -struct xmx_mix -{ - static inline std::size_t mix(std::size_t x)noexcept - { - return xmx(x); - } -}; - struct if_constexpr_void_else{void operator()()const{}}; template @@ -1317,7 +1322,7 @@ private: template inline std::size_t hash_for(const Key& x)const { - return mix_policy::mix(h()(x)); + return mix_policy::mix(h(),x); } inline std::size_t position_for(std::size_t hash)const From c4cc805063bfd0c78e8f0febaea23347ad10b1a5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 21:06:33 +0200 Subject: [PATCH 151/279] embed xmx code directly into xmx_mix --- include/boost/unordered/detail/foa.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index fca3b2c0..cf1ce6a7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -604,7 +604,14 @@ struct xmx_mix template static inline std::size_t mix(const Hash& h,const T& x) { - return xmx(h(x)); + //return xmx(h(x)); + boost::uint64_t z=(boost::uint64_t)(h(x)); + + z^=z>>23; + z*=0xff51afd7ed558ccdull; + z^=z>>23; + + return (std::size_t)z; } }; From c7836659d1b3ee519e0665817e5aeb18b16181a7 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 10 Oct 2022 21:45:53 +0200 Subject: [PATCH 152/279] activated alt impl of nosize_unchecked_emplace_at --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index cf1ce6a7..ee53046c 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1467,7 +1467,7 @@ private: return res; } -#if 0 +#if 1 template iterator nosize_unchecked_emplace_at( const arrays_type& arrays_,std::size_t pos0,std::size_t hash, From 05f96685974929e18b58d9315ed93f92bce10053 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 08:59:54 -0700 Subject: [PATCH 153/279] Refactor transparent type traits into their own header so they can be shared with FOA impl --- .../boost/unordered/detail/implementation.hpp | 34 +---------- .../boost/unordered/detail/type_traits.hpp | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 include/boost/unordered/detail/type_traits.hpp diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 1dd11ecb..4ee11748 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -618,39 +619,6 @@ namespace boost { #endif -//////////////////////////////////////////////////////////////////////////// -// Type checkers used for the transparent member functions added by C++20 and up - - template struct is_transparent : public false_type - { - }; - - template - struct is_transparent::type> - : public true_type - { - }; - - template struct are_transparent - { - static bool const value = - is_transparent::value && is_transparent::value; - }; - - template struct transparent_non_iterable - { - typedef typename UnorderedMap::hasher hash; - typedef typename UnorderedMap::key_equal key_equal; - typedef typename UnorderedMap::iterator iterator; - typedef typename UnorderedMap::const_iterator const_iterator; - - static bool const value = - are_transparent::value && - !boost::is_convertible::value && - !boost::is_convertible::value; - }; - //////////////////////////////////////////////////////////////////////////// // Explicitly call a destructor diff --git a/include/boost/unordered/detail/type_traits.hpp b/include/boost/unordered/detail/type_traits.hpp new file mode 100644 index 00000000..3d7dcf67 --- /dev/null +++ b/include/boost/unordered/detail/type_traits.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2022 Christian Mazakas +// +// 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_TYPE_TRAITS_HPP +#define BOOST_UNORDERED_DETAIL_TYPE_TRAITS_HPP + +#include +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include + +namespace boost { + namespace unordered { + namespace detail { + //////////////////////////////////////////////////////////////////////////// + // Type checkers used for the transparent member functions added by C++20 + // and up + + template + struct is_transparent : public boost::false_type + { + }; + + template + struct is_transparent::type> + : public boost::true_type + { + }; + + template struct are_transparent + { + static bool const value = + is_transparent::value && is_transparent::value; + }; + + template struct transparent_non_iterable + { + typedef typename UnorderedMap::hasher hash; + typedef typename UnorderedMap::key_equal key_equal; + typedef typename UnorderedMap::iterator iterator; + typedef typename UnorderedMap::const_iterator const_iterator; + + static bool const value = + are_transparent::value && + !boost::is_convertible::value && + !boost::is_convertible::value; + }; + } // namespace detail + } // namespace unordered +} // namespace boost + +#endif // BOOST_UNORDERED_DETAIL_TYPE_TRAITS_HPP From 1ff2dc40425da84b395d75368fafb17fc556a068 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 09:06:22 -0700 Subject: [PATCH 154/279] Add contains_tests --- .../boost/unordered/unordered_flat_map.hpp | 28 ++++++++++++ .../boost/unordered/unordered_flat_set.hpp | 33 ++++++++++++++ test/Jamfile.v2 | 1 + test/unordered/contains_tests.cpp | 43 ++++++++++++++++++- 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 449dec0e..426391fb 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -11,6 +11,7 @@ #endif #include +#include #include #include @@ -332,11 +333,38 @@ namespace boost { return table_.find(key); } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + iterator>::type + find(K const& key) + { + return table_.find(key); + } + + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + const_iterator>::type + find(K const& key) const + { + return table_.find(key); + } + bool contains(key_type const& key) const { return this->find(key) != this->end(); } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + bool>::type + contains(K const& key) const + { + return this->find(key) != this->end(); + } + std::pair equal_range(key_type const& key) { auto pos = table_.find(key); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 6b1cbe69..1b48a1a1 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -11,6 +11,7 @@ #endif #include +#include #include #include @@ -229,6 +230,38 @@ namespace boost { return table_.find(key); } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + iterator>::type + find(K const& key) + { + return table_.find(key); + } + + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + const_iterator>::type + find(K const& key) const + { + return table_.find(key); + } + + bool contains(key_type const& key) const + { + return this->find(key) != this->end(); + } + + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + bool>::type + contains(K const& key) const + { + return this->find(key) != this->end(); + } + std::pair equal_range(key_type const& key) { auto pos = table_.find(key); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 40839d14..f1425155 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -114,4 +114,5 @@ build_foa find_tests ; build_foa at_tests ; build_foa load_factor_tests ; build_foa rehash_tests ; +build_foa contains_tests ; build_foa equality_tests ; diff --git a/test/unordered/contains_tests.cpp b/test/unordered/contains_tests.cpp index 01654479..39302e17 100644 --- a/test/unordered/contains_tests.cpp +++ b/test/unordered/contains_tests.cpp @@ -4,8 +4,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -129,6 +135,20 @@ template void test_map_non_transparent_contains() void test_map() { +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_map + transparent_map; + + typedef boost::unordered_flat_map + non_transparent_map1; + + typedef boost::unordered_flat_map + non_transparent_map2; + + typedef boost::unordered_flat_map + non_transparent_map3; +#else typedef boost::unordered_map transparent_map; @@ -141,6 +161,7 @@ void test_map() typedef boost::unordered_map non_transparent_map3; +#endif test_map_transparent_contains(); test_map_non_transparent_contains(); @@ -148,6 +169,7 @@ void test_map() test_map_non_transparent_contains(); } +#ifndef BOOST_UNORDERED_FOA_TESTS void test_multimap() { typedef boost::unordered_multimap(); test_map_non_transparent_contains(); } +#endif template void test_set_transparent_contains() { @@ -231,6 +254,18 @@ template void test_set_non_transparent_contains() void test_set() { +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set + transparent_set; + + typedef boost::unordered_flat_set + non_transparent_set1; + typedef boost::unordered_flat_set + non_transparent_set2; + typedef boost::unordered_flat_set + non_transparent_set3; +#else typedef boost::unordered_set transparent_set; @@ -239,6 +274,7 @@ void test_set() typedef boost::unordered_set non_transparent_set2; typedef boost::unordered_set non_transparent_set3; +#endif test_set_transparent_contains(); test_set_non_transparent_contains(); @@ -246,6 +282,7 @@ void test_set() test_set_non_transparent_contains(); } +#ifndef BOOST_UNORDERED_FOA_TESTS void test_multiset() { typedef boost::unordered_multiset(); test_set_non_transparent_contains(); } +#endif UNORDERED_AUTO_TEST (contains_) { // avoid -Wshadow warning with `bool contains` test_map(); - test_multimap(); test_set(); +#ifndef BOOST_UNORDERED_FOA_TESTS + test_multimap(); + test_multiset(); +#endif } RUN_TESTS() From 58b78f8ff0b351ae440adf819123a38a94277ffd Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 10:52:01 -0700 Subject: [PATCH 155/279] Add transparent_tests --- .../boost/unordered/unordered_flat_map.hpp | 50 ++++++++ .../boost/unordered/unordered_flat_set.hpp | 50 ++++++++ test/Jamfile.v2 | 1 + test/unordered/transparent_tests.cpp | 109 +++++++++++++++--- 4 files changed, 194 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 426391fb..3c687124 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -286,6 +286,15 @@ namespace boost { size_type erase(key_type const& key) { return table_.erase(key); } + template + typename std::enable_if< + detail::transparent_non_iterable::value, + size_type>::type + erase(K const& key) + { + return table_.erase(key); + } + /// Lookup /// @@ -326,6 +335,15 @@ namespace boost { return pos != table_.end() ? 1 : 0; } + template + typename std::enable_if< + detail::are_transparent::value, size_type>::type + count(K const& key) const + { + auto pos = table_.find(key); + return pos != table_.end() ? 1 : 0; + } + iterator find(key_type const& key) { return table_.find(key); } const_iterator find(key_type const& key) const @@ -390,6 +408,38 @@ namespace boost { return {pos, next}; } + template + typename std::enable_if< + detail::are_transparent::value, + std::pair >::type + equal_range(K const& key) + { + auto pos = table_.find(key); + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; + } + + template + typename std::enable_if< + detail::are_transparent::value, + std::pair >::type + equal_range(K const& key) const + { + auto pos = table_.find(key); + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; + } + /// Hash Policy /// diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 1b48a1a1..297e4554 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -214,6 +214,15 @@ namespace boost { size_type erase(key_type const& key) { return table_.erase(key); } + template + typename std::enable_if< + detail::transparent_non_iterable::value, + size_type>::type + erase(K const& key) + { + return table_.erase(key); + } + /// Lookup /// @@ -223,6 +232,15 @@ namespace boost { return pos != table_.end() ? 1 : 0; } + template + typename std::enable_if< + detail::are_transparent::value, size_type>::type + count(K const& key) const + { + auto pos = table_.find(key); + return pos != table_.end() ? 1 : 0; + } + iterator find(key_type const& key) { return table_.find(key); } const_iterator find(key_type const& key) const @@ -287,6 +305,38 @@ namespace boost { return {pos, next}; } + template + typename std::enable_if< + detail::are_transparent::value, + std::pair >::type + equal_range(K const& key) + { + auto pos = table_.find(key); + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; + } + + template + typename std::enable_if< + detail::are_transparent::value, + std::pair >::type + equal_range(K const& key) const + { + auto pos = table_.find(key); + if (pos == table_.end()) { + return {pos, pos}; + } + + auto next = pos; + ++next; + return {pos, next}; + } + /// Hash Policy /// diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f1425155..628553a6 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -114,5 +114,6 @@ build_foa find_tests ; build_foa at_tests ; build_foa load_factor_tests ; build_foa rehash_tests ; +build_foa transparent_tests ; build_foa contains_tests ; build_foa equality_tests ; diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 50f6bfdc..d1e67870 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -4,8 +4,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -1053,14 +1059,25 @@ template struct convertible_to_const_iterator } }; +#ifdef BOOST_UNORDERED_FOA_TESTS +typedef boost::unordered_flat_map + transparent_unordered_map; +#else typedef boost::unordered_map transparent_unordered_map; +#endif // test that in the presence of the member function template `erase()`, we still // invoke the correct iterator overloads when the type is implicitly convertible // -transparent_unordered_map::iterator map_erase_overload_compile_test() +#ifdef BOOST_UNORDERED_FOA_TESTS +void +#else +transparent_unordered_map::iterator +#endif +map_erase_overload_compile_test() { convertible_to_iterator c; transparent_unordered_map map; @@ -1069,7 +1086,11 @@ transparent_unordered_map::iterator map_erase_overload_compile_test() return map.erase(c); } +#ifdef BOOST_UNORDERED_FOA_TESTS +void +#else transparent_unordered_map::const_iterator +#endif map_erase_const_overload_compile_test() { convertible_to_const_iterator c; @@ -1079,6 +1100,7 @@ map_erase_const_overload_compile_test() return map.erase(c); } +#ifndef BOOST_UNORDERED_FOA_TESTS typedef boost::unordered_multimap transparent_unordered_multimap; @@ -1101,6 +1123,7 @@ multimap_erase_const_overload_compile_test() pos = c; return map.erase(c); } +#endif template void test_map_transparent_erase() { @@ -1197,14 +1220,25 @@ template void test_map_non_transparent_erase() BOOST_TEST_EQ(key::count_, key_count); } +#if BOOST_UNORDERED_FOA_TESTS +typedef boost::unordered_flat_set + transparent_unordered_set; +#else typedef boost::unordered_set transparent_unordered_set; typedef boost::unordered_multiset transparent_unordered_multiset; +#endif -transparent_unordered_set::iterator set_erase_overload_compile_test() +#ifdef BOOST_UNORDERED_FOA_TESTS +void +#else +transparent_unordered_set::iterator +#endif +set_erase_overload_compile_test() { convertible_to_iterator c; transparent_unordered_set set; @@ -1213,7 +1247,11 @@ transparent_unordered_set::iterator set_erase_overload_compile_test() return set.erase(c); } +#ifdef BOOST_UNORDERED_FOA_TESTS +void +#else transparent_unordered_set::const_iterator +#endif set_erase_const_overload_compile_test() { convertible_to_const_iterator c; @@ -1223,6 +1261,7 @@ set_erase_const_overload_compile_test() return set.erase(c); } +#ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_multiset::iterator multiset_erase_overload_compile_test() { convertible_to_iterator c; @@ -1241,6 +1280,7 @@ multiset_erase_const_overload_compile_test() pos = c; return set.erase(c); } +#endif template void test_set_transparent_erase() { @@ -1337,6 +1377,7 @@ template void test_set_non_transparent_erase() BOOST_TEST_EQ(key::count_, key_count); } +#ifndef BOOST_UNORDERED_FOA_TESTS // test that in the presence of the member function template `extract()`, we // still invoke the correct iterator overloads when the type is implicitly // convertible @@ -1359,9 +1400,11 @@ multimap_extract_const_overload_compile_test() pos = c; return map.extract(c); } +#endif template void test_map_transparent_extract() { +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename UnorderedMap::node_type node_type; typedef typename UnorderedMap::const_iterator const_iterator; typedef std::pair const_iterator_pair; @@ -1397,10 +1440,12 @@ template void test_map_transparent_extract() BOOST_TEST(nh.empty()); BOOST_TEST_EQ(key::count_, expected_key_count); +#endif } template void test_map_non_transparent_extract() { +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename UnorderedMap::node_type node_type; typedef typename UnorderedMap::const_iterator const_iterator; typedef std::pair const_iterator_pair; @@ -1441,8 +1486,10 @@ template void test_map_non_transparent_extract() ++key_count; BOOST_TEST(nh.empty()); BOOST_TEST_EQ(key::count_, key_count); +#endif } +#ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_set::node_type set_extract_overload_compile_test() { convertible_to_iterator c; @@ -1480,9 +1527,11 @@ multiset_extract_const_overload_compile_test() pos = c; return set.extract(c); } +#endif template void test_set_transparent_extract() { +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename UnorderedSet::node_type node_type; count_reset(); @@ -1526,10 +1575,12 @@ template void test_set_transparent_extract() BOOST_TEST_EQ(set.size(), set_size); BOOST_TEST_EQ(key::count_, expected_key_count); +#endif } template void test_set_non_transparent_extract() { +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename UnorderedSet::node_type node_type; count_reset(); @@ -1583,14 +1634,23 @@ template void test_set_non_transparent_extract() BOOST_TEST_EQ(set.size(), set_size); BOOST_TEST_EQ(key::count_, key_count); +#endif } +template struct map_type +{ +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_map type; +#else + typedef boost::unordered_map type; +#endif +}; + void test_unordered_map() { { - typedef boost::unordered_map - unordered_map; + typedef typename map_type::type unordered_map; test_map_transparent_count(); test_map_transparent_find(); @@ -1602,7 +1662,7 @@ void test_unordered_map() { // non-transparent Hash, non-transparent KeyEqual // - typedef boost::unordered_map unordered_map; + typedef typename map_type::type unordered_map; test_map_non_transparent_count(); test_map_non_transparent_find(); @@ -1614,7 +1674,7 @@ void test_unordered_map() { // transparent Hash, non-transparent KeyEqual // - typedef boost::unordered_map + typedef typename map_type::type unordered_map; test_map_non_transparent_count(); @@ -1627,7 +1687,7 @@ void test_unordered_map() { // non-transparent Hash, transparent KeyEqual // - typedef boost::unordered_map + typedef typename map_type::type unordered_map; test_map_non_transparent_count(); @@ -1638,6 +1698,7 @@ void test_unordered_map() } } +#ifndef BOOST_UNORDERED_FOA_TESTS void test_unordered_multimap() { { @@ -1691,12 +1752,23 @@ void test_unordered_multimap() test_map_non_transparent_extract(); } } +#endif + +template struct set_type +{ +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set type; +#else + typedef boost::unordered_set type; +#endif +}; void test_unordered_set() { { - typedef boost::unordered_set - unordered_set; + typedef + typename set_type::type + unordered_set; test_set_transparent_count(); test_set_transparent_find(); @@ -1708,7 +1780,7 @@ void test_unordered_set() { // non-transparent Hash, non-transparent KeyEqual // - typedef boost::unordered_set unordered_set; + typedef typename set_type::type unordered_set; test_set_non_transparent_count(); test_set_non_transparent_find(); @@ -1720,8 +1792,8 @@ void test_unordered_set() { // transparent Hash, non-transparent KeyEqual // - typedef boost::unordered_set - unordered_set; + typedef + typename set_type::type unordered_set; test_set_non_transparent_count(); test_set_non_transparent_find(); @@ -1733,8 +1805,8 @@ void test_unordered_set() { // non-transparent Hash, transparent KeyEqual // - typedef boost::unordered_set - unordered_set; + typedef + typename set_type::type unordered_set; test_set_non_transparent_count(); test_set_non_transparent_find(); @@ -1744,6 +1816,7 @@ void test_unordered_set() } } +#ifndef BOOST_UNORDERED_FOA_TESTS void test_unordered_multiset() { { @@ -1796,12 +1869,16 @@ void test_unordered_multiset() test_set_non_transparent_extract(); } } +#endif UNORDERED_AUTO_TEST (transparent_ops) { test_unordered_map(); - test_unordered_multimap(); test_unordered_set(); + +#ifndef BOOST_UNORDERED_FOA_TESTS + test_unordered_multimap(); test_unordered_multiset(); +#endif } RUN_TESTS() From 72bca09429dfcac255d586a388df1efb038cd120 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 11:09:17 -0700 Subject: [PATCH 156/279] Remove extraneous usage of typename --- test/unordered/transparent_tests.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index d1e67870..9d230a18 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1649,8 +1649,8 @@ template struct map_type void test_unordered_map() { { - typedef typename map_type::type unordered_map; + typedef map_type::type + unordered_map; test_map_transparent_count(); test_map_transparent_find(); @@ -1662,7 +1662,7 @@ void test_unordered_map() { // non-transparent Hash, non-transparent KeyEqual // - typedef typename map_type::type unordered_map; + typedef map_type::type unordered_map; test_map_non_transparent_count(); test_map_non_transparent_find(); @@ -1674,7 +1674,7 @@ void test_unordered_map() { // transparent Hash, non-transparent KeyEqual // - typedef typename map_type::type + typedef map_type::type unordered_map; test_map_non_transparent_count(); @@ -1687,7 +1687,7 @@ void test_unordered_map() { // non-transparent Hash, transparent KeyEqual // - typedef typename map_type::type + typedef map_type::type unordered_map; test_map_non_transparent_count(); @@ -1766,9 +1766,8 @@ template struct set_type void test_unordered_set() { { - typedef - typename set_type::type - unordered_set; + typedef set_type::type + unordered_set; test_set_transparent_count(); test_set_transparent_find(); @@ -1780,7 +1779,7 @@ void test_unordered_set() { // non-transparent Hash, non-transparent KeyEqual // - typedef typename set_type::type unordered_set; + typedef set_type::type unordered_set; test_set_non_transparent_count(); test_set_non_transparent_find(); @@ -1792,8 +1791,7 @@ void test_unordered_set() { // transparent Hash, non-transparent KeyEqual // - typedef - typename set_type::type unordered_set; + typedef set_type::type unordered_set; test_set_non_transparent_count(); test_set_non_transparent_find(); @@ -1805,8 +1803,7 @@ void test_unordered_set() { // non-transparent Hash, transparent KeyEqual // - typedef - typename set_type::type unordered_set; + typedef set_type::type unordered_set; test_set_non_transparent_count(); test_set_non_transparent_find(); From 09f0b7c0a81ce5f86733c1ba073cdb1d16b7349f Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 12:32:10 -0700 Subject: [PATCH 157/279] Add swap_tests --- .../boost/unordered/unordered_flat_map.hpp | 14 +++++ .../boost/unordered/unordered_flat_set.hpp | 14 +++++ test/Jamfile.v2 | 3 +- test/unordered/swap_tests.cpp | 63 ++++++++++++++++--- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 3c687124..6a58269a 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -295,6 +295,12 @@ namespace boost { return table_.erase(key); } + void swap(unordered_flat_map& rhs) noexcept( + noexcept(std::declval().swap(std::declval()))) + { + table_.swap(rhs.table_); + } + /// Lookup /// @@ -493,6 +499,14 @@ namespace boost { { return !(lhs == rhs); } + + template + void swap(unordered_flat_map& lhs, + unordered_flat_map& rhs) + noexcept(noexcept(lhs.swap(rhs))) + { + lhs.swap(rhs); + } } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 297e4554..83b57484 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -223,6 +223,12 @@ namespace boost { return table_.erase(key); } + void swap(unordered_flat_set& rhs) noexcept( + noexcept(std::declval().swap(std::declval()))) + { + table_.swap(rhs.table_); + } + /// Lookup /// @@ -390,6 +396,14 @@ namespace boost { { return !(lhs == rhs); } + + template + void swap(unordered_flat_set& lhs, + unordered_flat_set& rhs) + noexcept(noexcept(lhs.swap(rhs))) + { + lhs.swap(rhs); + } } // namespace unordered } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 628553a6..c86df6f2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -114,6 +114,7 @@ build_foa find_tests ; build_foa at_tests ; build_foa load_factor_tests ; build_foa rehash_tests ; +build_foa equality_tests ; +build_foa swap_tests ; build_foa transparent_tests ; build_foa contains_tests ; -build_foa equality_tests ; diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index 9a7106ef..ed7feade 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -5,8 +5,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -139,6 +145,53 @@ namespace swap_tests { } } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + template bool is_propagate(T*) + { + return T::allocator_type::is_propagate_on_swap; + } + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map >* test_map_std_alloc; + + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map >* test_map; + + boost::unordered_flat_set >* + test_set_prop_swap; + boost::unordered_flat_map >* + test_map_prop_swap; + + boost::unordered_flat_set >* + test_set_no_prop_swap; + boost::unordered_flat_map >* + test_map_no_prop_swap; + + UNORDERED_AUTO_TEST (check_traits) { + BOOST_TEST(!is_propagate(test_set)); + BOOST_TEST(is_propagate(test_set_prop_swap)); + BOOST_TEST(!is_propagate(test_set_no_prop_swap)); + } + + UNORDERED_TEST(swap_tests1, + ((test_map_std_alloc)(test_set)(test_map)(test_set_prop_swap)(test_map_prop_swap)(test_set_no_prop_swap)(test_map_no_prop_swap))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(swap_tests2, + ((test_set)(test_map)(test_set_prop_swap)(test_map_prop_swap)(test_set_no_prop_swap)(test_map_no_prop_swap))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_map >* test_map_std_alloc; @@ -178,15 +231,6 @@ namespace swap_tests { test::cxx11_allocator >* test_multimap_no_prop_swap; - template bool is_propagate(T*) - { - return T::allocator_type::is_propagate_on_swap; - } - - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_AUTO_TEST (check_traits) { BOOST_TEST(!is_propagate(test_set)); BOOST_TEST(is_propagate(test_set_prop_swap)); @@ -207,5 +251,6 @@ namespace swap_tests { test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)( test_multimap_no_prop_swap))( (default_generator)(generate_collisions)(limited_range))) +#endif } RUN_TESTS() From 0bdfa3c39ea96797c95d03a0a99c2353958c9aa4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 14:17:50 -0700 Subject: [PATCH 158/279] Add forwarding tests --- .../unordered/unordered_flat_map_fwd.hpp | 21 ++++++++- .../unordered/unordered_flat_set_fwd.hpp | 21 ++++++++- test/Jamfile.v2 | 2 + test/unordered/fwd_map_test.cpp | 36 +++++++++++++++ test/unordered/fwd_set_test.cpp | 45 ++++++++++++++++++- 5 files changed, 122 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map_fwd.hpp b/include/boost/unordered/unordered_flat_map_fwd.hpp index 154b9093..2c34d0fb 100644 --- a/include/boost/unordered/unordered_flat_map_fwd.hpp +++ b/include/boost/unordered/unordered_flat_map_fwd.hpp @@ -22,9 +22,28 @@ namespace boost { class KeyEqual = std::equal_to, class Allocator = std::allocator > > class unordered_flat_map; - } + + template + bool operator==( + unordered_flat_map const& lhs, + unordered_flat_map const& rhs); + + template + bool operator!=( + unordered_flat_map const& lhs, + unordered_flat_map const& rhs); + + template + void swap(unordered_flat_map& lhs, + unordered_flat_map& rhs) + noexcept(noexcept(lhs.swap(rhs))); + } // namespace unordered using boost::unordered::unordered_flat_map; + + using boost::unordered::swap; + using boost::unordered::operator==; + using boost::unordered::operator!=; } // namespace boost #endif diff --git a/include/boost/unordered/unordered_flat_set_fwd.hpp b/include/boost/unordered/unordered_flat_set_fwd.hpp index 91550cc0..51f534ef 100644 --- a/include/boost/unordered/unordered_flat_set_fwd.hpp +++ b/include/boost/unordered/unordered_flat_set_fwd.hpp @@ -22,9 +22,28 @@ namespace boost { class KeyEqual = std::equal_to, class Allocator = std::allocator > class unordered_flat_set; - } + + template + bool operator==( + unordered_flat_set const& lhs, + unordered_flat_set const& rhs); + + template + bool operator!=( + unordered_flat_set const& lhs, + unordered_flat_set const& rhs); + + template + void swap(unordered_flat_set& lhs, + unordered_flat_set& rhs) + noexcept(noexcept(lhs.swap(rhs))); + } // namespace unordered using boost::unordered::unordered_flat_set; + + using boost::unordered::swap; + using boost::unordered::operator==; + using boost::unordered::operator!=; } // namespace boost #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c86df6f2..2a3e4f84 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -102,6 +102,8 @@ rule build_foa ( name ) run unordered/$(name).cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_$(name) ; } +build_foa fwd_set_test ; +build_foa fwd_map_test ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/fwd_map_test.cpp b/test/unordered/fwd_map_test.cpp index 0c7df04f..30acf14e 100644 --- a/test/unordered/fwd_map_test.cpp +++ b/test/unordered/fwd_map_test.cpp @@ -5,10 +5,39 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include +#endif #include "../helpers/postfix.hpp" // clang-format on +#ifdef BOOST_UNORDERED_FOA_TESTS +template +void call_swap( + boost::unordered_flat_map& x, boost::unordered_flat_map& y) +{ + swap(x, y); +} + +template +bool call_equals( + boost::unordered_flat_map& x, boost::unordered_flat_map& y) +{ + return x == y; +} + +template +bool call_not_equals( + boost::unordered_flat_map& x, boost::unordered_flat_map& y) +{ + return x != y; +} + +#include +#else template void call_swap(boost::unordered_map& x, boost::unordered_map& y) { @@ -50,10 +79,15 @@ bool call_not_equals( } #include +#endif #include "../helpers/test.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +typedef boost::unordered_flat_map int_map; +#else typedef boost::unordered_map int_map; typedef boost::unordered_multimap int_multimap; +#endif UNORDERED_AUTO_TEST (use_map_fwd_declared_function) { int_map x, y; @@ -71,11 +105,13 @@ UNORDERED_AUTO_TEST (use_map_fwd_declared_function) { BOOST_TEST(call_not_equals(x, y)); } +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (use_multimap_fwd_declared_function) { int_multimap x, y; call_swap(x, y); BOOST_TEST(call_equals(x, y)); BOOST_TEST(!call_not_equals(x, y)); } +#endif RUN_TESTS() diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 6512522a..58de82d5 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -5,7 +5,12 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -20,6 +25,31 @@ struct false_type false_type is_unordered_set_impl(void*); +#ifdef BOOST_UNORDERED_FOA_TESTS +template +true_type is_unordered_set_impl( + boost::unordered_flat_set*); + +template +void call_swap(boost::unordered_flat_set& x, boost::unordered_flat_set& y) +{ + swap(x, y); +} + +template +bool call_equals( + boost::unordered_flat_set& x, boost::unordered_flat_set& y) +{ + return x == y; +} + +template +bool call_not_equals( + boost::unordered_flat_set& x, boost::unordered_flat_set& y) +{ + return x != y; +} +#else template true_type is_unordered_set_impl( boost::unordered_set*); @@ -41,7 +71,9 @@ bool call_not_equals(boost::unordered_set& x, boost::unordered_set& y) { return x != y; } +#endif +#ifndef BOOST_UNORDERED_FOA_TESTS template void call_swap(boost::unordered_multiset& x, boost::unordered_multiset& y) { @@ -61,20 +93,29 @@ bool call_not_equals( { return x != y; } +#endif #include "../helpers/test.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +typedef boost::unordered_flat_set int_set; +#else typedef boost::unordered_set int_set; typedef boost::unordered_multiset int_multiset; +#endif UNORDERED_AUTO_TEST (use_fwd_declared_trait_without_definition) { BOOST_TEST(sizeof(is_unordered_set_impl((int_set*)0)) == sizeof(true_type)); } +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#else #include +#endif UNORDERED_AUTO_TEST (use_fwd_declared_trait) { - boost::unordered_set x; + int_set x; BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type)); BOOST_TEST(sizeof(is_unordered_set_impl((int*)0)) == sizeof(false_type)); @@ -96,11 +137,13 @@ UNORDERED_AUTO_TEST (use_set_fwd_declared_function) { BOOST_TEST(call_not_equals(x, y)); } +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (use_multiset_fwd_declared_function) { int_multiset x, y; call_swap(x, y); BOOST_TEST(call_equals(x, y)); BOOST_TEST(!call_not_equals(x, y)); } +#endif RUN_TESTS() From 91f5925c41fd6f1c7d2ee0cc1ea67409e8edd1d1 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 15:43:38 -0700 Subject: [PATCH 159/279] Replace naked throw statements with boost::throw_exception() --- include/boost/unordered/unordered_flat_map.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 6a58269a..f9309ac7 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -313,7 +314,8 @@ namespace boost { // TODO: someday refactor this to conditionally serialize the key and // include it in the error message // - throw std::out_of_range("key was not found in unordered_flat_map"); + boost::throw_exception( + std::out_of_range("key was not found in unordered_flat_map")); } mapped_type const& at(key_type const& key) const @@ -322,7 +324,8 @@ namespace boost { if (pos != table_.end()) { return pos->second; } - throw std::out_of_range("key was not found in unordered_flat_map"); + boost::throw_exception( + std::out_of_range("key was not found in unordered_flat_map")); } mapped_type& operator[](key_type const& key) From e9a94cb62a2b0395e7ce9efc17d42651362fb328 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 10 Oct 2022 15:47:00 -0700 Subject: [PATCH 160/279] Force inlining for find() member functions in the flat containers --- include/boost/unordered/unordered_flat_map.hpp | 11 +++++++---- include/boost/unordered/unordered_flat_set.hpp | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index f9309ac7..46784ac4 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -353,15 +353,18 @@ namespace boost { return pos != table_.end() ? 1 : 0; } - iterator find(key_type const& key) { return table_.find(key); } + BOOST_FORCEINLINE iterator find(key_type const& key) + { + return table_.find(key); + } - const_iterator find(key_type const& key) const + BOOST_FORCEINLINE const_iterator find(key_type const& key) const { return table_.find(key); } template - typename std::enable_if< + BOOST_FORCEINLINE typename std::enable_if< boost::unordered::detail::are_transparent::value, iterator>::type find(K const& key) @@ -370,7 +373,7 @@ namespace boost { } template - typename std::enable_if< + BOOST_FORCEINLINE typename std::enable_if< boost::unordered::detail::are_transparent::value, const_iterator>::type find(K const& key) const diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 83b57484..98f2534c 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -247,15 +247,18 @@ namespace boost { return pos != table_.end() ? 1 : 0; } - iterator find(key_type const& key) { return table_.find(key); } + BOOST_FORCEINLINE iterator find(key_type const& key) + { + return table_.find(key); + } - const_iterator find(key_type const& key) const + BOOST_FORCEINLINE const_iterator find(key_type const& key) const { return table_.find(key); } template - typename std::enable_if< + BOOST_FORCEINLINE typename std::enable_if< boost::unordered::detail::are_transparent::value, iterator>::type find(K const& key) @@ -264,7 +267,7 @@ namespace boost { } template - typename std::enable_if< + BOOST_FORCEINLINE typename std::enable_if< boost::unordered::detail::are_transparent::value, const_iterator>::type find(K const& key) const From f2afbe9f85dad356d58866eabb21ba64276b9718 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 09:09:20 +0200 Subject: [PATCH 161/279] silenced unused capture warning --- include/boost/unordered/detail/foa.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index ee53046c..c5045685 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1168,6 +1168,7 @@ public: }, [&,this]{ /* else */ BOOST_ASSERT(al()==x.al()); + (void)this; /* makes sure captured this is used */ }); swap(size_,x.size_); swap(arrays,x.arrays); From 316eeea9830751e4e65fc022e34c9112ac595d17 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 10:46:07 +0200 Subject: [PATCH 162/279] dropped BOOST_FORCEINLINE in insert --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c5045685..7486c350 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1114,12 +1114,12 @@ public: typename std::enable_if< std::is_constructible::value>* =nullptr > - BOOST_FORCEINLINE std::pair insert(T&& x) + /*BOOST_FORCEINLINE*/ std::pair insert(T&& x) { return emplace_impl(value_from(std::forward(x))); } - BOOST_FORCEINLINE std::pair insert(init_type&& x) + /*BOOST_FORCEINLINE*/ std::pair insert(init_type&& x) { return emplace_impl(std::move(x)); } From c42d86ac0d44b44076bcdae021ee1c8e6ac32f6b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 10:52:51 +0200 Subject: [PATCH 163/279] reverted --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 7486c350..c5045685 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1114,12 +1114,12 @@ public: typename std::enable_if< std::is_constructible::value>* =nullptr > - /*BOOST_FORCEINLINE*/ std::pair insert(T&& x) + BOOST_FORCEINLINE std::pair insert(T&& x) { return emplace_impl(value_from(std::forward(x))); } - /*BOOST_FORCEINLINE*/ std::pair insert(init_type&& x) + BOOST_FORCEINLINE std::pair insert(init_type&& x) { return emplace_impl(std::move(x)); } From 545ad4f7adf8b97e8bdb013d7dae976848615f66 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 10:54:01 +0200 Subject: [PATCH 164/279] temporarily s/init_type/value_type in brace-init insert --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c5045685..f22f8bf6 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1119,7 +1119,7 @@ public: return emplace_impl(value_from(std::forward(x))); } - BOOST_FORCEINLINE std::pair insert(init_type&& x) + BOOST_FORCEINLINE std::pair insert(/*init_type*/value_type&& x) { return emplace_impl(std::move(x)); } From 7abd7bb36d284eeca157bf00d30c5b0fa39ac073 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 11:48:46 +0200 Subject: [PATCH 165/279] reverted --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f22f8bf6..c5045685 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1119,7 +1119,7 @@ public: return emplace_impl(value_from(std::forward(x))); } - BOOST_FORCEINLINE std::pair insert(/*init_type*/value_type&& x) + BOOST_FORCEINLINE std::pair insert(init_type&& x) { return emplace_impl(std::move(x)); } From 3b1f635926cafaebac1cb706b943cf376ce27a5f Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 11:50:17 +0200 Subject: [PATCH 166/279] reverted c4cc805063bfd0c78e8f0febaea23347ad10b1a5 --- include/boost/unordered/detail/foa.hpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c5045685..c2b42370 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -604,14 +604,7 @@ struct xmx_mix template static inline std::size_t mix(const Hash& h,const T& x) { - //return xmx(h(x)); - boost::uint64_t z=(boost::uint64_t)(h(x)); - - z^=z>>23; - z*=0xff51afd7ed558ccdull; - z^=z>>23; - - return (std::size_t)z; + return xmx(h(x)); } }; From e163aa465c6c885578ea89fd3f7dfd2b151ffcf9 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 11:51:16 +0200 Subject: [PATCH 167/279] reverted c7836659d1b3ee519e0665817e5aeb18b16181a7 --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c2b42370..049dfada 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1461,7 +1461,7 @@ private: return res; } -#if 1 +#if 0 template iterator nosize_unchecked_emplace_at( const arrays_type& arrays_,std::size_t pos0,std::size_t hash, From becd6078b3c58264966aca5f7f1c10893ed30af6 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 17:10:39 +0200 Subject: [PATCH 168/279] temporarily used value_type&& for brace-init insert --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 049dfada..b743cc21 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1112,9 +1112,9 @@ public: return emplace_impl(value_from(std::forward(x))); } - BOOST_FORCEINLINE std::pair insert(init_type&& x) + BOOST_FORCEINLINE std::pair insert(value_type&& x) { - return emplace_impl(std::move(x)); + return emplace_impl(value_from(std::move(x))); } template< From 59c84cb744767296da389261f605d85962eec816 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 17:20:22 +0200 Subject: [PATCH 169/279] dropped BOOST_FORCEINLINE in brace-init insert --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index b743cc21..864884f6 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1112,7 +1112,7 @@ public: return emplace_impl(value_from(std::forward(x))); } - BOOST_FORCEINLINE std::pair insert(value_type&& x) + /*BOOST_FORCEINLINE*/ std::pair insert(value_type&& x) { return emplace_impl(value_from(std::move(x))); } From 648fb7b99d29333db2a95a2e9eda179e3571c8f1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 17:30:23 +0200 Subject: [PATCH 170/279] reverted two prior --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 864884f6..049dfada 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1112,9 +1112,9 @@ public: return emplace_impl(value_from(std::forward(x))); } - /*BOOST_FORCEINLINE*/ std::pair insert(value_type&& x) + BOOST_FORCEINLINE std::pair insert(init_type&& x) { - return emplace_impl(value_from(std::move(x))); + return emplace_impl(std::move(x)); } template< From 858737fd88b355d47217fe3bcc66f6e8faeede38 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 17:55:55 +0200 Subject: [PATCH 171/279] s/move/forward in brace-init insert --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 049dfada..b1dd5f87 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1114,7 +1114,7 @@ public: BOOST_FORCEINLINE std::pair insert(init_type&& x) { - return emplace_impl(std::move(x)); + return emplace_impl(std::forward(x)); } template< From 35118b5a71952dee234a3e3f2a929e0c852495f6 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 11 Oct 2022 20:35:59 +0200 Subject: [PATCH 172/279] reverted --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index b1dd5f87..049dfada 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1114,7 +1114,7 @@ public: BOOST_FORCEINLINE std::pair insert(init_type&& x) { - return emplace_impl(std::forward(x)); + return emplace_impl(std::move(x)); } template< From ccd40d0c44e2d19e3b452aa9b266837489159961 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 11 Oct 2022 15:20:13 -0700 Subject: [PATCH 173/279] Update fancy pointer's implementation of `pointer_to` to support all types by using boost::addressof() --- test/objects/minimal.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index f5298265..cb1fe9b0 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -11,6 +11,7 @@ #if !defined(BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER) #define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER +#include #include #include #include @@ -320,7 +321,7 @@ namespace test { bool operator!() const { return !ptr_; } static ptr pointer_to(T& p) { - return ptr(&p); + return ptr(boost::addressof(p)); } // I'm not using the safe bool idiom because the containers should be From 4a8d6877789684b55cc3860c3ffc724f91ad87ea Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 11 Oct 2022 15:20:37 -0700 Subject: [PATCH 174/279] Add compile_set tests with stub for merge() --- include/boost/unordered/detail/foa.hpp | 15 ++- .../boost/unordered/unordered_flat_set.hpp | 46 +++++++ test/Jamfile.v2 | 1 + test/unordered/compile_set.cpp | 121 +++++++++++++++++- test/unordered/compile_tests.hpp | 35 +++++ 5 files changed, 209 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 049dfada..63d5e827 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -618,10 +618,13 @@ class table_iterator { public: using difference_type=std::ptrdiff_t; - using value_type=typename std::conditional::type; - using pointer=value_type*; + using value_type=Value; + using pointer= + typename std::conditional::type; using reference=value_type&; using iterator_category=std::forward_iterator_tag; + using element_type= + typename std::conditional::type; table_iterator()=default; template::type* =nullptr> @@ -746,10 +749,12 @@ struct table_arrays static void delete_(Allocator& al,table_arrays& arrays)noexcept { using alloc_traits=boost::allocator_traits; + using pointer=typename alloc_traits::pointer; + using pointer_traits=boost::pointer_traits; if(arrays.elements){ alloc_traits::deallocate( - al,arrays.elements,buffer_size(arrays.groups_size_mask+1)); + al,pointer_traits::pointer_to(*arrays.elements),buffer_size(arrays.groups_size_mask+1)); } } @@ -981,7 +986,7 @@ public: static constexpr auto pocca= alloc_traits::propagate_on_container_copy_assignment::value; - if(this!=&x){ + if(this!=std::addressof(x)){ clear(); h()=x.h(); pred()=x.pred(); @@ -1025,7 +1030,7 @@ public: unchecked_insert(type_policy::move(*p)); }; - if(this!=&x){ + if(this!=std::addressof(x)){ clear(); h()=std::move(x.h()); pred()=std::move(x.pred()); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 98f2534c..9a740448 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -46,6 +46,7 @@ namespace boost { using key_type = Key; using value_type = typename set_types::value_type; using size_type = std::size_t; + using difference_type = std::ptrdiff_t; using hasher = Hash; using key_equal = KeyEqual; using allocator_type = Allocator; @@ -68,6 +69,11 @@ namespace boost { { } + unordered_flat_set(size_type n, hasher const& h, allocator_type const& a) + : unordered_flat_set(n, h, key_equal(), a) + { + } + explicit unordered_flat_set(allocator_type const& a) : unordered_flat_set(0, a) { @@ -82,6 +88,20 @@ namespace boost { this->insert(first, last); } + template + unordered_flat_set( + InputIt first, InputIt last, size_type n, allocator_type const& a) + : unordered_flat_set(first, last, n, hasher(), key_equal(), a) + { + } + + template + unordered_flat_set(Iterator first, Iterator last, size_type n, + hasher const& h, allocator_type const& a) + : unordered_flat_set(first, last, n, h, key_equal(), a) + { + } + unordered_flat_set(unordered_flat_set const& other) : table_(other.table_) { } @@ -113,6 +133,18 @@ namespace boost { { } + unordered_flat_set(std::initializer_list init, size_type n, + allocator_type const& a) + : unordered_flat_set(init, n, hasher(), key_equal(), a) + { + } + + unordered_flat_set(std::initializer_list init, size_type n, + hasher const& h, allocator_type const& a) + : unordered_flat_set(init, n, h, key_equal(), a) + { + } + ~unordered_flat_set() = default; unordered_flat_set& operator=(unordered_flat_set const& other) @@ -154,6 +186,8 @@ namespace boost { size_type size() const noexcept { return table_.size(); } + size_type max_size() const noexcept { return table_.max_size(); } + /// Modifiers /// @@ -229,6 +263,18 @@ namespace boost { table_.swap(rhs.table_); } + template + void merge(unordered_flat_set& source) + { + (void) source; + } + + template + void merge(unordered_flat_set&& source) + { + (void) source; + } + /// Lookup /// diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2a3e4f84..fa9d474c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -104,6 +104,7 @@ rule build_foa ( name ) build_foa fwd_set_test ; build_foa fwd_map_test ; +build_foa compile_set ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index 727294f3..32e4a170 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -8,7 +8,12 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -18,6 +23,28 @@ // Explicit instantiation to catch compile-time errors +#ifdef BOOST_UNORDERED_FOA_TESTS + +// emulates what was already done for previous tests but without leaking to +// the detail namespace +// +template +class instantiate_flat_set +{ + typedef boost::unordered_flat_set container; + container x; +}; + +template class instantiate_flat_set, std::equal_to, + test::minimal::allocator >; + +template class instantiate_flat_set, + test::minimal::equal_to, + test::minimal::allocator >; + +#else + #define INSTANTIATE(type) \ template class boost::unordered::detail::instantiate_##type @@ -35,6 +62,8 @@ INSTANTIATE(multiset), test::minimal::allocator >; +#endif + UNORDERED_AUTO_TEST (test0) { test::minimal::constructor_param x; @@ -42,6 +71,19 @@ UNORDERED_AUTO_TEST (test0) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set int_set; + + boost::unordered_flat_set, std::equal_to, + test::minimal::cxx11_allocator > + int_set2; + + boost::unordered_flat_set, + test::minimal::equal_to, + test::minimal::allocator > + set; +#else boost::unordered_set int_set; boost::unordered_set, std::equal_to, @@ -53,11 +95,13 @@ UNORDERED_AUTO_TEST (test0) { test::minimal::equal_to, test::minimal::allocator > set; +#endif container_test(int_set, 0); container_test(int_set2, 0); container_test(set, assignable); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset int_multiset; @@ -75,11 +119,27 @@ UNORDERED_AUTO_TEST (test0) { container_test(int_multiset, 0); container_test(int_multiset2, 0); container_test(multiset, assignable); +#endif } UNORDERED_AUTO_TEST (equality_tests) { typedef test::minimal::copy_constructible_equality_comparable value_type; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set int_set; + + boost::unordered_flat_set, std::equal_to, + test::minimal::cxx11_allocator > + int_set2; + + boost::unordered_flat_set< + test::minimal::copy_constructible_equality_comparable, + test::minimal::hash, + test::minimal::equal_to< + test::minimal::copy_constructible_equality_comparable>, + test::minimal::allocator > + set; +#else boost::unordered_set int_set; boost::unordered_set, std::equal_to, @@ -92,11 +152,13 @@ UNORDERED_AUTO_TEST (equality_tests) { test::minimal::copy_constructible_equality_comparable>, test::minimal::allocator > set; +#endif equality_test(int_set); equality_test(int_set2); equality_test(set); +#ifndef BOOST_UNORDERED_FOA_TESTS boost::unordered_multiset int_multiset; boost::unordered_multiset, std::equal_to, @@ -114,6 +176,7 @@ UNORDERED_AUTO_TEST (equality_tests) { equality_test(int_multiset); equality_test(int_multiset2); equality_test(multiset); +#endif } UNORDERED_AUTO_TEST (test1) { @@ -122,12 +185,19 @@ UNORDERED_AUTO_TEST (test1) { int value = 0; BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set." << std::endl; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set set; + boost::unordered_flat_set, std::equal_to, + test::minimal::cxx11_allocator > + set2; +#else boost::unordered_set set; boost::unordered_set, std::equal_to, test::minimal::cxx11_allocator > set2; +#endif unordered_unique_test(set, value); unordered_set_test(set, value); @@ -137,6 +207,7 @@ UNORDERED_AUTO_TEST (test1) { unordered_set_test(set2, value); unordered_copyable_test(set2, value, value, hash, equal_to); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl; boost::unordered_multiset multiset; @@ -152,6 +223,7 @@ UNORDERED_AUTO_TEST (test1) { unordered_equivalent_test(multiset2, value); unordered_set_test(multiset2, value); unordered_copyable_test(multiset2, value, value, hash, equal_to); +#endif } UNORDERED_AUTO_TEST (test2) { @@ -163,18 +235,26 @@ UNORDERED_AUTO_TEST (test2) { test::minimal::equal_to equal_to(x); BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; - +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set, + test::minimal::equal_to, + test::minimal::allocator > + set; +#else boost::unordered_set, test::minimal::equal_to, test::minimal::allocator > set; +#endif unordered_unique_test(set, assignable); unordered_set_test(set, assignable); unordered_copyable_test(set, assignable, assignable, hash, equal_to); unordered_set_member_test(set, assignable); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset equal_to(x); BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; - +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set, + test::minimal::equal_to, + test::minimal::allocator > + set; +#else boost::unordered_set, test::minimal::equal_to, test::minimal::allocator > set; +#endif // unordered_unique_test(set, movable1); unordered_set_test(set, movable1); unordered_movable_test(set, movable1, movable1, hash, equal_to); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset equal_to(x); BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; - +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set, + test::minimal::equal_to, + test::minimal::allocator > + set; +#else boost::unordered_set, test::minimal::equal_to, test::minimal::allocator > set; +#endif // unordered_unique_test(set, movable2); unordered_set_test(set, movable2); unordered_movable_test(set, movable2, movable2, hash, equal_to); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset equal_to(x); BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; - +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set, + test::minimal::equal_to > + set; +#else boost::unordered_set, test::minimal::equal_to > set; +#endif unordered_destructible_test(set); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset x; + x.emplace(lwg2059_key(10)); + x.erase(x.begin()); +#else { boost::unordered_set x; x.emplace(lwg2059_key(10)); @@ -308,6 +420,7 @@ UNORDERED_AUTO_TEST (lwg2059) { x.emplace(lwg2059_key(10)); x.erase(x.begin()); } +#endif } RUN_TESTS() diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index bb5256f8..3975cd07 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -70,7 +70,9 @@ template void container_test(X& r, T const&) typedef typename X::reference reference; typedef typename X::const_reference const_reference; +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::node_type node_type; +#endif typedef typename X::allocator_type allocator_type; @@ -97,8 +99,10 @@ template void container_test(X& r, T const&) // node_type +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_STATIC_ASSERT(( boost::is_same::value)); +#endif // difference_type @@ -167,6 +171,7 @@ template void container_test(X& r, T const&) sink(X(rvalue(a_const), m)); X c3(rvalue(a_const), m); +#ifndef BOOST_UNORDERED_FOA_TESTS // node_type implicit_construct(); @@ -193,6 +198,7 @@ template void container_test(X& r, T const&) test::check_return_type::equals(n_const.empty()); TEST_NOEXCEPT_EXPR(!n_const); TEST_NOEXCEPT_EXPR(n_const.empty()); +#endif // Avoid unused variable warnings: @@ -262,24 +268,30 @@ template void unordered_set_test(X& r, Key const&) typedef typename X::iterator iterator; typedef typename X::const_iterator const_iterator; +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::local_iterator local_iterator; typedef typename X::const_local_iterator const_local_iterator; +#endif typedef typename std::iterator_traits::pointer iterator_pointer; typedef typename std::iterator_traits::pointer const_iterator_pointer; +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename std::iterator_traits::pointer local_iterator_pointer; typedef typename std::iterator_traits::pointer const_local_iterator_pointer; +#endif BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); +#endif // pointer_traits @@ -299,6 +311,8 @@ template void unordered_set_test(X& r, Key const&) BOOST_STATIC_ASSERT((boost::is_same::difference_type>::value)); + (void) r; +#ifndef BOOST_UNORDERED_FOA_TESTS // pointer_traits BOOST_STATIC_ASSERT((boost::is_same void unordered_set_test(X& r, Key const&) r.emplace(boost::move(k_lvalue)); node_type n1 = r.extract(r.begin()); test::check_return_type::equals_ref(n1.value()); +#endif } template @@ -475,6 +490,9 @@ template void equality_test(X& r) template void unordered_unique_test(X& r, T const& t) { + (void) r; + (void) t; +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::iterator iterator; test::check_return_type >::equals(r.insert(t)); test::check_return_type >::equals(r.emplace(t)); @@ -503,6 +521,7 @@ template void unordered_unique_test(X& r, T const& t) test::check_return_type::equals(insert_return.position); test::check_return_type::equals_ref(insert_return.node); boost::swap(insert_return, insert_return2); +#endif } template void unordered_equivalent_test(X& r, T const& t) @@ -554,6 +573,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) typedef typename X::iterator iterator; typedef typename X::const_iterator const_iterator; +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::local_iterator local_iterator; typedef typename X::const_local_iterator const_local_iterator; @@ -590,6 +610,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) const_local_iterator_pointer; typedef typename std::iterator_traits::reference const_local_iterator_reference; +#endif typedef typename X::allocator_type allocator_type; BOOST_STATIC_ASSERT((boost::is_same::value)); @@ -602,6 +623,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) BOOST_STATIC_ASSERT((boost::is_same::value)); test::check_return_type::convertible(eq(k, k)); +#ifndef BOOST_UNORDERED_FOA_TESTS boost::function_requires >(); BOOST_STATIC_ASSERT( (boost::is_same::value)); @@ -622,6 +644,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) const_iterator_pointer>::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); +#endif X a; allocator_type m = a.get_allocator(); @@ -667,6 +690,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) test::check_return_type >::equals( b.equal_range(k)); test::check_return_type::equals(b.bucket_count()); +#ifndef BOOST_UNORDERED_FOA_TESTS test::check_return_type::equals(b.max_bucket_count()); test::check_return_type::equals(b.bucket(k)); test::check_return_type::equals(b.bucket_size(0)); @@ -680,6 +704,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) test::check_return_type::equals(b.cbegin(0)); test::check_return_type::equals(a.cend(0)); test::check_return_type::equals(b.cend(0)); +#endif test::check_return_type::equals(b.load_factor()); test::check_return_type::equals(b.max_load_factor()); @@ -792,7 +817,11 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) X a10; a10.insert(t); q = a10.cbegin(); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_STATIC_ASSERT(std::is_same::value); +#else test::check_return_type::equals(a10.erase(q)); +#endif // Avoid unused variable warnings: @@ -807,10 +836,12 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) sink(a7a); sink(a9a); +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::node_type node_type; typedef typename X::allocator_type allocator_type; node_type const n_const = a.extract(a.begin()); test::check_return_type::equals(n_const.get_allocator()); +#endif } template @@ -879,7 +910,11 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq) T v5(v); a10.insert(boost::move(v5)); q = a10.cbegin(); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_STATIC_ASSERT(std::is_same::value); +#else test::check_return_type::equals(a10.erase(q)); +#endif // Avoid unused variable warnings: From 57ea45cb8fcff7a76ec20e552b2363e262c528b5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 12 Oct 2022 10:31:52 +0200 Subject: [PATCH 175/279] overloaded for_all_elements --- include/boost/unordered/detail/foa.hpp | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 63d5e827..8d5a258b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1175,20 +1175,10 @@ public: void clear()noexcept { - auto pg=arrays.groups; - auto p=arrays.elements; - if(p){ - for(std::size_t pos=0,last=arrays.groups_size_mask+1; - pos!=last;++pos,++pg,p+=N){ - auto mask=pg->match_really_occupied(); - while(mask){ - auto n=unchecked_countr_zero(mask); - destroy_element(p+n); - pg->reset(n); - mask&=mask-1; - } - } - } + for_all_elements([&,this](group_type* pg,unsigned int n,value_type* p){ + destroy_element(p); + pg->reset(n); + }); size_=0; } @@ -1525,7 +1515,16 @@ private: } template - static void for_all_elements(const arrays_type& arrays_,F f) + static auto for_all_elements(const arrays_type& arrays_,F f) + ->decltype(f(nullptr),void()) + { + for_all_elements( + arrays_,[=](group_type*,unsigned int,value_type* p){return f(p);}); + } + + template + static auto for_all_elements(const arrays_type& arrays_,F f) + ->decltype(f(nullptr,0,nullptr),void()) { auto pg=arrays_.groups; auto p=arrays_.elements; @@ -1534,7 +1533,8 @@ private: pos!=last;++pos,++pg,p+=N){ auto mask=pg->match_really_occupied(); while(mask){ - f(p+unchecked_countr_zero(mask)); + auto n=unchecked_countr_zero(mask); + f(pg,n,p+n); mask&=mask-1; } } From df7792040cffac302a90befca467086e623cbf1c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 12 Oct 2022 11:18:05 +0200 Subject: [PATCH 176/279] implemented merge --- include/boost/unordered/detail/foa.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 8d5a258b..ac142209 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1182,6 +1182,20 @@ public: size_=0; } + // TODO: should we accept different allocator too? + template + void merge(table& x) + { + x.for_all_elements([&,this](group_type* pg,unsigned int n,value_type* p){ + if(emplace_impl(type_policy::move(*p)).second){ + x.erase(iterator{pg,n,p}); + } + }); + } + + template + void merge(table&& x){merge(x);} + hasher hash_function()const{return h();} key_equal key_eq()const{return pred();} @@ -1226,6 +1240,7 @@ public: } private: + template friend class table; using arrays_type=table_arrays; Hash& h(){return hash_base::get();} From 334dcb91acf0af6f79a23b1243cd182b6f40c26e Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 12 Oct 2022 11:20:37 +0200 Subject: [PATCH 177/279] removed unused typedef --- include/boost/unordered/detail/foa.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index ac142209..4bdf9818 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -623,8 +623,6 @@ public: typename std::conditional::type; using reference=value_type&; using iterator_category=std::forward_iterator_tag; - using element_type= - typename std::conditional::type; table_iterator()=default; template::type* =nullptr> From 006f62047b7f18cc15469863d1affcb7aa9b140c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 12 Oct 2022 12:46:47 +0200 Subject: [PATCH 178/279] reverted 334dcb91acf0af6f79a23b1243cd182b6f40c26e --- include/boost/unordered/detail/foa.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 4bdf9818..ac142209 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -623,6 +623,8 @@ public: typename std::conditional::type; using reference=value_type&; using iterator_category=std::forward_iterator_tag; + using element_type= + typename std::conditional::type; table_iterator()=default; template::type* =nullptr> From becd166e66372d741b1d736fc8f260031d00988a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 12 Oct 2022 15:34:05 +0200 Subject: [PATCH 179/279] implemented erase_if --- include/boost/unordered/detail/foa.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index ac142209..dcb6a749 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1239,6 +1239,12 @@ public: rehash(std::size_t(std::ceil(static_cast(n)/mlf))); } + template + friend std::size_t erase_if(table& x,Predicate pr) + { + return x.erase_if_impl(pr); + } + private: template friend class table; using arrays_type=table_arrays; @@ -1523,6 +1529,16 @@ private: } #endif + template + std::size_t erase_if_impl(Predicate pr) + { + std::size_t s=size(); + for_all_elements([&,this](group_type* pg,unsigned int n,value_type* p){ + if(pr(*p)) erase(iterator{pg,n,p}); + }); + return std::size_t(s-size()); + } + template void for_all_elements(F f)const { @@ -1534,7 +1550,7 @@ private: ->decltype(f(nullptr),void()) { for_all_elements( - arrays_,[=](group_type*,unsigned int,value_type* p){return f(p);}); + arrays_,[&](group_type*,unsigned int,value_type* p){return f(p);}); } template From 05b3025c0e599ea33a2578483b29b005cae277bb Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 12 Oct 2022 08:58:32 -0700 Subject: [PATCH 180/279] Fix regression in how the table_iterator defines its reference type --- include/boost/unordered/detail/foa.hpp | 3 ++- test/unordered/compile_set.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index dcb6a749..dfa99753 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -621,7 +621,8 @@ public: using value_type=Value; using pointer= typename std::conditional::type; - using reference=value_type&; + using reference= + typename std::conditional::type; using iterator_category=std::forward_iterator_tag; using element_type= typename std::conditional::type; diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index 32e4a170..dfd40d53 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -64,6 +64,19 @@ INSTANTIATE(multiset) set_type; +#else + typedef boost::unordered_set set_type; +#endif + + typedef set_type::iterator iterator; + + BOOST_STATIC_ASSERT(boost::is_same::reference>::value); +} + UNORDERED_AUTO_TEST (test0) { test::minimal::constructor_param x; From 3f9bd00f014cb2e1cdd6073ebceb0a2c161d3029 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 12 Oct 2022 13:37:12 -0700 Subject: [PATCH 181/279] Add compile_map tests --- .../boost/unordered/unordered_flat_map.hpp | 59 ++++++++++- test/Jamfile.v2 | 1 + test/unordered/compile_map.cpp | 97 +++++++++++++++++++ test/unordered/compile_tests.hpp | 19 ++++ 4 files changed, 173 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 46784ac4..e39c194d 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -35,9 +35,12 @@ namespace boost { using init_type = std::pair; using moved_type = std::pair; using value_type = std::pair; - static Key const& extract(init_type const& kv) { return kv.first; } - static Key const& extract(value_type const& kv) { return kv.first; } - static Key const& extract(moved_type const& kv) { return kv.first; } + + template + static K const& extract(std::pair const& kv) + { + return kv.first; + } static moved_type move(value_type& x) { @@ -57,6 +60,7 @@ namespace boost { using mapped_type = T; using value_type = typename map_types::value_type; using size_type = std::size_t; + using difference_type = std::ptrdiff_t; using hasher = Hash; using key_equal = KeyEqual; using allocator_type = Allocator; @@ -79,6 +83,11 @@ namespace boost { { } + unordered_flat_map(size_type n, hasher const& h, allocator_type const& a) + : unordered_flat_map(n, h, key_equal(), a) + { + } + explicit unordered_flat_map(allocator_type const& a) : unordered_flat_map(0, a) { @@ -93,6 +102,20 @@ namespace boost { this->insert(first, last); } + template + unordered_flat_map( + Iterator first, Iterator last, size_type n, allocator_type const& a) + : unordered_flat_map(first, last, n, hasher(), key_equal(), a) + { + } + + template + unordered_flat_map(Iterator first, Iterator last, size_type n, + hasher const& h, allocator_type const& a) + : unordered_flat_map(first, last, n, h, key_equal(), a) + { + } + unordered_flat_map(unordered_flat_map const& other) : table_(other.table_) { } @@ -124,6 +147,18 @@ namespace boost { { } + unordered_flat_map(std::initializer_list init, size_type n, + allocator_type const& a) + : unordered_flat_map(init, n, hasher(), key_equal(), a) + { + } + + unordered_flat_map(std::initializer_list init, size_type n, + hasher const& h, allocator_type const& a) + : unordered_flat_map(init, n, h, key_equal(), a) + { + } + ~unordered_flat_map() = default; unordered_flat_map& operator=(unordered_flat_map const& other) @@ -165,6 +200,8 @@ namespace boost { size_type size() const noexcept { return table_.size(); } + size_type max_size() const noexcept { return table_.max_size(); } + /// Modifiers /// @@ -302,6 +339,22 @@ namespace boost { table_.swap(rhs.table_); } + template + void merge( + unordered_flat_map& + source) + { + (void)source; + } + + template + void merge( + unordered_flat_map&& + source) + { + (void)source; + } + /// Lookup /// diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index fa9d474c..5c15aa0d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -105,6 +105,7 @@ rule build_foa ( name ) build_foa fwd_set_test ; build_foa fwd_map_test ; build_foa compile_set ; +build_foa compile_map ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 6a84d595..272f7de5 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -8,7 +8,12 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#else #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -17,7 +22,28 @@ #include "./compile_tests.hpp" // Explicit instantiation to catch compile-time errors +#ifdef BOOST_UNORDERED_FOA_TESTS +// emulates what was already done for previous tests but without leaking to +// the detail namespace +// +template +class instantiate_flat_map +{ + typedef boost::unordered_flat_map container; + container x; +}; + +template class instantiate_flat_map, + std::equal_to, test::minimal::allocator >; + +template class instantiate_flat_map, + test::minimal::equal_to, + test::minimal::allocator >; + +#else #define INSTANTIATE(type) \ template class boost::unordered::detail::instantiate_##type @@ -35,6 +61,7 @@ INSTANTIATE(multimap), test::minimal::equal_to, test::minimal::allocator >; +#endif UNORDERED_AUTO_TEST (test0) { test::minimal::constructor_param x; @@ -45,6 +72,19 @@ UNORDERED_AUTO_TEST (test0) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map int_map; + + boost::unordered_flat_map, std::equal_to, + test::minimal::cxx11_allocator > > + int_map2; + + boost::unordered_flat_map, + test::minimal::equal_to, + test::minimal::allocator > + map; +#else boost::unordered_map int_map; boost::unordered_map, std::equal_to, @@ -56,11 +96,13 @@ UNORDERED_AUTO_TEST (test0) { test::minimal::equal_to, test::minimal::allocator > map; +#endif container_test(int_map, std::pair(0, 0)); container_test(int_map2, std::pair(0, 0)); container_test(map, value); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap int_multimap; @@ -78,6 +120,7 @@ UNORDERED_AUTO_TEST (test0) { container_test(int_multimap, std::pair(0, 0)); container_test(int_multimap2, std::pair(0, 0)); container_test(multimap, value); +#endif } UNORDERED_AUTO_TEST (equality_tests) { @@ -85,6 +128,22 @@ UNORDERED_AUTO_TEST (equality_tests) { test::minimal::copy_constructible_equality_comparable> value_type; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map int_map; + + boost::unordered_flat_map, std::equal_to, + test::minimal::cxx11_allocator > > + int_map2; + + boost::unordered_flat_map< + test::minimal::copy_constructible_equality_comparable, + test::minimal::copy_constructible_equality_comparable, + test::minimal::hash, + test::minimal::equal_to< + test::minimal::copy_constructible_equality_comparable>, + test::minimal::allocator > + map; +#else boost::unordered_map int_map; boost::unordered_map, std::equal_to, @@ -98,11 +157,13 @@ UNORDERED_AUTO_TEST (equality_tests) { test::minimal::copy_constructible_equality_comparable>, test::minimal::allocator > map; +#endif equality_test(int_map); equality_test(int_map2); equality_test(map); +#ifndef BOOST_UNORDERED_FOA_TESTS boost::unordered_multimap int_multimap; boost::unordered_multimap, std::equal_to, @@ -121,6 +182,7 @@ UNORDERED_AUTO_TEST (equality_tests) { equality_test(int_multimap); equality_test(int_multimap2); equality_test(multimap); +#endif } UNORDERED_AUTO_TEST (test1) { @@ -131,11 +193,19 @@ UNORDERED_AUTO_TEST (test1) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map map; + + boost::unordered_flat_map, std::equal_to, + test::minimal::cxx11_allocator > > + map2; +#else boost::unordered_map map; boost::unordered_map, std::equal_to, test::minimal::cxx11_allocator > > map2; +#endif unordered_unique_test(map, map_value); unordered_map_test(map, value, value); @@ -147,6 +217,7 @@ UNORDERED_AUTO_TEST (test1) { unordered_copyable_test(map2, value, map_value, hash, equal_to); unordered_map_functions(map2, value, value); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap multimap; @@ -162,6 +233,7 @@ UNORDERED_AUTO_TEST (test1) { unordered_equivalent_test(multimap2, map_value); unordered_map_test(multimap2, value, value); unordered_copyable_test(multimap2, value, map_value, hash, equal_to); +#endif } UNORDERED_AUTO_TEST (test2) { @@ -178,28 +250,46 @@ UNORDERED_AUTO_TEST (test2) { BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map, + test::minimal::equal_to, + test::minimal::allocator > + map; +#else boost::unordered_map, test::minimal::equal_to, test::minimal::allocator > map; +#endif unordered_unique_test(map, map_value); unordered_map_test(map, assignable, assignable); unordered_copyable_test(map, assignable, map_value, hash, equal_to); unordered_map_member_test(map, map_value); +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map, + test::minimal::equal_to, + test::minimal::allocator > + map2; +#else boost::unordered_map, test::minimal::equal_to, test::minimal::allocator > map2; +#endif test::minimal::default_assignable default_assignable; unordered_map_functions(map2, assignable, default_assignable); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap x; + x.emplace(lwg2059_key(10), 5); + x.erase(x.begin()); +#else { boost::unordered_map x; x.emplace(lwg2059_key(10), 5); @@ -243,6 +339,7 @@ UNORDERED_AUTO_TEST (lwg2059) { x.emplace(lwg2059_key(10), 5); x.erase(x.begin()); } +#endif } RUN_TESTS() diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 3975cd07..65509e79 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -360,23 +360,29 @@ void unordered_map_test(X& r, Key const& k, T const& v) typedef typename X::iterator iterator; typedef typename X::const_iterator const_iterator; +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::local_iterator local_iterator; typedef typename X::const_local_iterator const_local_iterator; +#endif typedef typename std::iterator_traits::pointer iterator_pointer; typedef typename std::iterator_traits::pointer const_iterator_pointer; +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename std::iterator_traits::pointer local_iterator_pointer; typedef typename std::iterator_traits::pointer const_local_iterator_pointer; +#endif BOOST_STATIC_ASSERT((boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_STATIC_ASSERT( (boost::is_same::value)); BOOST_STATIC_ASSERT( (boost::is_same::value)); +#endif // pointer_traits @@ -396,6 +402,7 @@ void unordered_map_test(X& r, Key const& k, T const& v) BOOST_STATIC_ASSERT((boost::is_same::difference_type>::value)); +#ifndef BOOST_UNORDERED_FOA_TESTS // pointer_traits BOOST_STATIC_ASSERT((boost::is_same::value)); // Superfluous,but just to make sure. BOOST_STATIC_ASSERT((!boost::is_const::value)); +#endif // Calling functions @@ -442,8 +450,12 @@ void unordered_map_test(X& r, Key const& k, T const& v) r.emplace(k_lvalue, v_lvalue); r.emplace(rvalue(k), rvalue(v)); +#ifdef BOOST_UNORDERED_FOA_TESTS + r.emplace(std::piecewise_construct, std::make_tuple(k), std::make_tuple(v)); +#else r.emplace(boost::unordered::piecewise_construct, boost::make_tuple(k), boost::make_tuple(v)); +#endif // Emplace with hint @@ -451,9 +463,15 @@ void unordered_map_test(X& r, Key const& k, T const& v) r.emplace_hint(r.begin(), k_lvalue, v_lvalue); r.emplace_hint(r.begin(), rvalue(k), rvalue(v)); +#ifdef BOOST_UNORDERED_FOA_TESTS + r.emplace_hint(r.begin(), std::piecewise_construct, std::make_tuple(k), + std::make_tuple(v)); +#else r.emplace_hint(r.begin(), boost::unordered::piecewise_construct, boost::make_tuple(k), boost::make_tuple(v)); +#endif +#ifndef BOOST_UNORDERED_FOA_TESTS // Extract test::check_return_type::equals(r.extract(r.begin())); @@ -476,6 +494,7 @@ void unordered_map_test(X& r, Key const& k, T const& v) node_type n = r.extract(r.begin()); test::check_return_type::equals_ref(n.key()); test::check_return_type::equals_ref(n.mapped()); +#endif } template void equality_test(X& r) From 4399e8b3600a1d597849ac7005209c6918edadc0 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 12 Oct 2022 13:39:23 -0700 Subject: [PATCH 182/279] Add noexcept tests --- test/Jamfile.v2 | 1 + test/unordered/noexcept_tests.cpp | 51 +++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 5c15aa0d..9c875f20 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -106,6 +106,7 @@ build_foa fwd_set_test ; build_foa fwd_map_test ; build_foa compile_set ; build_foa compile_map ; +build_foa noexcept_tests ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index bc1207a1..26a189f6 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -5,8 +5,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -202,6 +208,12 @@ namespace noexcept_tests { UNORDERED_AUTO_TEST (test_noexcept) { if (have_is_nothrow_move) { +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_flat_set >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_flat_map >::value)); +#else BOOST_TEST((boost::is_nothrow_move_constructible< boost::unordered_set >::value)); BOOST_TEST((boost::is_nothrow_move_constructible< @@ -210,19 +222,35 @@ namespace noexcept_tests { boost::unordered_map >::value)); BOOST_TEST((boost::is_nothrow_move_constructible< boost::unordered_multimap >::value)); +#endif } +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST( + (!boost::is_nothrow_move_constructible< + boost::unordered_flat_set >::value)); + BOOST_TEST( + (!boost::is_nothrow_move_constructible, equal_to_possible_exception> >::value)); +#else BOOST_TEST((!boost::is_nothrow_move_constructible< boost::unordered_set >::value)); BOOST_TEST( (!boost::is_nothrow_move_constructible, equal_to_possible_exception> >::value)); +#endif } UNORDERED_AUTO_TEST (test_nothrow_move_when_noexcept) { +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set + throwing_set; +#else typedef boost::unordered_set throwing_set; +#endif if (have_is_nothrow_move) { BOOST_TEST(boost::is_nothrow_move_constructible::value); @@ -310,8 +338,14 @@ namespace noexcept_tests { } UNORDERED_AUTO_TEST (test_nothrow_swap_when_noexcept) { +#if BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set + throwing_set; +#else typedef boost::unordered_set throwing_set; +#endif if (have_is_nothrow_swap) { BOOST_TEST(boost::is_nothrow_swappable::value); @@ -410,6 +444,20 @@ UNORDERED_AUTO_TEST (prelim_allocator_checks) { allocator2 >::type::value); } +using test::default_generator; + +#ifdef BOOST_UNORDERED_FOA_TESTS +boost::unordered_flat_set >* + throwing_set_alloc1; + +boost::unordered_flat_set >* + throwing_set_alloc2; + +UNORDERED_TEST(test_nothrow_move_assign_when_noexcept, + ((throwing_set_alloc1)(throwing_set_alloc2))((default_generator))) +#else boost::unordered_set >* throwing_set_alloc1; @@ -418,9 +466,8 @@ boost::unordered_set >* throwing_set_alloc2; -using test::default_generator; - UNORDERED_TEST(test_nothrow_move_assign_when_noexcept, ((throwing_set_alloc1)(throwing_set_alloc2))((default_generator))) +#endif RUN_TESTS() From 1c14bc1215e39a2a1918892c80adce819f4072e4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 12 Oct 2022 13:39:43 -0700 Subject: [PATCH 183/279] Use explicit cast for when KeyEqual returns a size_t type --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index dfa99753..614654a3 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1381,7 +1381,7 @@ private: prefetch_elements(p); do{ auto n=unchecked_countr_zero(mask); - if(BOOST_LIKELY(pred()(x,key_from(p[n])))){ + if(BOOST_LIKELY(static_cast(pred()(x,key_from(p[n]))))){ return {pg,n,p+n}; } mask&=mask-1; From fc7b5573c12ac79af20edbd8f18bbdcf31547160 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 12 Oct 2022 14:05:25 -0700 Subject: [PATCH 184/279] Add link_test --- test/Jamfile.v2 | 1 + test/unordered/link_test_1.cpp | 20 ++++++++++++++++++++ test/unordered/link_test_2.cpp | 23 +++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9c875f20..3fdc0edb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -107,6 +107,7 @@ build_foa fwd_map_test ; build_foa compile_set ; build_foa compile_map ; build_foa noexcept_tests ; +run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_link_test ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/link_test_1.cpp b/test/unordered/link_test_1.cpp index c32c3ac9..2e9b3631 100644 --- a/test/unordered/link_test_1.cpp +++ b/test/unordered/link_test_1.cpp @@ -5,11 +5,30 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on +#ifdef BOOST_UNORDERED_FOA_TESTS +void foo(boost::unordered_flat_set&, boost::unordered_flat_map&); + +int main() +{ + boost::unordered_flat_set x1; + boost::unordered_flat_map x2; + + foo(x1, x2); + + return 0; +} +#else void foo(boost::unordered_set&, boost::unordered_map&, boost::unordered_multiset&, boost::unordered_multimap&); @@ -24,3 +43,4 @@ int main() return 0; } +#endif diff --git a/test/unordered/link_test_2.cpp b/test/unordered/link_test_2.cpp index 1c3ed766..fb42ba0d 100644 --- a/test/unordered/link_test_2.cpp +++ b/test/unordered/link_test_2.cpp @@ -5,11 +5,33 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on +#ifdef BOOST_UNORDERED_FOA_TESTS +void foo( + boost::unordered_flat_set& x1, boost::unordered_flat_map& x2) +{ +#if BOOST_WORKAROUND(BOOST_CODEGEARC, BOOST_TESTED_AT(0x0613)) + struct dummy + { + boost::unordered_flat_set x1; + boost::unordered_flat_map x2; + }; +#endif + + x1.insert(1); + x2[2] = 2; +} +#else void foo(boost::unordered_set& x1, boost::unordered_map& x2, boost::unordered_multiset& x3, boost::unordered_multimap& x4) { @@ -28,3 +50,4 @@ void foo(boost::unordered_set& x1, boost::unordered_map& x2, x3.insert(3); x4.insert(std::make_pair(4, 5)); } +#endif From d4f7939aaefcb7acc3d90985e394efa0ad5afe42 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 12 Oct 2022 14:30:07 -0700 Subject: [PATCH 185/279] Add incomplete_test --- test/Jamfile.v2 | 1 + test/unordered/incomplete_test.cpp | 47 ++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3fdc0edb..b598a6a9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -108,6 +108,7 @@ build_foa compile_set ; build_foa compile_map ; build_foa noexcept_tests ; run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_link_test ; +build_foa incomplete_test ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 09afcba6..76e8c7f5 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -5,8 +5,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -15,7 +21,11 @@ namespace x { struct D { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map x; +#else boost::unordered_map x; +#endif }; } @@ -29,6 +39,17 @@ namespace incomplete_test { // Declare some instances +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_map > > + map; + typedef boost::unordered_flat_map > > + multimap; + typedef boost::unordered_flat_set > set; + typedef boost::unordered_flat_set > + multiset; +#else typedef boost::unordered_map > > map; @@ -38,6 +59,7 @@ namespace incomplete_test { typedef boost::unordered_set > set; typedef boost::unordered_multiset > multiset; +#endif // Now define the types which are stored as members, as they are needed for // declaring struct members. @@ -76,7 +98,28 @@ namespace incomplete_test { // // Incomplete hash, equals and allocator aren't here supported at the // moment. - +#ifdef BOOST_UNORDERED_FOA_TESTS + struct struct1 + { + boost::unordered_flat_map > > + x; + }; + struct struct2 + { + boost::unordered_flat_map > > + x; + }; + struct struct3 + { + boost::unordered_flat_set > x; + }; + struct struct4 + { + boost::unordered_flat_set > x; + }; +#else struct struct1 { boost::unordered_map > x; }; - +#endif // Now define the value type. struct value From c39ed8a5cf5e0a12554744a75256b9de27500644 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 12 Oct 2022 15:19:11 -0700 Subject: [PATCH 186/279] Add simple_tests --- test/Jamfile.v2 | 1 + test/unordered/simple_tests.cpp | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b598a6a9..99d29ca4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -109,6 +109,7 @@ build_foa compile_map ; build_foa noexcept_tests ; run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_link_test ; build_foa incomplete_test ; +build_foa simple_tests ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index d8a9ce41..7c00fdc8 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -7,8 +7,14 @@ // clang-format off #include "../helpers/prefix.hpp" -#include +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include +#include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -93,7 +99,11 @@ UNORDERED_AUTO_TEST (simple_tests) { srand(14878); BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set set; +#else boost::unordered_set set; +#endif simple_test(set); set.insert(1); @@ -101,6 +111,7 @@ UNORDERED_AUTO_TEST (simple_tests) { set.insert(1456); simple_test(set); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset multiset; simple_test(multiset); @@ -111,15 +122,21 @@ UNORDERED_AUTO_TEST (simple_tests) { multiset.insert(index); } simple_test(multiset); +#endif BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map map; +#else boost::unordered_map map; +#endif for (int i2 = 0; i2 < 1000; ++i2) { map.insert(std::pair(rand(), rand())); } simple_test(map); +#ifndef BOOST_UNORDERED_FOA_TESTS BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap multimap; @@ -129,6 +146,7 @@ UNORDERED_AUTO_TEST (simple_tests) { multimap.insert(std::pair(index, rand())); } simple_test(multimap); +#endif } RUN_TESTS() From 6227ae49a7509bd7d8033824dc67b7a9312ed68b Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 13 Oct 2022 10:23:36 -0700 Subject: [PATCH 187/279] Update find_impl() to ignore warnings about unsigned-signed casting when KeyEqual returns an unsinged integral type --- include/boost/unordered/detail/foa.hpp | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 614654a3..37de4346 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1367,6 +1367,24 @@ private: #endif } +/* GCC and clang (including clang-win toolsets) will generate warnings when the + * KeyEqual predicate returns an integral type such as std::size_t because the + * implementation of __builtin_expect() accepts long as its argument types. + * + * Because we can't control this, it's easiest to simply silence the warning + * instead of introducing any potential performance pitfalls. + */ +#if defined(BOOST_GCC) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#if defined(BOOST_CLANG) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wsign-conversion" +#endif + template BOOST_FORCEINLINE iterator find_impl( const Key& x,std::size_t pos0,std::size_t hash)const @@ -1381,7 +1399,7 @@ private: prefetch_elements(p); do{ auto n=unchecked_countr_zero(mask); - if(BOOST_LIKELY(static_cast(pred()(x,key_from(p[n]))))){ + if(BOOST_LIKELY(pred()(x,key_from(p[n])))){ return {pg,n,p+n}; } mask&=mask-1; @@ -1394,6 +1412,13 @@ private: while(BOOST_LIKELY(pb.next(arrays.groups_size_mask))); return {}; // TODO end() does not work (returns const_iterator) } +#if defined(BOOST_CLANG) +#pragma clang diagnostic pop /* ignored "-Wshorten-64-to-32", "-Wsign-conversion" */ +#endif + +#if defined(BOOST_GCC) +#pragma GCC diagnostic pop /* ignored "-Wsign-conversion" */ +#endif template BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) From 87674d000bc80f19f54ce8c4e11b5325edccd5ee Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 13 Oct 2022 11:39:18 -0700 Subject: [PATCH 188/279] Update map_types to strip const from key, value parameters so that init_type is more efficient and extract() returns a const reference unconditionally --- .gitignore | 4 + .../boost/unordered/unordered_flat_map.hpp | 9 +- test/Jamfile.v2 | 120 +++++++++--------- 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index 2eec3746..2b76deba 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ /doc/html/ +*.sh +*.txt +u64benchmarks +.vscode/ \ No newline at end of file diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index e39c194d..14f3aa53 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -32,12 +32,15 @@ namespace boost { struct map_types { using key_type = Key; - using init_type = std::pair; - using moved_type = std::pair; + using raw_key_type = typename std::remove_const::type; + using raw_value_type = typename std::remove_const::type; + + using init_type = std::pair; + using moved_type = std::pair; using value_type = std::pair; template - static K const& extract(std::pair const& kv) + static raw_key_type const& extract(std::pair const& kv) { return kv.first; } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 99d29ca4..0a01a95b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -32,70 +32,70 @@ project msvc:on ; -run unordered/prime_fmod_tests.cpp ; -run unordered/fwd_set_test.cpp ; -run unordered/fwd_map_test.cpp ; -run unordered/allocator_traits.cpp ; -run unordered/minimal_allocator.cpp ; -run unordered/compile_set.cpp ; -run unordered/compile_map.cpp ; -run unordered/noexcept_tests.cpp ; -run unordered/link_test_1.cpp unordered/link_test_2.cpp ; -run unordered/incomplete_test.cpp ; -run unordered/simple_tests.cpp ; -run unordered/equivalent_keys_tests.cpp ; -run unordered/constructor_tests.cpp ; -run unordered/copy_tests.cpp ; -run unordered/move_tests.cpp ; -run unordered/post_move_tests.cpp ; -run unordered/assign_tests.cpp ; -run unordered/insert_tests.cpp ; -run unordered/insert_stable_tests.cpp ; -run unordered/insert_hint_tests.cpp ; -run unordered/emplace_tests.cpp ; -run unordered/unnecessary_copy_tests.cpp ; -run unordered/erase_tests.cpp : : : BOOST_UNORDERED_SUPPRESS_DEPRECATED ; -run unordered/erase_equiv_tests.cpp ; -run unordered/extract_tests.cpp ; -run unordered/node_handle_tests.cpp ; -run unordered/merge_tests.cpp ; -compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MAP : insert_node_type_fail_map ; -compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ; -compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_SET : insert_node_type_fail_set ; -compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ; -run unordered/find_tests.cpp ; -run unordered/at_tests.cpp ; -run unordered/bucket_tests.cpp ; -run unordered/load_factor_tests.cpp ; -run unordered/rehash_tests.cpp ; -run unordered/equality_tests.cpp ; -run unordered/swap_tests.cpp ; -run unordered/deduction_tests.cpp ; -run unordered/scoped_allocator.cpp : : : msvc-14.0:no ; -run unordered/transparent_tests.cpp ; -run unordered/reserve_tests.cpp ; -run unordered/contains_tests.cpp ; -run unordered/erase_if.cpp ; -run unordered/scary_tests.cpp ; +# run unordered/prime_fmod_tests.cpp ; +# run unordered/fwd_set_test.cpp ; +# run unordered/fwd_map_test.cpp ; +# run unordered/allocator_traits.cpp ; +# run unordered/minimal_allocator.cpp ; +# run unordered/compile_set.cpp ; +# run unordered/compile_map.cpp ; +# run unordered/noexcept_tests.cpp ; +# run unordered/link_test_1.cpp unordered/link_test_2.cpp ; +# run unordered/incomplete_test.cpp ; +# run unordered/simple_tests.cpp ; +# run unordered/equivalent_keys_tests.cpp ; +# run unordered/constructor_tests.cpp ; +# run unordered/copy_tests.cpp ; +# run unordered/move_tests.cpp ; +# run unordered/post_move_tests.cpp ; +# run unordered/assign_tests.cpp ; +# run unordered/insert_tests.cpp ; +# run unordered/insert_stable_tests.cpp ; +# run unordered/insert_hint_tests.cpp ; +# run unordered/emplace_tests.cpp ; +# run unordered/unnecessary_copy_tests.cpp ; +# run unordered/erase_tests.cpp : : : BOOST_UNORDERED_SUPPRESS_DEPRECATED ; +# run unordered/erase_equiv_tests.cpp ; +# run unordered/extract_tests.cpp ; +# run unordered/node_handle_tests.cpp ; +# run unordered/merge_tests.cpp ; +# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MAP : insert_node_type_fail_map ; +# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ; +# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_SET : insert_node_type_fail_set ; +# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ; +# run unordered/find_tests.cpp ; +# run unordered/at_tests.cpp ; +# run unordered/bucket_tests.cpp ; +# run unordered/load_factor_tests.cpp ; +# run unordered/rehash_tests.cpp ; +# run unordered/equality_tests.cpp ; +# run unordered/swap_tests.cpp ; +# run unordered/deduction_tests.cpp ; +# run unordered/scoped_allocator.cpp : : : msvc-14.0:no ; +# run unordered/transparent_tests.cpp ; +# run unordered/reserve_tests.cpp ; +# run unordered/contains_tests.cpp ; +# run unordered/erase_if.cpp ; +# run unordered/scary_tests.cpp ; -run unordered/compile_set.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_set ; -run unordered/compile_map.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_map ; -run unordered/copy_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_copy ; -run unordered/move_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_move ; -run unordered/assign_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_assign ; +# run unordered/compile_set.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_set ; +# run unordered/compile_map.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_map ; +# run unordered/copy_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_copy ; +# run unordered/move_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_move ; +# run unordered/assign_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_assign ; -run exception/constructor_exception_tests.cpp ; -run exception/copy_exception_tests.cpp ; -run exception/assign_exception_tests.cpp ; -run exception/move_assign_exception_tests.cpp ; -run exception/insert_exception_tests.cpp ; -run exception/erase_exception_tests.cpp ; -run exception/rehash_exception_tests.cpp ; -run exception/swap_exception_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ; -run exception/merge_exception_tests.cpp ; +# run exception/constructor_exception_tests.cpp ; +# run exception/copy_exception_tests.cpp ; +# run exception/assign_exception_tests.cpp ; +# run exception/move_assign_exception_tests.cpp ; +# run exception/insert_exception_tests.cpp ; +# run exception/erase_exception_tests.cpp ; +# run exception/rehash_exception_tests.cpp ; +# run exception/swap_exception_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ; +# run exception/merge_exception_tests.cpp ; -run quick.cpp ; +# run quick.cpp ; rule build_foa ( name ) { From 7339f4264ac6ad3cbd6f12b5b09ff9bf05bc1627 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 13 Oct 2022 11:58:20 -0700 Subject: [PATCH 189/279] Undo bad commits to Jamfile, gitignore --- .gitignore | 4 -- test/Jamfile.v2 | 120 ++++++++++++++++++++++++------------------------ 2 files changed, 60 insertions(+), 64 deletions(-) diff --git a/.gitignore b/.gitignore index 2b76deba..2eec3746 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1 @@ /doc/html/ -*.sh -*.txt -u64benchmarks -.vscode/ \ No newline at end of file diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0a01a95b..99d29ca4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -32,70 +32,70 @@ project msvc:on ; -# run unordered/prime_fmod_tests.cpp ; -# run unordered/fwd_set_test.cpp ; -# run unordered/fwd_map_test.cpp ; -# run unordered/allocator_traits.cpp ; -# run unordered/minimal_allocator.cpp ; -# run unordered/compile_set.cpp ; -# run unordered/compile_map.cpp ; -# run unordered/noexcept_tests.cpp ; -# run unordered/link_test_1.cpp unordered/link_test_2.cpp ; -# run unordered/incomplete_test.cpp ; -# run unordered/simple_tests.cpp ; -# run unordered/equivalent_keys_tests.cpp ; -# run unordered/constructor_tests.cpp ; -# run unordered/copy_tests.cpp ; -# run unordered/move_tests.cpp ; -# run unordered/post_move_tests.cpp ; -# run unordered/assign_tests.cpp ; -# run unordered/insert_tests.cpp ; -# run unordered/insert_stable_tests.cpp ; -# run unordered/insert_hint_tests.cpp ; -# run unordered/emplace_tests.cpp ; -# run unordered/unnecessary_copy_tests.cpp ; -# run unordered/erase_tests.cpp : : : BOOST_UNORDERED_SUPPRESS_DEPRECATED ; -# run unordered/erase_equiv_tests.cpp ; -# run unordered/extract_tests.cpp ; -# run unordered/node_handle_tests.cpp ; -# run unordered/merge_tests.cpp ; -# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MAP : insert_node_type_fail_map ; -# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ; -# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_SET : insert_node_type_fail_set ; -# compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ; -# run unordered/find_tests.cpp ; -# run unordered/at_tests.cpp ; -# run unordered/bucket_tests.cpp ; -# run unordered/load_factor_tests.cpp ; -# run unordered/rehash_tests.cpp ; -# run unordered/equality_tests.cpp ; -# run unordered/swap_tests.cpp ; -# run unordered/deduction_tests.cpp ; -# run unordered/scoped_allocator.cpp : : : msvc-14.0:no ; -# run unordered/transparent_tests.cpp ; -# run unordered/reserve_tests.cpp ; -# run unordered/contains_tests.cpp ; -# run unordered/erase_if.cpp ; -# run unordered/scary_tests.cpp ; +run unordered/prime_fmod_tests.cpp ; +run unordered/fwd_set_test.cpp ; +run unordered/fwd_map_test.cpp ; +run unordered/allocator_traits.cpp ; +run unordered/minimal_allocator.cpp ; +run unordered/compile_set.cpp ; +run unordered/compile_map.cpp ; +run unordered/noexcept_tests.cpp ; +run unordered/link_test_1.cpp unordered/link_test_2.cpp ; +run unordered/incomplete_test.cpp ; +run unordered/simple_tests.cpp ; +run unordered/equivalent_keys_tests.cpp ; +run unordered/constructor_tests.cpp ; +run unordered/copy_tests.cpp ; +run unordered/move_tests.cpp ; +run unordered/post_move_tests.cpp ; +run unordered/assign_tests.cpp ; +run unordered/insert_tests.cpp ; +run unordered/insert_stable_tests.cpp ; +run unordered/insert_hint_tests.cpp ; +run unordered/emplace_tests.cpp ; +run unordered/unnecessary_copy_tests.cpp ; +run unordered/erase_tests.cpp : : : BOOST_UNORDERED_SUPPRESS_DEPRECATED ; +run unordered/erase_equiv_tests.cpp ; +run unordered/extract_tests.cpp ; +run unordered/node_handle_tests.cpp ; +run unordered/merge_tests.cpp ; +compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MAP : insert_node_type_fail_map ; +compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ; +compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_SET : insert_node_type_fail_set ; +compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ; +run unordered/find_tests.cpp ; +run unordered/at_tests.cpp ; +run unordered/bucket_tests.cpp ; +run unordered/load_factor_tests.cpp ; +run unordered/rehash_tests.cpp ; +run unordered/equality_tests.cpp ; +run unordered/swap_tests.cpp ; +run unordered/deduction_tests.cpp ; +run unordered/scoped_allocator.cpp : : : msvc-14.0:no ; +run unordered/transparent_tests.cpp ; +run unordered/reserve_tests.cpp ; +run unordered/contains_tests.cpp ; +run unordered/erase_if.cpp ; +run unordered/scary_tests.cpp ; -# run unordered/compile_set.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_set ; -# run unordered/compile_map.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_map ; -# run unordered/copy_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_copy ; -# run unordered/move_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_move ; -# run unordered/assign_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_assign ; +run unordered/compile_set.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_set ; +run unordered/compile_map.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_compile_map ; +run unordered/copy_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_copy ; +run unordered/move_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_move ; +run unordered/assign_tests.cpp : : : BOOST_UNORDERED_USE_MOVE : bmove_assign ; -# run exception/constructor_exception_tests.cpp ; -# run exception/copy_exception_tests.cpp ; -# run exception/assign_exception_tests.cpp ; -# run exception/move_assign_exception_tests.cpp ; -# run exception/insert_exception_tests.cpp ; -# run exception/erase_exception_tests.cpp ; -# run exception/rehash_exception_tests.cpp ; -# run exception/swap_exception_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ; -# run exception/merge_exception_tests.cpp ; +run exception/constructor_exception_tests.cpp ; +run exception/copy_exception_tests.cpp ; +run exception/assign_exception_tests.cpp ; +run exception/move_assign_exception_tests.cpp ; +run exception/insert_exception_tests.cpp ; +run exception/erase_exception_tests.cpp ; +run exception/rehash_exception_tests.cpp ; +run exception/swap_exception_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ; +run exception/merge_exception_tests.cpp ; -# run quick.cpp ; +run quick.cpp ; rule build_foa ( name ) { From d538f6184c3d48d2d0c79448ff5368f8f2b50e45 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 13 Oct 2022 11:59:44 -0700 Subject: [PATCH 190/279] Add equivalent_keys_tests --- test/Jamfile.v2 | 1 + test/unordered/equivalent_keys_tests.cpp | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 99d29ca4..041dbdac 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -110,6 +110,7 @@ build_foa noexcept_tests ; run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_link_test ; build_foa incomplete_test ; build_foa simple_tests ; +build_foa equivalent_keys_tests ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index f040819d..fe365b66 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -5,8 +5,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -38,8 +44,11 @@ void test_equal_insertion(Iterator begin, Iterator end) UNORDERED_AUTO_TEST (set_tests) { int values[][5] = {{1}, {54, 23}, {-13, 65}, {77, 77}, {986, 25, 986}}; +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set set; +#else typedef boost::unordered_set set; - typedef boost::unordered_multiset multiset; +#endif test_equal_insertion(values[0], values[0] + 1); test_equal_insertion(values[1], values[1] + 2); @@ -47,6 +56,7 @@ UNORDERED_AUTO_TEST (set_tests) { test_equal_insertion(values[3], values[3] + 2); test_equal_insertion(values[4], values[4] + 3); + typedef boost::unordered_multiset multiset; test_equal_insertion(values[0], values[0] + 1); test_equal_insertion(values[1], values[1] + 2); test_equal_insertion(values[2], values[2] + 2); @@ -66,12 +76,17 @@ UNORDERED_AUTO_TEST (map_tests) { v[2].push_back(std::pair(432, 24)); for (int i = 0; i < 5; ++i) +#ifdef BOOST_UNORDERED_FOA_TESTS + test_equal_insertion >( + v[i].begin(), v[i].end()); +#else test_equal_insertion >( v[i].begin(), v[i].end()); for (int i2 = 0; i2 < 5; ++i2) test_equal_insertion >( v[i2].begin(), v[i2].end()); +#endif } RUN_TESTS() From 8c58ffe546e6823b75e2b6e3cd995628e2d4c7a8 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 14 Oct 2022 10:16:47 +0200 Subject: [PATCH 191/279] made sure BOOST_[UN]LIKELY is passed a boolean everywhere --- include/boost/unordered/detail/foa.hpp | 31 +++----------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 37de4346..79e5b079 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1367,24 +1367,6 @@ private: #endif } -/* GCC and clang (including clang-win toolsets) will generate warnings when the - * KeyEqual predicate returns an integral type such as std::size_t because the - * implementation of __builtin_expect() accepts long as its argument types. - * - * Because we can't control this, it's easiest to simply silence the warning - * instead of introducing any potential performance pitfalls. - */ -#if defined(BOOST_GCC) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - -#if defined(BOOST_CLANG) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wshorten-64-to-32" -#pragma clang diagnostic ignored "-Wsign-conversion" -#endif - template BOOST_FORCEINLINE iterator find_impl( const Key& x,std::size_t pos0,std::size_t hash)const @@ -1399,7 +1381,7 @@ private: prefetch_elements(p); do{ auto n=unchecked_countr_zero(mask); - if(BOOST_LIKELY(pred()(x,key_from(p[n])))){ + if(BOOST_LIKELY(bool(pred()(x,key_from(p[n]))))){ return {pg,n,p+n}; } mask&=mask-1; @@ -1412,13 +1394,6 @@ private: while(BOOST_LIKELY(pb.next(arrays.groups_size_mask))); return {}; // TODO end() does not work (returns const_iterator) } -#if defined(BOOST_CLANG) -#pragma clang diagnostic pop /* ignored "-Wshorten-64-to-32", "-Wsign-conversion" */ -#endif - -#if defined(BOOST_GCC) -#pragma GCC diagnostic pop /* ignored "-Wsign-conversion" */ -#endif template BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) @@ -1527,7 +1502,7 @@ private: auto pos=pb.get(); auto pg=arrays_.groups+pos; auto mask=pg->match_available(); - if(BOOST_LIKELY(mask)){ + if(BOOST_LIKELY(mask!=0)){ return {pos,unchecked_countr_zero(mask)}; } else pg->mark_overflow(hash); @@ -1543,7 +1518,7 @@ private: auto pos=pb.get(); auto pg=arrays_.groups+pos; auto mask=pg->match_available(); - if(BOOST_LIKELY(mask)){ + if(BOOST_LIKELY(mask!=0)){ auto n=unchecked_countr_zero(mask); auto p=arrays_.elements+pos*N+n; construct_element(p,std::forward(args)...); From f85e04ef318715fbd08b0e1464e64a24368285a3 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 14 Oct 2022 10:30:53 +0200 Subject: [PATCH 192/279] stylistic --- include/boost/unordered/unordered_flat_map.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 14f3aa53..b67fa9d4 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -33,10 +33,10 @@ namespace boost { { using key_type = Key; using raw_key_type = typename std::remove_const::type; - using raw_value_type = typename std::remove_const::type; + using raw_mapped_type = typename std::remove_const::type; - using init_type = std::pair; - using moved_type = std::pair; + using init_type = std::pair; + using moved_type = std::pair; using value_type = std::pair; template From aefb5dd66a95cd8f21556249690c153e34547c84 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 14 Oct 2022 10:40:07 +0200 Subject: [PATCH 193/279] fixed unordered_flat_map::map_types::move --- include/boost/unordered/unordered_flat_map.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index b67fa9d4..74dad701 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -48,7 +48,10 @@ namespace boost { static moved_type move(value_type& x) { // TODO: we probably need to launder here - return {std::move(const_cast(x.first)), std::move(x.second)}; + return { + std::move(const_cast(x.first)), + std::move(const_cast(x.second)) + }; } }; From df32d79e8a8dd1e1827e4f1f681f4ce43a9ae8d0 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 14 Oct 2022 13:30:49 +0200 Subject: [PATCH 194/279] shut down VS warning --- include/boost/unordered/detail/foa.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 79e5b079..f81517de 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1367,6 +1367,12 @@ private: #endif } +#if defined(BOOST_MSVC) +/* warning: forcing value to bool 'true' or 'false' in bool(pred()...) */ +#pragma warning(push) +#pragma warning(disable:4800) +#endif + template BOOST_FORCEINLINE iterator find_impl( const Key& x,std::size_t pos0,std::size_t hash)const @@ -1395,6 +1401,10 @@ private: return {}; // TODO end() does not work (returns const_iterator) } +#if defined(BOOST_MSVC) +#pragma warning(pop) /* C4800 */ +#endif + template BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { From fc5c8c3669ec207f7484b0bd3b2bf0aba7fe9324 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 14 Oct 2022 13:40:56 +0200 Subject: [PATCH 195/279] removed unused typedef --- include/boost/unordered/detail/foa.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f81517de..5c448cf9 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -877,8 +877,6 @@ public: private: static constexpr bool has_mutable_iterator= !std::is_same::value; - static constexpr bool has_different_init_type= - !std::is_same::value; public: using hasher=Hash; From 3683b43242c6f8a15baa58fe23c72d2b33b77bea Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 14 Oct 2022 13:52:37 +0200 Subject: [PATCH 196/279] [skip CI] editorial --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 5c448cf9..b73a64a2 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -704,7 +704,7 @@ struct table_arrays { using alloc_traits=boost::allocator_traits; - /* n/N+1 == ceil(n+1/N) (extra +1 for the sentinel) */ + /* n/N+1 == ceil((n+1)/N) (extra +1 for the sentinel) */ auto groups_size_index=size_policy::size_index(n/N+1); auto groups_size=size_policy::size(groups_size_index); table_arrays arrays{groups_size_index,groups_size-1,nullptr,nullptr}; From 9a03d1e904b0bafc5b3296634f4ecc8e1b2f9bf7 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 14 Oct 2022 20:00:24 +0200 Subject: [PATCH 197/279] added design and implementation notes --- include/boost/unordered/detail/foa.hpp | 133 ++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 5 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index b73a64a2..c03dae25 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -72,7 +72,59 @@ namespace unordered{ namespace detail{ namespace foa{ -/* TODO: description */ +/* foa::table is an open-addressing hash table serving as the foundational core + * of boost::unordered_flat_[map|set]. Its main design aspects are: + * + * - Element slots are logically split into groups of size N=15. The number + * of groups is always a power of two, so the number of allocated slots + is of the form (N*2^n)-1 (final slot reserved for a sentinel mark). + * - Positioning is done at the group level rather than the slot level, that + * is, for any given element its hash value is used to locate a group and + * insertion is performed on the first available element of that group; + * if the group is full (overflow), further groups are tried using + * quadratic probing. + * - Each group has an associated 16B metadata word holding reduced hash + * values and overflow information. Reduced hash values are used to + * accelerate lookup within the group by using SIMD or 64-bit word + * operations. + */ + +/* group15 controls metadata information of a group of N=15 element slots. + * The 16B metadata word is organized as follows (LSB depicted rightmost): + * + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * |ofw|h14|h13|h13|h11|h10|h09|h08|h07|h06|h05|h04|h03|h02|h01|h00| + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * + * hi is 0 if the i-th element slot is avalaible, 1 to mark a sentinel and, + * when the slot is occupied, a value in the range [2,255] obtained from the + * element's original hash value. + * ofw is the so-called overflow byte. If insertion of an element with hash + * value h is tried on a full group, then the (h%8)-th bit of the overflow + * byte is set to 1 and a further group is probed. Having an overflow byte + * brings two advantages: + * + * - There's no need to reserve a special value of hi to mark tombstone + * slots; each reduced hash value keeps then log2(254)=7.99 bits of the + * original hash (alternative approaches reserve one full bit to mark + * if the slot is available/deleted, so their reduced hash values are 7 bit + * strong only). + * - When doing an unsuccessful lookup (i.e. the element is not present in + * the table), probing stops at the first non-overflowed group. Having 8 + * bits for signalling overflow makes it very likely that we stop at the + * current group (this happens when no element with the same (h%8) value + * has overflowed in the same group), saving us an additional group check + * even under high-load/high-erase conditions. + * + * When looking for an element with hash value h, match(n) returns a bitmask + * signalling which slots have the same reduced hash value. If available, + * match uses SSE2 or (little endian) Neon 128-bit SIMD operations. On non-SIMD + * scenarios, the logical layout described above is physically mapped to two + * 64-bit words with *bit interleaving*, i.e. the least significant 16 bits of + * the first 64-bit word contain the least significant bits of each byte in the + * "logical" 128-bit word, and so forth. With this layout, match can be + * implemented with 5 ANDs, 3 shifts, 2 XORs and 2 NOTs. + */ #if defined(BOOST_UNORDERED_SSE2) @@ -549,6 +601,30 @@ inline void prefetch(const void* p) #endif } +/* foa::table uses a size policy to control the permissible sizes of the group + * array (and, by implication, the element array) and the hash->group mapping. + * + * - size_index(n) returns an unspecified "index" number used in other policy + * operations. + * - size(size_index_) returns the number of groups for the given index. It is + * guaranteed that size(size_index(n)) >= n. + * - min_size() is the minimum number of groups permissible, i.e. + * size(size_index(0)). + * - position(hash,size_index_) maps hash to a position in the range + * [0,size(size_index_)). + * + * The reason we're introducing the intermediate index value for calculating + * sizes and positions is that it allows us to optimize the implementation of + * position, which is in the hot path of lookup and insertion operations. + * pow2_size_policy, the actual size policy used by foa::table, returns 2^n + * (n>0) as permissible sizes and returns the n most significant bits + * of the hash value as the position in the group array. Using a size index + * defined as i = (bits in std::size_t) - n, we have an unbeatable + * implementation of position(hash) as hash>>i. We've chosen to select the + * most significant bits of hash for positioning as multiplication-based mixing + * tends to yield better entropy in the high part of its result. + */ + struct pow2_size_policy { static inline std::size_t size_index(std::size_t n) @@ -560,25 +636,35 @@ struct pow2_size_policy (n<=2?1:((std::size_t)(boost::core::bit_width(n-1)))); } - static inline std::size_t size(std::size_t size_index) + static inline std::size_t size(std::size_t size_index_) { - return std::size_t(1)<<(sizeof(std::size_t)*CHAR_BIT-size_index); + return std::size_t(1)<<(sizeof(std::size_t)*CHAR_BIT-size_index_); } static constexpr std::size_t min_size(){return 2;} - static inline std::size_t position(std::size_t hash,std::size_t size_index) + static inline std::size_t position(std::size_t hash,std::size_t size_index_) { - return hash>>size_index; + return hash>>size_index_; } }; +/* Quadratic prober over a power-of-two range using triangular numbers. + * mask in next(mask) is expected to be the range size minus one (and since + * size is 2^n, mask has exactly its n first bits set to 1). + */ + struct pow2_quadratic_prober { pow2_quadratic_prober(std::size_t pos_):pos{pos_}{} inline std::size_t get()const{return pos;} + /* next returns false when the whole array has been traversed, which ends + * probing (in practice, full-table probing will only happen with very small + * arrays). + */ + inline bool next(std::size_t mask) { step+=1; @@ -590,6 +676,12 @@ private: std::size_t pos,step=0; }; +/* Mixing policies: no_mix is the identity function and xmx_mix uses the + * xmx function defined in . + * foa::table mixes hash results with xmx_mix unless the hash is marked as + * avalanching, i.e. of good quality (see ). + */ + struct no_mix { template @@ -611,6 +703,28 @@ struct xmx_mix template class table; +/* table_iterators keeps two pointers: + * + * - A pointer p to the element slot. + * - A pointer pc to the n-th byte of the associated group metadata, where n + * is the position of the element in the group. + * + * A simpler solution would have been to keep a pointer p to the element, a + * pointer pg to the group, and the position n, but that would increase + * sizeof(table_iterator) by 4/8 bytes. In order to make this compact + * representation possible, it is required that group objects are aligned + * to its size, so that we can recover pg and n as + * + * - n = pc%sizeof(group) + * - pg = pc-n + * + * (for explanatory purposes pg and pc are treated above as if they were memory + * addresses rather than pointers).The main drawback of this two-pointer + * representation is that iterator increment is relatively slow. + * + * p = nullptr is conventionally used to mark end() iterators. + */ + class const_iterator_cast_tag {}; template @@ -691,6 +805,15 @@ private: Value *p=nullptr; }; +/* table_arrays controls allocation, initialization and deallocation of + * paired arrays of groups and element slots. Only one chunk of memory is + * allocated to place both arrays: this is not done for efficiency reasons, + * but in order to be able to properly align the group array without storing + * additional offset information --the alignment required (16B) is usually + * greater than alignof(std::max_align_t) and thus not guaranteed by + * allocators. + */ + template struct table_arrays { From d02d4094e69f6864a125cc828c96e29e27eb4420 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 13 Oct 2022 13:16:36 -0700 Subject: [PATCH 198/279] Add merge_tests --- .../boost/unordered/unordered_flat_map.hpp | 4 +- .../boost/unordered/unordered_flat_set.hpp | 4 +- test/Jamfile.v2 | 1 + test/unordered/merge_tests.cpp | 96 ++++++++++++++++++- 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 74dad701..f415b038 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -350,7 +350,7 @@ namespace boost { unordered_flat_map& source) { - (void)source; + table_.merge(source.table_); } template @@ -358,7 +358,7 @@ namespace boost { unordered_flat_map&& source) { - (void)source; + table_.merge(std::move(source.table_)); } /// Lookup diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 9a740448..7c0fe941 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -266,13 +266,13 @@ namespace boost { template void merge(unordered_flat_set& source) { - (void) source; + table_.merge(source.table_); } template void merge(unordered_flat_set&& source) { - (void) source; + table_.merge(std::move(source.table_)); } /// Lookup diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 041dbdac..783d3497 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -119,6 +119,7 @@ build_foa insert_tests ; build_foa insert_hint_tests ; build_foa emplace_tests ; build_foa erase_tests ; +build_foa merge_tests ; build_foa find_tests ; build_foa at_tests ; build_foa load_factor_tests ; diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 897abb34..1d169373 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -4,9 +4,15 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "../helpers/postfix.hpp" -#include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif +#include "../helpers/prefix.hpp" #include "../helpers/count.hpp" #include "../helpers/helpers.hpp" @@ -19,8 +25,13 @@ namespace merge_tests { UNORDERED_AUTO_TEST (merge_set) { +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set x; + boost::unordered_flat_set y; +#else boost::unordered_set x; boost::unordered_set y; +#endif x.merge(y); BOOST_TEST(x.empty()); @@ -57,6 +68,7 @@ namespace merge_tests { test::check_equivalent_keys(y); } +#ifndef BOOST_UNORDERED_FOA_TESTS UNORDERED_AUTO_TEST (merge_multiset) { boost::unordered_multiset x; boost::unordered_multiset y; @@ -134,6 +146,7 @@ namespace merge_tests { test::check_equivalent_keys(x); test::check_equivalent_keys(y); } +#endif template void merge_empty_test(X1*, X2*, test::random_generator generator) @@ -228,6 +241,82 @@ namespace merge_tests { test::check_equivalent_keys(x2); } + using test::default_generator; + using test::generate_collisions; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_set >* test_set_std_alloc; + + + boost::unordered_flat_map >* test_map_std_alloc; + + + boost::unordered_flat_set >* test_set; + + + boost::unordered_flat_map >* test_map; + + // clang-format off +UNORDERED_TEST(merge_empty_test, + ((test_set_std_alloc)) + ((test_set_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_map_std_alloc)) + ((test_map_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_set)) + ((test_set)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_map)) + ((test_map)) + ((default_generator)(generate_collisions))) + +UNORDERED_TEST(merge_into_empty_test, + ((test_set_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_map_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_set)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_map)) + ((default_generator)(generate_collisions))) + +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_set_std_alloc)) + ((test_set_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_map_std_alloc)) + ((test_map_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_set)) + ((test_set)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_map)) + ((test_map)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) + // clang-format on +#else boost::unordered_set >* test_set_std_alloc; boost::unordered_multiset >* test_multimap; - using test::default_generator; - using test::generate_collisions; - // clang-format off UNORDERED_TEST(merge_empty_test, ((test_set_std_alloc)(test_multiset_std_alloc)) @@ -332,6 +418,8 @@ UNORDERED_TEST(merge_into_equiv_keys_test, ((0)(1)(2)) ((default_generator)(generate_collisions))) // clang-format on +#endif + } RUN_TESTS() From 5e24f6ef224425fe255a126820493cdf95504ccc Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 13 Oct 2022 15:42:06 -0700 Subject: [PATCH 199/279] Add reserve_tests --- test/Jamfile.v2 | 1 + test/unordered/reserve_tests.cpp | 40 ++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 783d3497..06a69bf8 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -127,4 +127,5 @@ build_foa rehash_tests ; build_foa equality_tests ; build_foa swap_tests ; build_foa transparent_tests ; +build_foa reserve_tests ; build_foa contains_tests ; diff --git a/test/unordered/reserve_tests.cpp b/test/unordered/reserve_tests.cpp index f0d83b91..a67bd39f 100644 --- a/test/unordered/reserve_tests.cpp +++ b/test/unordered/reserve_tests.cpp @@ -4,8 +4,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -113,8 +119,8 @@ template void reserve_tests() s.max_load_factor(0.37f); s.reserve(count); - std::size_t expected_bucket_count = - static_cast(std::ceil(static_cast(count) / 0.37f)); + std::size_t expected_bucket_count = static_cast( + std::ceil(static_cast(count) / s.max_load_factor())); BOOST_TEST_GE(total_allocation, expected_bucket_count * sizeof(void*)); BOOST_TEST_GE(s.bucket_count(), expected_bucket_count); @@ -173,6 +179,12 @@ template void rehash_tests() // note, the test is vulnerable to cases where the next calculated bucket // count can exceed `prev_count + count` // +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST_LT(s.bucket_count(), prev_count + count); + BOOST_TEST_LE(total_allocation, + (prev_count + count) * sizeof(typename UnorderedContainer::value_type) + + ((prev_count + count) / 15 + 1) * 16); +#else std::size_t const estimated_bucket_group_size = 3 * sizeof(void*) + sizeof(std::size_t); std::size_t const estimated_bucket_groups = @@ -182,6 +194,7 @@ template void rehash_tests() BOOST_TEST_LE(total_allocation, (prev_count + count) * sizeof(void*) + estimated_bucket_group_size * estimated_bucket_groups); +#endif } BOOST_TEST_GT(num_allocations, 0u); @@ -214,6 +227,28 @@ UNORDERED_AUTO_TEST (unordered_set_reserve) { BOOST_ASSERT(A(b) == a); } +#ifdef BOOST_UNORDERED_FOA_TESTS + typedef boost::unordered_flat_set, + std::equal_to, A > + unordered_set; + + typedef boost::unordered_flat_map, + std::equal_to, A > > + unordered_map; + + bucket_count_constructor(); + bucket_count_constructor(); + + range_bucket_constructor(); + range_bucket_constructor(); + + reserve_tests(); + reserve_tests(); + + rehash_tests(); + rehash_tests(); + +#else typedef boost::unordered_set, std::equal_to, A > unordered_set; @@ -249,6 +284,7 @@ UNORDERED_AUTO_TEST (unordered_set_reserve) { rehash_tests(); rehash_tests(); rehash_tests(); +#endif } RUN_TESTS() From 454cb24cc82a848b1159d67b5d60a64c972c4d2f Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 14 Oct 2022 10:50:49 -0700 Subject: [PATCH 200/279] Ease test requiremets for erase_if, require copyability now of supplied predicate --- test/unordered/erase_if.cpp | 55 +++---------------------------------- 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/test/unordered/erase_if.cpp b/test/unordered/erase_if.cpp index fcea06fa..cad9bce7 100644 --- a/test/unordered/erase_if.cpp +++ b/test/unordered/erase_if.cpp @@ -23,36 +23,13 @@ namespace test { struct is_even { - is_even() {} - -#if BOOST_CXX_VERSION >= 201703L - // immovable for C++17 - is_even(is_even const&) = delete; - is_even(is_even&&) = delete; - - is_even& operator=(is_even const&) = delete; - is_even& operator=(is_even&&) = delete; -#elif BOOST_CXX_VERSION >= 201103L - // move-only for C++11 - is_even(is_even const&) = delete; - is_even(is_even&&) = default; - - is_even& operator=(is_even const&) = delete; - is_even& operator=(is_even&&) = default; -#else - // copyable otherwise - is_even(is_even const&) {} - is_even& operator=(is_even const&) { return *this; } -#endif - - bool operator()( - std::pair& key_value) UNORDERED_LVALUE_QUAL + bool operator()(std::pair& key_value) { int const v = key_value.second; return (v % 2 == 0); } - bool operator()(int const& value) UNORDERED_LVALUE_QUAL + bool operator()(int const& value) { int const v = value; return (v % 2 == 0); @@ -61,37 +38,13 @@ namespace test { struct is_too_large { - is_too_large() {} - -#if BOOST_CXX_VERSION >= 201703L - // immovable for C++17 - is_too_large(is_too_large const&) = delete; - is_too_large(is_too_large&&) = delete; - - is_too_large& operator=(is_too_large const&) = delete; - is_too_large& operator=(is_too_large&&) = delete; -#elif BOOST_CXX_VERSION >= 201103L - // move-only for C++11 - is_too_large(is_too_large const&) = delete; - is_too_large(is_too_large&&) = default; - - is_too_large& operator=(is_too_large const&) = delete; - is_too_large& operator=(is_too_large&&) = default; -#else - // copyable otherwise - is_too_large(is_too_large const&) {} - - is_too_large& operator=(is_too_large const&) { return *this; } -#endif - - bool operator()( - std::pair& key_value) UNORDERED_LVALUE_QUAL + bool operator()(std::pair& key_value) { int const v = key_value.second; return v >= 1000; } - bool operator()(int const& value) UNORDERED_LVALUE_QUAL + bool operator()(int const& value) { int const v = value; return v >= 1000; From e3c91ad812224081a46eb132081840b18c56d84e Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 14 Oct 2022 10:51:54 -0700 Subject: [PATCH 201/279] Add erase_if tests --- .../boost/unordered/unordered_flat_map.hpp | 19 +++++++++++++++---- .../boost/unordered/unordered_flat_set.hpp | 12 ++++++++++++ test/Jamfile.v2 | 1 + test/unordered/erase_if.cpp | 11 +++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index f415b038..ea90c7e6 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -48,10 +48,8 @@ namespace boost { static moved_type move(value_type& x) { // TODO: we probably need to launder here - return { - std::move(const_cast(x.first)), - std::move(const_cast(x.second)) - }; + return {std::move(const_cast(x.first)), + std::move(const_cast(x.second))}; } }; @@ -61,6 +59,10 @@ namespace boost { table_type table_; + template + typename unordered_flat_map::size_type friend erase_if( + unordered_flat_map& set, Pred pred); + public: using key_type = Key; using mapped_type = T; @@ -572,6 +574,15 @@ namespace boost { { lhs.swap(rhs); } + + template + typename unordered_flat_map::size_type + erase_if( + unordered_flat_map& map, Pred pred) + { + return erase_if(map.table_, pred); + } } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 7c0fe941..fde8605c 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -42,6 +42,10 @@ namespace boost { table_type table_; + template + typename unordered_flat_set::size_type friend erase_if( + unordered_flat_set& set, Pred pred); + public: using key_type = Key; using value_type = typename set_types::value_type; @@ -453,6 +457,14 @@ namespace boost { { lhs.swap(rhs); } + + template + typename unordered_flat_set::size_type + erase_if(unordered_flat_set& set, Pred pred) + { + return erase_if(set.table_, pred); + } } // namespace unordered } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 06a69bf8..c33da46c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -129,3 +129,4 @@ build_foa swap_tests ; build_foa transparent_tests ; build_foa reserve_tests ; build_foa contains_tests ; +build_foa erase_if ; diff --git a/test/unordered/erase_if.cpp b/test/unordered/erase_if.cpp index cad9bce7..cc4bcd5c 100644 --- a/test/unordered/erase_if.cpp +++ b/test/unordered/erase_if.cpp @@ -4,8 +4,14 @@ // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -112,11 +118,16 @@ template void test_set_erase_if() } UNORDERED_AUTO_TEST (unordered_erase_if) { +#ifdef BOOST_UNORDERED_FOA_TESTS + test_map_erase_if >(); + test_set_erase_if >(); +#else test_map_erase_if >(); test_map_erase_if >(); test_set_erase_if >(); test_set_erase_if >(); +#endif } RUN_TESTS() From 14c190223caec5028a0920e7c2600d33f6f49ab4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 14 Oct 2022 11:02:05 -0700 Subject: [PATCH 202/279] Add scoped_allocator tests --- test/Jamfile.v2 | 1 + test/unordered/scoped_allocator.cpp | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c33da46c..572fa265 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -126,6 +126,7 @@ build_foa load_factor_tests ; build_foa rehash_tests ; build_foa equality_tests ; build_foa swap_tests ; +run unordered/scoped_allocator.cpp : : : 98:no 03:no 0x:no msvc-14.0:no BOOST_UNORDERED_FOA_TESTS : foa_scoped_allocator ; build_foa transparent_tests ; build_foa reserve_tests ; build_foa contains_tests ; diff --git a/test/unordered/scoped_allocator.cpp b/test/unordered/scoped_allocator.cpp index a8e02c8b..cde1f96e 100644 --- a/test/unordered/scoped_allocator.cpp +++ b/test/unordered/scoped_allocator.cpp @@ -21,8 +21,14 @@ int main() {} // clang-format off #include "../helpers/prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else #include #include +#endif #include "../helpers/postfix.hpp" // clang-format on @@ -32,10 +38,10 @@ int main() {} #include +#include #include #include #include -#include namespace test { template struct allocator @@ -70,9 +76,15 @@ typedef std::scoped_allocator_adaptor, test::allocator > allocator_type; +#ifdef BOOST_UNORDERED_FOA_TESTS +typedef boost::unordered_flat_map, std::equal_to, allocator_type> + map_type; +#else typedef boost::unordered_map, std::equal_to, allocator_type> map_type; +#endif UNORDERED_AUTO_TEST (scoped_allocator) { allocator_type alloc( From e16537d24438933d07e0e0791e545577802b7e90 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 14 Oct 2022 11:28:26 -0700 Subject: [PATCH 203/279] Add helper header to include map types based on FOA vs FCA --- test/helpers/unordered.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/helpers/unordered.hpp diff --git a/test/helpers/unordered.hpp b/test/helpers/unordered.hpp new file mode 100644 index 00000000..289e79b7 --- /dev/null +++ b/test/helpers/unordered.hpp @@ -0,0 +1,21 @@ + +// Copyright 2022 Christian Mazakas +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_UNORDERED_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_UNORDERED_HEADER + +// clang-format off +#include "prefix.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +#include +#include +#include +#else +#include +#include +#endif +#include "postfix.hpp" + +#endif From 1de8801c08c41f06a8fd64389150a65cef95b421 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 14 Oct 2022 11:28:40 -0700 Subject: [PATCH 204/279] Add scary_tests --- test/Jamfile.v2 | 1 + test/unordered/scary_tests.cpp | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 572fa265..f1b4b641 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -131,3 +131,4 @@ build_foa transparent_tests ; build_foa reserve_tests ; build_foa contains_tests ; build_foa erase_if ; +build_foa scary_tests ; diff --git a/test/unordered/scary_tests.cpp b/test/unordered/scary_tests.cpp index 383af13a..f4508519 100644 --- a/test/unordered/scary_tests.cpp +++ b/test/unordered/scary_tests.cpp @@ -2,14 +2,8 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#include -#include -#include "../helpers/postfix.hpp" -// clang-format on - #include "../helpers/test.hpp" +#include "../helpers/unordered.hpp" #include "../objects/test.hpp" #include @@ -107,8 +101,7 @@ public: // ever using it with an int with has a trivial destructor so it eliminates // the code and generates a warning about an unused variable // - template - void destroy(U* p) + template void destroy(U* p) { (void)p; p->~U(); @@ -192,8 +185,7 @@ public: // ever using it with an int with has a trivial destructor so it eliminates // the code and generates a warning about an unused variable // - template - void destroy(U* p) + template void destroy(U* p) { (void)p; p->~U(); @@ -226,11 +218,13 @@ template void scary_test() BOOST_TEST_EQ(x.bucket_count(), 0u); +#ifndef BOOST_UNORDERED_FOA_TESTS typename C2::local_iterator lbegin(x.begin(0)); BOOST_TEST(lbegin == x.end(0)); typename C2::const_local_iterator clbegin(x.cbegin(0)); BOOST_TEST(clbegin == x.cend(0)); +#endif } template < @@ -316,11 +310,16 @@ void set_scary_test() } UNORDERED_AUTO_TEST (scary_tests) { +#ifdef BOOST_UNORDERED_FOA_TESTS + map_scary_test(); + set_scary_test(); +#else map_scary_test(); map_scary_test(); set_scary_test(); set_scary_test(); +#endif } RUN_TESTS() From 9da61e9050afab56eb5a088fb66e8eb02684a93e Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 14 Oct 2022 13:19:37 -0700 Subject: [PATCH 205/279] Add post_move_tests --- test/Jamfile.v2 | 1 + test/unordered/post_move_tests.cpp | 63 ++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f1b4b641..4210f127 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -114,6 +114,7 @@ build_foa equivalent_keys_tests ; build_foa constructor_tests ; build_foa copy_tests ; build_foa move_tests ; +build_foa post_move_tests ; build_foa assign_tests ; build_foa insert_tests ; build_foa insert_hint_tests ; diff --git a/test/unordered/post_move_tests.cpp b/test/unordered/post_move_tests.cpp index 5184a3a0..c0bb0aa7 100644 --- a/test/unordered/post_move_tests.cpp +++ b/test/unordered/post_move_tests.cpp @@ -3,13 +3,7 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) -// clang-format off -#include "../helpers/prefix.hpp" -#include -#include -#include "../helpers/postfix.hpp" -// clang-format on - +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../objects/cxx11_allocator.hpp" @@ -438,11 +432,13 @@ namespace move_tests { copy_assignment, move_assignment, equal, + #ifndef BOOST_UNORDERED_FOA_TESTS extract, + buckets, + #endif merge, erase_with_pred, container_swap, - buckets, double_move_construct, double_move_assign }; @@ -489,8 +485,13 @@ namespace move_tests { T y(v.begin(), v.end(), 0, hf, eq, al1); T x(boost::move(y), al2); +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); +#else BOOST_TEST_NOT(y.empty()); BOOST_TEST(y.begin() != y.end()); +#endif fps[i](y, v); @@ -558,8 +559,13 @@ namespace move_tests { #endif } else { +#ifdef BOOST_UNORDERED_FOA_TESTS + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); +#else BOOST_TEST_NOT(y.empty()); BOOST_TEST(y.begin() != y.end()); +#endif } fps[i](y, v); @@ -569,6 +575,42 @@ namespace move_tests { } } + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS + boost::unordered_flat_map > >* + test_map_std_alloc; + + boost::unordered_flat_set >* test_set; + boost::unordered_flat_map > >* test_map; + + boost::unordered_flat_set >* + test_set_prop_move; + boost::unordered_flat_map, + test::propagate_move> >* test_map_prop_move; + + boost::unordered_flat_set >* + test_set_no_prop_move; + boost::unordered_flat_map, + test::no_propagate_move> >* test_map_no_prop_move; + + UNORDERED_TEST(post_move_tests, + ((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) +#else boost::unordered_map > >* test_map_std_alloc; @@ -612,16 +654,13 @@ namespace move_tests { test::cxx11_allocator, test::no_propagate_move> >* test_multimap_no_prop_move; - using test::default_generator; - using test::generate_collisions; - using test::limited_range; - UNORDERED_TEST(post_move_tests, ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)( test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)( test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( test_multimap_no_prop_move))( (default_generator)(generate_collisions)(limited_range))) +#endif } RUN_TESTS() From e663812f2422f68c1f07b6cf315fd367aa7164e2 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 10:18:47 +0200 Subject: [PATCH 206/279] editorial --- include/boost/unordered/detail/foa.hpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index c03dae25..3f80f587 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -85,7 +85,7 @@ namespace foa{ * quadratic probing. * - Each group has an associated 16B metadata word holding reduced hash * values and overflow information. Reduced hash values are used to - * accelerate lookup within the group by using SIMD or 64-bit word + * accelerate lookup within the group by using 128-bit SIMD or 64-bit word * operations. */ @@ -113,10 +113,10 @@ namespace foa{ * the table), probing stops at the first non-overflowed group. Having 8 * bits for signalling overflow makes it very likely that we stop at the * current group (this happens when no element with the same (h%8) value - * has overflowed in the same group), saving us an additional group check - * even under high-load/high-erase conditions. + * has overflowed in the group), saving us an additional group check even + * under high-load/high-erase conditions. * - * When looking for an element with hash value h, match(n) returns a bitmask + * When looking for an element with hash value h, match(h) returns a bitmask * signalling which slots have the same reduced hash value. If available, * match uses SSE2 or (little endian) Neon 128-bit SIMD operations. On non-SIMD * scenarios, the logical layout described above is physically mapped to two @@ -601,8 +601,9 @@ inline void prefetch(const void* p) #endif } -/* foa::table uses a size policy to control the permissible sizes of the group - * array (and, by implication, the element array) and the hash->group mapping. +/* foa::table uses a size policy to obtain the permissible sizes of the group + * array (and, by implication, the element array) and to do the hash->group + * mapping. * * - size_index(n) returns an unspecified "index" number used in other policy * operations. @@ -621,8 +622,8 @@ inline void prefetch(const void* p) * of the hash value as the position in the group array. Using a size index * defined as i = (bits in std::size_t) - n, we have an unbeatable * implementation of position(hash) as hash>>i. We've chosen to select the - * most significant bits of hash for positioning as multiplication-based mixing - * tends to yield better entropy in the high part of its result. + * most significant bits of hash for positioning because multiplication-based + * mixing tends to yield better entropy in the high part of its result. */ struct pow2_size_policy @@ -650,8 +651,8 @@ struct pow2_size_policy }; /* Quadratic prober over a power-of-two range using triangular numbers. - * mask in next(mask) is expected to be the range size minus one (and since - * size is 2^n, mask has exactly its n first bits set to 1). + * mask in next(mask) must be the range size minus one (and since size is 2^n, + * mask has exactly its n first bits set to 1). */ struct pow2_quadratic_prober @@ -703,7 +704,7 @@ struct xmx_mix template class table; -/* table_iterators keeps two pointers: +/* table_iterator keeps two pointers: * * - A pointer p to the element slot. * - A pointer pc to the n-th byte of the associated group metadata, where n @@ -713,7 +714,7 @@ class table; * pointer pg to the group, and the position n, but that would increase * sizeof(table_iterator) by 4/8 bytes. In order to make this compact * representation possible, it is required that group objects are aligned - * to its size, so that we can recover pg and n as + * to their size, so that we can recover pg and n as * * - n = pc%sizeof(group) * - pg = pc-n From 1532e301d178c07aae0749d303dd8458fba10b26 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 10:51:28 +0200 Subject: [PATCH 207/279] micro-optimized non-SIMD group15::match_impl --- include/boost/unordered/detail/foa.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3f80f587..3b8eeed6 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -123,7 +123,7 @@ namespace foa{ * 64-bit words with *bit interleaving*, i.e. the least significant 16 bits of * the first 64-bit word contain the least significant bits of each byte in the * "logical" 128-bit word, and so forth. With this layout, match can be - * implemented with 5 ANDs, 3 shifts, 2 XORs and 2 NOTs. + * implemented with 4 ANDs, 3 shifts, 2 XORs, 1 OR and 1 NOT. */ #if defined(BOOST_UNORDERED_SSE2) @@ -568,9 +568,9 @@ private: }; BOOST_ASSERT(n<256); - boost::uint64_t lo=~(m[0]^mask[n&0xFu]); - boost::uint64_t hi=~(m[1]^mask[n>>4])&lo; - boost::uint32_t y=static_cast(hi&(hi>>32)); + boost::uint64_t x=m[0]^mask[n&0xFu]; + x=~((m[1]^mask[n>>4])|x); + boost::uint32_t y=static_cast(x&(x>>32)); y&=y>>16; return y&0x7FFF; } From acc7f0ce5cc7ca6a0b428e7d0f9995c833432f97 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 11:05:51 +0200 Subject: [PATCH 208/279] refactored table_arrays dummy groups handling --- include/boost/unordered/detail/foa.hpp | 30 +++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3b8eeed6..d875ac7b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -815,6 +815,23 @@ private: * allocators. */ +template +Group* dummy_groups() +{ + /* Dummy storage initialized as if in an empty container. We make + * table_arrays::groups point to this for empty containers, so that find() + * etc. can be implemented without checking groups==nullptr. This space won't + * ever be used for insertion as container capacity is properly tuned to + * avoid that. + */ + + static constexpr typename Group::dummy_group_type + storage[Size]={typename Group::dummy_group_type(),}; + + return reinterpret_cast( + const_cast(storage)); +} + template struct table_arrays { @@ -834,18 +851,7 @@ struct table_arrays table_arrays arrays{groups_size_index,groups_size-1,nullptr,nullptr}; if(!n){ - /* We make groups point to dummy storage initialized as if in an empty - * container. This allows us to implement find() etc. without checking - * groups==nullptr. This space won't ever be used for insertion as - * container capacity is properly tuned to avoid that. - */ - - static constexpr typename group_type::dummy_group_type - storage[size_policy::min_size()]= - {typename group_type::dummy_group_type(),}; - - arrays.groups=reinterpret_cast( - const_cast(storage)); + arrays.groups=dummy_groups(); } else{ arrays.elements= From 3bf28d7b61c52701824fd9906d5a38e3c61c1856 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 11:06:15 +0200 Subject: [PATCH 209/279] stylistic --- include/boost/unordered/detail/foa.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d875ac7b..4603e9eb 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1710,9 +1710,9 @@ private: } } - std::size_t size_; - arrays_type arrays; - std::size_t ml; + std::size_t size_; + arrays_type arrays; + std::size_t ml; }; #if BOOST_WORKAROUND(BOOST_MSVC,<=1900) From b8d4df2b5c33407af7877741973e6912ef5c4b27 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 11:07:48 +0200 Subject: [PATCH 210/279] stylistic --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 4603e9eb..0ba23751 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1436,7 +1436,7 @@ private: typename T, typename std::enable_if::value>::type* =nullptr > - static inline auto value_from(T&& x)->decltype(std::forward(x)) + static inline T&& value_from(T&& x) { return std::forward(x); } From 0b575dc98304af2b8e8f565783f0f85898df3b52 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 11:14:36 +0200 Subject: [PATCH 211/279] s/const/constexpr in simde_mm_movemask_epi8 --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 0ba23751..5404126e 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -377,7 +377,7 @@ private: static inline int simde_mm_movemask_epi8(uint8x16_t a) { - static const uint8_t md[16]={ + static constexpr uint8_t md[16]={ 1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7, 1 << 0, 1 << 1, 1 << 2, 1 << 3, From 63eaed843f1d3568a88a671a01d6154e10ced18b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 11:15:29 +0200 Subject: [PATCH 212/279] stylistic --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 5404126e..666565f3 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -571,8 +571,8 @@ private: boost::uint64_t x=m[0]^mask[n&0xFu]; x=~((m[1]^mask[n>>4])|x); boost::uint32_t y=static_cast(x&(x>>32)); - y&=y>>16; - return y&0x7FFF; + y&=y>>16; + return y&0x7FFF; } alignas(16) boost::uint64_t m[2]; From 3a0b75236319db72eb67e6acfdcd075f8f26666c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 11:17:51 +0200 Subject: [PATCH 213/279] reorganized function definitions --- include/boost/unordered/detail/foa.hpp | 43 +++++++++++++------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 666565f3..5f6f7fdd 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -580,27 +580,6 @@ private: #endif -inline unsigned int unchecked_countr_zero(int x) -{ -#if defined(BOOST_MSVC) - unsigned long r; - _BitScanForward(&r,(unsigned long)x); - return (unsigned int)r; -#else - BOOST_UNORDERED_ASSUME(x); - return (unsigned int)boost::core::countr_zero((unsigned int)x); -#endif -} - -inline void prefetch(const void* p) -{ -#if defined(BOOST_GCC)||defined(BOOST_CLANG) - __builtin_prefetch((const char*)p); -#elif defined(BOOST_UNORDERED_SSE2) - _mm_prefetch((const char*)p,_MM_HINT_T0); -#endif -} - /* foa::table uses a size policy to obtain the permissible sizes of the group * array (and, by implication, the element array) and to do the hash->group * mapping. @@ -701,6 +680,18 @@ struct xmx_mix } }; +inline unsigned int unchecked_countr_zero(int x) +{ +#if defined(BOOST_MSVC) + unsigned long r; + _BitScanForward(&r,(unsigned long)x); + return (unsigned int)r; +#else + BOOST_UNORDERED_ASSUME(x); + return (unsigned int)boost::core::countr_zero((unsigned int)x); +#endif +} + template class table; @@ -935,6 +926,16 @@ void swap_if(T& x,T& y){using std::swap; swap(x,y);} template::type* =nullptr> void swap_if(T&,T&){} +inline void prefetch(const void* p) +{ +#if defined(BOOST_GCC)||defined(BOOST_CLANG) + __builtin_prefetch((const char*)p); +#elif defined(BOOST_UNORDERED_SSE2) + _mm_prefetch((const char*)p,_MM_HINT_T0); +#endif +} + + // we pull this out so the tests don't have to rely on a magic constant or // instantiate the table class template as it can be quite gory // From cc75360f4c051ef1ce5220a8273f78967c033f99 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 12:38:39 +0200 Subject: [PATCH 214/279] kept adding design/implementation notes --- include/boost/unordered/detail/foa.hpp | 70 +++++++++++++++++++++----- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 5f6f7fdd..8babc8a9 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -73,7 +73,7 @@ namespace detail{ namespace foa{ /* foa::table is an open-addressing hash table serving as the foundational core - * of boost::unordered_flat_[map|set]. Its main design aspects are: + * of boost::unordered_flat_[map|set]. Its main internal design aspects are: * * - Element slots are logically split into groups of size N=15. The number * of groups is always a power of two, so the number of allocated slots @@ -373,7 +373,9 @@ private: return table[(unsigned char)hash]; } - /* copied from https://github.com/simd-everywhere/simde/blob/master/simde/x86/sse2.h#L3763 */ + /* Copied from + * https://github.com/simd-everywhere/simde/blob/master/simde/x86/sse2.h#L3763 + */ static inline int simde_mm_movemask_epi8(uint8x16_t a) { @@ -680,6 +682,10 @@ struct xmx_mix } }; +/* boost::core::countr_zero has a potentially costly check for + * the case x==0. + */ + inline unsigned int unchecked_countr_zero(int x) { #if defined(BOOST_MSVC) @@ -704,7 +710,7 @@ class table; * A simpler solution would have been to keep a pointer p to the element, a * pointer pg to the group, and the position n, but that would increase * sizeof(table_iterator) by 4/8 bytes. In order to make this compact - * representation possible, it is required that group objects are aligned + * representation feasible, it is required that group objects are aligned * to their size, so that we can recover pg and n as * * - n = pc%sizeof(group) @@ -717,7 +723,8 @@ class table; * p = nullptr is conventionally used to mark end() iterators. */ -class const_iterator_cast_tag {}; +/* internal conversion from const_iterator to iterator */ +class const_iterator_cast_tag {}; template class table_iterator @@ -935,12 +942,6 @@ inline void prefetch(const void* p) #endif } - -// we pull this out so the tests don't have to rely on a magic constant or -// instantiate the table class template as it can be quite gory -// -constexpr static float const mlf = 0.875f; - #if defined(BOOST_GCC) /* GCC's -Wshadow triggers at scenarios like this: * @@ -976,6 +977,51 @@ constexpr static float const mlf = 0.875f; #pragma warning(disable:4702) #endif +/* 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_[map|set] wrappers complete it as appropriate) and, + * more importantly, because of fundamental restrictions imposed by open + * addressing: + * + * - value_type must be moveable. + * - Pointer stability is not kept under rehashing. + * - begin() is not O(1). + * - No bucket API. + * - Load factor is fixed and can't be set by the user. + * - No extract API. + * + * The TypePolicy template parameter is used to generate instantiations + * suitable for either maps or sets, and introduces non-standard init_type: + * + * - TypePolicy::key_type and TypePolicy::value_type have the obvious + * meaning. + * - TypePolicy::init_type is the type implicitly converted to when + * writing x.insert({...}). For maps, this is std::pair rather + * than std::pair so that, for instance, x.insert({"hello",0}) + * produces a cheaply moveable std::string&& ("hello") rather than + * a copyable const std::string&&. foa::table::insert is extended to accept + * both init_type and value_type references. + * - TypePolicy::move(value_type&) returns a temporary object for value + * transfer on rehashing, move copy/asignment, and merge. For maps, this + * object is a std::pair, which is generally cheaper to move + * than std::pair&& because of the constness in Key. + * - TypePolicy::extract returns a const reference to the key part of + * a value of type value_type, init_type or + * decltype(TypePolicy::move(...)). + * + * try_emplace, erase and find support heterogenous lookup by default, that is, + * without checking for any ::is_transparent typedefs --the checking is done by + * boost::unordered_flat_[map|set]. + * + * At the moment, we're not supporting allocators with fancy pointers. + * Allocator::pointer must be convertible to/from regular pointers. + */ + +/* We pull this out so the tests don't have to rely on a magic constant or + * instantiate the table class template as it can be quite gory. + */ +constexpr static float const mlf = 0.875f; + template class @@ -1523,11 +1569,11 @@ private: }while(mask); } if(BOOST_LIKELY(pg->is_not_overflowed(hash))){ - return {}; // TODO end() does not work (returns const_iterator) + return {}; /* end() */ } } while(BOOST_LIKELY(pb.next(arrays.groups_size_mask))); - return {}; // TODO end() does not work (returns const_iterator) + return {}; /* end() */ } #if defined(BOOST_MSVC) From 7c5bad60c65604f339dabe8c1630bc26db2db765 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 13:14:32 +0200 Subject: [PATCH 215/279] reordered #includes --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 8babc8a9..49276fa0 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -14,8 +14,8 @@ #include #include #include -#include #include +#include #include #include #include From ec389cdecd773d541eace8f9ed2cbf967cb53630 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 15 Oct 2022 18:33:59 +0200 Subject: [PATCH 216/279] kept adding design/implementation notes --- include/boost/unordered/detail/foa.hpp | 42 +++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 49276fa0..2a9d812b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -597,14 +597,17 @@ private: * * The reason we're introducing the intermediate index value for calculating * sizes and positions is that it allows us to optimize the implementation of - * position, which is in the hot path of lookup and insertion operations. + * position, which is in the hot path of lookup and insertion operations: * pow2_size_policy, the actual size policy used by foa::table, returns 2^n * (n>0) as permissible sizes and returns the n most significant bits - * of the hash value as the position in the group array. Using a size index + * of the hash value as the position in the group array; using a size index * defined as i = (bits in std::size_t) - n, we have an unbeatable - * implementation of position(hash) as hash>>i. We've chosen to select the - * most significant bits of hash for positioning because multiplication-based - * mixing tends to yield better entropy in the high part of its result. + * implementation of position(hash) as hash>>i. + * There's a twofold reason for choosing the high bits of hash for positioning: + * - Multiplication-based mixing tends to yield better entropy in the high + * part of its result. + * - group15 reduced-hash values take the *low* bits of hash, and we want + * these values and positioning to be as uncorrelated as possible. */ struct pow2_size_policy @@ -816,11 +819,12 @@ private: template Group* dummy_groups() { - /* Dummy storage initialized as if in an empty container. We make - * table_arrays::groups point to this for empty containers, so that find() - * etc. can be implemented without checking groups==nullptr. This space won't - * ever be used for insertion as container capacity is properly tuned to - * avoid that. + /* Dummy storage initialized as if in an empty container (actually, each + * of its groups is initialized like a separate empty container). + * We make table_arrays::groups point to this when capacity()==0, so that + * we are not allocating any dynamic memory and yet lookup can be implemented + * without checking for groups==nullptr. This space won't ever be used for + * insertion as the container's capacity is precisely zero. */ static constexpr typename Group::dummy_group_type @@ -883,7 +887,8 @@ struct table_arrays if(arrays.elements){ alloc_traits::deallocate( - al,pointer_traits::pointer_to(*arrays.elements),buffer_size(arrays.groups_size_mask+1)); + al,pointer_traits::pointer_to(*arrays.elements), + buffer_size(arrays.groups_size_mask+1)); } } @@ -1087,7 +1092,6 @@ public: std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value): - // TODO verify if we should copy or move copy hash, pred and al hash_base{empty_init,std::move(x.h())}, pred_base{empty_init,std::move(x.pred())}, allocator_base{empty_init,std::move(x.al())}, @@ -1224,6 +1228,7 @@ public: * under noexcept(true) conditions. */ + // TODO may shrink arrays and miss an opportunity for memory reuse reserve(x.size()); BOOST_TRY{ /* This works because subsequent x.clear() does not depend on the @@ -1531,9 +1536,18 @@ private: static inline void prefetch_elements(const value_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 + * prefetched, whereas for Intel just the first cache line is best. + * Please report back if you find better tunings for some particular + * architectures. + */ + #if BOOST_ARCH_ARM - constexpr int cache_line=64; // TODO: get from Boost.Predef? - // TODO: check if this is 128 in current benchmark machine + /* Cache line size can't be known at compile time, so we settle on + * the very frequent value of 64B. + */ + constexpr int cache_line=64; const char *p0=reinterpret_cast(p), *p1=p0+sizeof(value_type)*N/2; for(;p0 Date: Sat, 15 Oct 2022 18:56:46 +0200 Subject: [PATCH 217/279] introduced internal noshrink_reserve --- include/boost/unordered/detail/foa.hpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2a9d812b..ec9450f6 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1174,8 +1174,7 @@ public: if(al()!=x.al())reserve(0); copy_assign_if(al(),x.al()); }); - // TODO may shrink arrays and miss an opportunity for memory reuse - reserve(x.size()); + noshrink_reserve(x.size()); x.for_all_elements([this](value_type* p){ unchecked_insert(*p); }); @@ -1228,8 +1227,7 @@ public: * under noexcept(true) conditions. */ - // TODO may shrink arrays and miss an opportunity for memory reuse - reserve(x.size()); + noshrink_reserve(x.size()); BOOST_TRY{ /* This works because subsequent x.clear() does not depend on the * elements' values. @@ -1652,6 +1650,22 @@ private: ml=max_load(); } + void noshrink_reserve(std::size_t n) + { + /* used only on assignment after element clearance */ + BOOST_ASSERT(size_==0); + + auto c=std::size_t(std::ceil(static_cast(n)/mlf)); + if(c) c=size_policy::size(size_policy::size_index(c/N+1))*N-1; + + if(c>capacity()){ + auto new_arrays_=new_arrays(c); + delete_arrays(arrays); + arrays=new_arrays_; + ml=max_load(); + } + } + template void unchecked_insert(Value&& x) { From 4fa61b98ebb5accf3375f264a0d23a7e0b375292 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 16 Oct 2022 10:11:47 +0200 Subject: [PATCH 218/279] made rehash work with exact capacities, refactored capacity calculations --- include/boost/unordered/detail/foa.hpp | 49 +++++++++++++++++--------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index ec9450f6..47f500c6 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -634,6 +634,15 @@ struct pow2_size_policy } }; +/* size index of a group array for a given *element* capacity */ + +template +static inline std::size_t size_index_for(std::size_t n) +{ + /* n/N+1 == ceil((n+1)/N) (extra +1 for the sentinel) */ + return SizePolicy::size_index(n/Group::N+1); +} + /* Quadratic prober over a power-of-two range using triangular numbers. * mask in next(mask) must be the range size minus one (and since size is 2^n, * mask has exactly its n first bits set to 1). @@ -847,8 +856,7 @@ struct table_arrays { using alloc_traits=boost::allocator_traits; - /* n/N+1 == ceil((n+1)/N) (extra +1 for the sentinel) */ - auto groups_size_index=size_policy::size_index(n/N+1); + auto groups_size_index=size_index_for(n); auto groups_size=size_policy::size(groups_size_index); table_arrays arrays{groups_size_index,groups_size-1,nullptr,nullptr}; @@ -1174,7 +1182,8 @@ public: if(al()!=x.al())reserve(0); copy_assign_if(al(),x.al()); }); - noshrink_reserve(x.size()); + /* noshrink: favor memory reuse over tightness */ + noshrink_reserve(x.size()); x.for_all_elements([this](value_type* p){ unchecked_insert(*p); }); @@ -1227,6 +1236,7 @@ public: * under noexcept(true) conditions. */ + /* noshrink: favor memory reuse over tightness */ noshrink_reserve(x.size()); BOOST_TRY{ /* This works because subsequent x.clear() does not depend on the @@ -1406,16 +1416,16 @@ public: void rehash(std::size_t n) { - auto c1=std::size_t(std::ceil(float(size())/mlf)); - auto c2=n?size_policy::size(size_policy::size_index(n/N+1))*N-1:0; - auto c=c1>c2?c1:c2; /* we avoid std::max to not include */ + auto m=size_t(std::ceil(float(size())/mlf)); + if(m>n)n=m; + if(n)n=capacity_for(n); /* exact resulting capacity */ - if(c!=capacity())unchecked_rehash(c); + if(n!=capacity())unchecked_rehash(n); } void reserve(std::size_t n) { - rehash(std::size_t(std::ceil(static_cast(n)/mlf))); + rehash(std::size_t(std::ceil(float(n)/mlf))); } template @@ -1614,6 +1624,11 @@ private: }; } + static std::size_t capacity_for(std::size_t n) + { + return size_policy::size(size_index_for(n))*N-1; + } + BOOST_NOINLINE void unchecked_rehash(std::size_t n) { auto new_arrays_=new_arrays(n); @@ -1653,16 +1668,18 @@ private: void noshrink_reserve(std::size_t n) { /* used only on assignment after element clearance */ - BOOST_ASSERT(size_==0); + BOOST_ASSERT(empty()); - auto c=std::size_t(std::ceil(static_cast(n)/mlf)); - if(c) c=size_policy::size(size_policy::size_index(c/N+1))*N-1; + if(n){ + n=std::size_t(std::ceil(float(n)/mlf)); /* elements -> slots */ + n=capacity_for(n); /* exact resulting capacity */ - if(c>capacity()){ - auto new_arrays_=new_arrays(c); - delete_arrays(arrays); - arrays=new_arrays_; - ml=max_load(); + if(n>capacity()){ + auto new_arrays_=new_arrays(n); + delete_arrays(arrays); + arrays=new_arrays_; + ml=max_load(); + } } } From bb6b57d1a4940067f07750f0dcc605e73953df5f Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 16 Oct 2022 17:45:17 +0200 Subject: [PATCH 219/279] typo --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 47f500c6..d34a49c7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1015,7 +1015,7 @@ inline void prefetch(const void* p) * a copyable const std::string&&. foa::table::insert is extended to accept * both init_type and value_type references. * - TypePolicy::move(value_type&) returns a temporary object for value - * transfer on rehashing, move copy/asignment, and merge. For maps, this + * transfer on rehashing, move copy/assignment, and merge. For maps, this * object is a std::pair, which is generally cheaper to move * than std::pair&& because of the constness in Key. * - TypePolicy::extract returns a const reference to the key part of From 9246c301784fdaf2210c64e919a874a6c565adcd Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 16 Oct 2022 21:33:40 +0200 Subject: [PATCH 220/279] activated alternative impl of nosize_unchecked_emplace_at --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d34a49c7..01fc3d84 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1708,7 +1708,7 @@ private: return res; } -#if 0 +#if 1 template iterator nosize_unchecked_emplace_at( const arrays_type& arrays_,std::size_t pos0,std::size_t hash, From 0389e0bc16416446c05fe8d509d4b79432913bb1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 16 Oct 2022 22:17:53 +0200 Subject: [PATCH 221/279] reverted --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 01fc3d84..d34a49c7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1708,7 +1708,7 @@ private: return res; } -#if 1 +#if 0 template iterator nosize_unchecked_emplace_at( const arrays_type& arrays_,std::size_t pos0,std::size_t hash, From b0f6bb128fd0e48503394851fc572c6de15696c0 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 17 Oct 2022 09:43:22 +0200 Subject: [PATCH 222/279] micro-optimized group loops --- include/boost/unordered/detail/foa.hpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d34a49c7..cb225c9d 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1640,10 +1640,9 @@ private: }); } BOOST_CATCH(...){ - size_-=num_tx; if(num_tx){ - auto pg=arrays.groups; - for(std::size_t pos=0;;++pos,++pg){ + size_-=num_tx; + for(auto pg=arrays.groups;;++pg){ auto mask=pg->match_occupied(); while(mask){ auto nz=unchecked_countr_zero(mask); @@ -1651,11 +1650,11 @@ private: if(!(--num_tx))goto continue_; } } + continue_: + for_all_elements(new_arrays_,[this](value_type* p){ + destroy_element(p); + }); } - continue_: - for_all_elements(new_arrays_,[this](value_type* p){ - destroy_element(p); - }); delete_arrays(new_arrays_); BOOST_RETHROW } @@ -1788,11 +1787,10 @@ private: static auto for_all_elements(const arrays_type& arrays_,F f) ->decltype(f(nullptr,0,nullptr),void()) { - auto pg=arrays_.groups; auto p=arrays_.elements; if(!p){return;} - for(std::size_t pos=0,last=arrays_.groups_size_mask+1; - pos!=last;++pos,++pg,p+=N){ + for(auto pg=arrays_.groups,last=pg+arrays_.groups_size_mask+1; + pg!=last;++pg,p+=N){ auto mask=pg->match_really_occupied(); while(mask){ auto n=unchecked_countr_zero(mask); From 6b1d2f13da801742dd49a11718303f19869b1066 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 17 Oct 2022 17:51:43 +0200 Subject: [PATCH 223/279] made clear reset overflow bytes --- include/boost/unordered/detail/foa.hpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index cb225c9d..90388f44 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1364,11 +1364,24 @@ public: void clear()noexcept { - for_all_elements([&,this](group_type* pg,unsigned int n,value_type* p){ - destroy_element(p); - pg->reset(n); - }); - size_=0; + alignas(group_type) static constexpr unsigned char + zero[sizeof(group_type)]={0,}; + + auto p=arrays.elements; + if(p){ + for(auto pg=arrays.groups,last=pg+arrays.groups_size_mask+1; + pg!=last;++pg,p+=N){ + auto mask=pg->match_really_occupied(); + while(mask){ + destroy_element(p+unchecked_countr_zero(mask)); + mask&=mask-1; + } + /* we wipe the entire metadata to reset the overflow byte as well */ + *pg=*reinterpret_cast(zero); + } + arrays.groups[arrays.groups_size_mask].set_sentinel(); + size_=0; + } } // TODO: should we accept different allocator too? From 599dee204ff9bc9cbaad75ec1d077a6e7d957c15 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 17 Oct 2022 18:00:15 +0200 Subject: [PATCH 224/279] micro-optimized table destruction --- include/boost/unordered/detail/foa.hpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 90388f44..92bffb5d 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1123,8 +1123,7 @@ public: }); } BOOST_CATCH(...){ - clear(); - delete_arrays(arrays); + destroy(); BOOST_RETHROW } BOOST_CATCH_END @@ -1153,9 +1152,8 @@ public: }); } BOOST_CATCH(...){ - clear(); - delete_arrays(arrays); x.clear(); + destroy(); BOOST_RETHROW } BOOST_CATCH_END @@ -1165,8 +1163,7 @@ public: ~table()noexcept { - clear(); - delete_arrays(arrays); + destroy(); } table& operator=(const table& x) @@ -1458,6 +1455,14 @@ private: Allocator& al(){return allocator_base::get();} const Allocator& al()const{return allocator_base::get();} + void destroy()noexcept + { + for_all_elements([this](value_type* p){ + destroy_element(p); + }); + delete_arrays(arrays); + } + arrays_type new_arrays(std::size_t n) { return arrays_type::new_(al(),n); From eb5351b2c6b814e833dc185d2659ab5dd847b9e4 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 17 Oct 2022 18:21:41 +0200 Subject: [PATCH 225/279] used regular method for group resetting in clear --- include/boost/unordered/detail/foa.hpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 92bffb5d..a88ab187 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -269,7 +269,7 @@ private: return at(N); } - alignas(16) __m128i m; + alignas(16) __m128i m=_mm_setzero_si128(); }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) @@ -412,7 +412,7 @@ private: return at(N); } - alignas(16) int8x16_t m; + alignas(16) int8x16_t m=vdupq_n_s8(0); }; #else /* non-SIMD */ @@ -577,7 +577,7 @@ private: return y&0x7FFF; } - alignas(16) boost::uint64_t m[2]; + alignas(16) boost::uint64_t m[2]={0,0}; }; #endif @@ -1361,9 +1361,6 @@ public: void clear()noexcept { - alignas(group_type) static constexpr unsigned char - zero[sizeof(group_type)]={0,}; - auto p=arrays.elements; if(p){ for(auto pg=arrays.groups,last=pg+arrays.groups_size_mask+1; @@ -1374,7 +1371,7 @@ public: mask&=mask-1; } /* we wipe the entire metadata to reset the overflow byte as well */ - *pg=*reinterpret_cast(zero); + *pg=group_type(); } arrays.groups[arrays.groups_size_mask].set_sentinel(); size_=0; From 6e4e5ead03e22007a4e16955fa80a8d4236e64e1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Mon, 17 Oct 2022 18:43:48 +0200 Subject: [PATCH 226/279] made Neon group15 compatible with A32 --- include/boost/unordered/detail/foa.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index a88ab187..448ba371 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -389,7 +389,13 @@ private: uint8x16_t masked=vandq_u8(vld1q_u8(md),a); uint8x8x2_t tmp=vzip_u8(vget_low_u8(masked),vget_high_u8(masked)); uint16x8_t x=vreinterpretq_u16_u8(vcombine_u8(tmp.val[0],tmp.val[1])); + +#if defined(__ARM_ARCH_ISA_A64) return vaddvq_u16(x); +#else + uint64x2_t t64=vpaddlq_u32(vpaddlq_u16(x)); + return int(vgetq_lane_u64(t64,0))+int(vgetq_lane_u64(t64,1)); +#endif } inline unsigned char& at(std::size_t pos) From aa41ab4195e50f2f94a1d589181db93fe6c12299 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 17 Oct 2022 13:19:29 -0700 Subject: [PATCH 227/279] Add constructor_exception tests for FOA --- test/Jamfile.v2 | 2 ++ test/exception/containers.hpp | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4210f127..817fd125 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -133,3 +133,5 @@ build_foa reserve_tests ; build_foa contains_tests ; build_foa erase_if ; build_foa scary_tests ; + +run exception/constructor_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ; diff --git a/test/exception/containers.hpp b/test/exception/containers.hpp index c3b34be2..9f78923d 100644 --- a/test/exception/containers.hpp +++ b/test/exception/containers.hpp @@ -3,15 +3,30 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#include -#include -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../objects/exception.hpp" +#ifdef BOOST_UNORDERED_FOA_TESTS +typedef boost::unordered_flat_set > + test_set; + +typedef boost::unordered_flat_map > + test_map; + +typedef boost::unordered_flat_set< + std::pair, + test::exception::hash, test::exception::equal_to, + test::exception::allocator > + test_pair_set; + +#define CONTAINER_SEQ (test_set)(test_map) +#define CONTAINER_PAIR_SEQ (test_pair_set)(test_map) +#else typedef boost::unordered_set > @@ -42,3 +57,5 @@ typedef boost::unordered_multiset< #define CONTAINER_SEQ (test_set)(test_multiset)(test_map)(test_multimap) #define CONTAINER_PAIR_SEQ \ (test_pair_set)(test_pair_multiset)(test_map)(test_multimap) + +#endif From cf6f4023bb5517b00f57c00f5e4251c10aee90b5 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 17 Oct 2022 13:19:57 -0700 Subject: [PATCH 228/279] Make sure mask is properly cleared during rehash cleanup --- include/boost/unordered/detail/foa.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 448ba371..eef0729c 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1669,6 +1669,7 @@ private: auto nz=unchecked_countr_zero(mask); pg->reset(nz); if(!(--num_tx))goto continue_; + mask&=mask-1; } } continue_: From 27c386d47b8a6ca376e6a67211f7841465314f03 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 17 Oct 2022 13:20:01 -0700 Subject: [PATCH 229/279] Revert "used regular method for group resetting in clear" This reverts commit eb5351b2c6b814e833dc185d2659ab5dd847b9e4. --- include/boost/unordered/detail/foa.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index eef0729c..31292a15 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -269,7 +269,7 @@ private: return at(N); } - alignas(16) __m128i m=_mm_setzero_si128(); + alignas(16) __m128i m; }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) @@ -418,7 +418,7 @@ private: return at(N); } - alignas(16) int8x16_t m=vdupq_n_s8(0); + alignas(16) int8x16_t m; }; #else /* non-SIMD */ @@ -583,7 +583,7 @@ private: return y&0x7FFF; } - alignas(16) boost::uint64_t m[2]={0,0}; + alignas(16) boost::uint64_t m[2]; }; #endif @@ -1367,6 +1367,9 @@ public: void clear()noexcept { + alignas(group_type) static constexpr unsigned char + zero[sizeof(group_type)]={0,}; + auto p=arrays.elements; if(p){ for(auto pg=arrays.groups,last=pg+arrays.groups_size_mask+1; @@ -1377,7 +1380,7 @@ public: mask&=mask-1; } /* we wipe the entire metadata to reset the overflow byte as well */ - *pg=group_type(); + *pg=*reinterpret_cast(zero); } arrays.groups[arrays.groups_size_mask].set_sentinel(); size_=0; From 0d6ebb4d2fefe3a430e2176632479cd1ee71b2b8 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 17 Oct 2022 13:27:36 -0700 Subject: [PATCH 230/279] Add copy_exception_tests for FOA --- test/Jamfile.v2 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 817fd125..58204e16 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -135,3 +135,4 @@ build_foa erase_if ; build_foa scary_tests ; run exception/constructor_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ; +run exception/copy_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ; From ac2bc8d615e9a0e9c7936437c1c4fde650c8fa96 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 12:17:40 +0200 Subject: [PATCH 231/279] made group initialization more straightforward --- include/boost/unordered/detail/foa.hpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 31292a15..37ee4344 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -124,6 +124,10 @@ namespace foa{ * the first 64-bit word contain the least significant bits of each byte in the * "logical" 128-bit word, and so forth. With this layout, match can be * implemented with 4 ANDs, 3 shifts, 2 XORs, 1 OR and 1 NOT. + * + * group15 has no user-defined ctor so that it's a trivial type and can be + * initialized via memset etc. Where needed, group15::initialize sets the + * metadata to all zeros. */ #if defined(BOOST_UNORDERED_SSE2) @@ -137,6 +141,8 @@ struct group15 alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; }; + inline void initialize(){m=_mm_setzero_si128();} + inline void set(std::size_t pos,std::size_t hash) { BOOST_ASSERT(pos(zero); + pg->initialize(); } arrays.groups[arrays.groups_size_mask].set_sentinel(); size_=0; From 2cb1d2bdf0dbafeb2ff83642cc1fe53bb6b8971a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 15:25:54 +0200 Subject: [PATCH 232/279] removed duplicated call to destroy --- include/boost/unordered/detail/foa.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 37ee4344..a707fb1d 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1169,7 +1169,6 @@ public: } BOOST_CATCH(...){ x.clear(); - destroy(); BOOST_RETHROW } BOOST_CATCH_END From a200af610f64dbdbc4210eecd3977d22006fa35a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 15:41:33 +0200 Subject: [PATCH 233/279] refactored table's allocator-extended copy tor --- include/boost/unordered/detail/foa.hpp | 34 +++++++------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index a707fb1d..d75d842b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1109,7 +1109,7 @@ public: {} table(const table& x): - table(x,alloc_traits::select_on_container_copy_construction(x.al())){} + table{x,alloc_traits::select_on_container_copy_construction(x.al())}{} table(table&& x) noexcept( @@ -1127,22 +1127,11 @@ public: } table(const table& x,const Allocator& al_): - hash_base{empty_init,x.h()},pred_base{empty_init,x.pred()}, - allocator_base{empty_init,al_},size_{0}, - arrays( - new_arrays(std::size_t(std::ceil(static_cast(x.size())/mlf)))), - ml{max_load()} + table{std::size_t(std::ceil(float(x.size())/mlf)),x.h(),x.pred(),al_} { - BOOST_TRY{ - x.for_all_elements([this](value_type* p){ - unchecked_insert(*p); - }); - } - BOOST_CATCH(...){ - destroy(); - BOOST_RETHROW - } - BOOST_CATCH_END + x.for_all_elements([this](value_type* p){ + unchecked_insert(*p); + }); } table(table&& x,const Allocator& al_): @@ -1178,7 +1167,10 @@ public: ~table()noexcept { - destroy(); + for_all_elements([this](value_type* p){ + destroy_element(p); + }); + delete_arrays(arrays); } table& operator=(const table& x) @@ -1467,14 +1459,6 @@ private: Allocator& al(){return allocator_base::get();} const Allocator& al()const{return allocator_base::get();} - void destroy()noexcept - { - for_all_elements([this](value_type* p){ - destroy_element(p); - }); - delete_arrays(arrays); - } - arrays_type new_arrays(std::size_t n) { return arrays_type::new_(al(),n); From 2290375515d2083134c22da264303d2d3f3b8223 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 16:14:29 +0200 Subject: [PATCH 234/279] replaced try blocks with scope guards --- include/boost/unordered/detail/foa.hpp | 70 +++++++++----------------- 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d75d842b..0de4782c 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1147,21 +1147,15 @@ public: } else{ reserve(x.size()); - BOOST_TRY{ - /* This works because subsequent x.clear() does not depend on the - * elements' values. - */ + clear_on_exit c{x}; + (void)c; /* unused var warning */ - x.for_all_elements([this](value_type* p){ - unchecked_insert(type_policy::move(*p)); - }); - } - BOOST_CATCH(...){ - x.clear(); - BOOST_RETHROW - } - BOOST_CATCH_END - x.clear(); + /* This works because subsequent x.clear() does not depend on the + * elements' values. + */ + x.for_all_elements([this](value_type* p){ + unchecked_insert(type_policy::move(*p)); + }); } } @@ -1209,19 +1203,6 @@ public: static constexpr auto pocma= alloc_traits::propagate_on_container_move_assignment::value; - /* Avoid using nested lambdas with a `this` capture as it seems to trigger - * a bug in GCC: - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 - * - * Rather than directly attempting to manipulate the visibility of the - * table class, it's easier to work around the bug by simply un-nesting the - * lambda. - */ - - auto const move_element=[this](value_type* p){ - unchecked_insert(type_policy::move(*p)); - }; - if(this!=std::addressof(x)){ clear(); h()=std::move(x.h()); @@ -1234,28 +1215,19 @@ public: swap(arrays,x.arrays); swap(ml,x.ml); } - else if_constexpr([&,this]{ - /* The check above is redundant: we're setting up a compile-time - * barrier so that the compiler is convinced we're not throwing - * under noexcept(true) conditions. - */ - + else{ /* noshrink: favor memory reuse over tightness */ noshrink_reserve(x.size()); - BOOST_TRY{ - /* This works because subsequent x.clear() does not depend on the - * elements' values. - */ + clear_on_exit c{x}; + (void)c; /* unused var warning */ - x.for_all_elements(move_element); - } - BOOST_CATCH(...){ - x.clear(); - BOOST_RETHROW - } - BOOST_CATCH_END - x.clear(); - }); + /* This works because subsequent x.clear() does not depend on the + * elements' values. + */ + x.for_all_elements([this](value_type* p){ + unchecked_insert(type_policy::move(*p)); + }); + } } return *this; } @@ -1452,6 +1424,12 @@ private: template friend class table; using arrays_type=table_arrays; + struct clear_on_exit + { + ~clear_on_exit(){x.clear();} + table& x; + }; + Hash& h(){return hash_base::get();} const Hash& h()const{return hash_base::get();} Pred& pred(){return pred_base::get();} From c76f44a8b3c2d5e5e5fbf1f45dedb761f1040abf Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 16:18:05 +0200 Subject: [PATCH 235/279] hardened unchecked_rehash against exceptions thrown in the middle of value move construction --- include/boost/unordered/detail/foa.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 0de4782c..827c22c2 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1627,8 +1627,11 @@ private: std::size_t num_tx=0; BOOST_TRY{ for_all_elements([&,this](value_type* p){ - nosize_transfer_element(p,new_arrays_); + /* We increment num_tx *before* actual transfer to guard us against + * exceptions thrown in the middle of value move construction. + */ ++num_tx; + nosize_transfer_element(p,new_arrays_); }); } BOOST_CATCH(...){ From c9340390b00be65aad99447bf817592a28810987 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 17:28:57 +0200 Subject: [PATCH 236/279] completed previous commit --- include/boost/unordered/detail/foa.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 827c22c2..114f94c5 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1458,6 +1458,13 @@ private: alloc_traits::destroy(al(),p); } + struct destroy_on_exit + { + ~destroy_on_exit(){this_->destroy_element(p);} + table* this_; + value_type* p; + }; + std::size_t max_load()const { static constexpr std::size_t small_capacity=2*N-1; @@ -1688,9 +1695,10 @@ private: void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { auto hash=hash_for(key_from(*p)); + destroy_on_exit d{this,p}; + (void)d; /* ununsed var warning */ nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash,type_policy::move(*p)); - destroy_element(p); } template From 64cb43ce32923cf30547112aea8c6c721ca77c1c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 17:42:22 +0200 Subject: [PATCH 237/279] protected against hash throwing in nosize_transfer_element --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 114f94c5..d84a0736 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1694,9 +1694,9 @@ private: void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { - auto hash=hash_for(key_from(*p)); destroy_on_exit d{this,p}; (void)d; /* ununsed var warning */ + auto hash=hash_for(key_from(*p)); nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash,type_policy::move(*p)); } From d13a9dcaaf5c24314a3fad24c9633cdeb9b246f5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 18:35:41 +0200 Subject: [PATCH 238/279] stylistic --- include/boost/unordered/detail/foa.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d84a0736..7afee8f5 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1151,8 +1151,8 @@ public: (void)c; /* unused var warning */ /* This works because subsequent x.clear() does not depend on the - * elements' values. - */ + * elements' values. + */ x.for_all_elements([this](value_type* p){ unchecked_insert(type_policy::move(*p)); }); @@ -1631,25 +1631,22 @@ private: BOOST_NOINLINE void unchecked_rehash(std::size_t n) { auto new_arrays_=new_arrays(n); - std::size_t num_tx=0; + std::size_t num_destroyed=0; BOOST_TRY{ for_all_elements([&,this](value_type* p){ - /* We increment num_tx *before* actual transfer to guard us against - * exceptions thrown in the middle of value move construction. - */ - ++num_tx; + ++num_destroyed; /* p destroyed below even if an exception is thrown */ nosize_transfer_element(p,new_arrays_); }); } BOOST_CATCH(...){ - if(num_tx){ - size_-=num_tx; + if(num_destroyed){ + size_-=num_destroyed; for(auto pg=arrays.groups;;++pg){ auto mask=pg->match_occupied(); while(mask){ auto nz=unchecked_countr_zero(mask); pg->reset(nz); - if(!(--num_tx))goto continue_; + if(!(--num_destroyed))goto continue_; mask&=mask-1; } } @@ -1694,8 +1691,11 @@ private: void nosize_transfer_element(value_type* p,const arrays_type& arrays_) { + /* Destroy p always to guard us against an exception in the middle of value + * move construction, which could leave the source half-moved. + */ destroy_on_exit d{this,p}; - (void)d; /* ununsed var warning */ + (void)d; /* unused var warning */ auto hash=hash_for(key_from(*p)); nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash,type_policy::move(*p)); From 8e42367a6231193259b09fe79ab4191973b5211b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 18 Oct 2022 19:33:52 +0200 Subject: [PATCH 239/279] stylistic --- include/boost/unordered/detail/foa.hpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 7afee8f5..b513b4f7 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1138,12 +1138,9 @@ public: table{0,std::move(x.h()),std::move(x.pred()),al_} { if(al()==x.al()){ - size_=x.size_; - arrays=x.arrays; - ml=x.ml; - x.size_=0; - x.arrays=x.new_arrays(0); - x.ml=x.max_load(); + std::swap(size_,x.size_); + std::swap(arrays,x.arrays); + std::swap(ml,x.ml); } else{ reserve(x.size()); @@ -1461,8 +1458,8 @@ private: struct destroy_on_exit { ~destroy_on_exit(){this_->destroy_element(p);} - table* this_; - value_type* p; + table *this_; + value_type *p; }; std::size_t max_load()const From 46065065be9a76097f0ae192c2a0dcc6681909f7 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 18 Oct 2022 15:51:53 -0700 Subject: [PATCH 240/279] Temporarily disable strong checks for FOA --- test/helpers/strong.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/helpers/strong.hpp b/test/helpers/strong.hpp index 3c936133..26dd2ce3 100644 --- a/test/helpers/strong.hpp +++ b/test/helpers/strong.hpp @@ -30,11 +30,15 @@ namespace test { void test(X const& x, unsigned int allocations = 0) const { + (void) x; + (void) allocations; +#ifndef BOOST_UNORDERED_FOA_TESTS if (!(x.size() == values_.size() && test::equal(x.cbegin(), x.cend(), values_.begin(), test::equivalent))) BOOST_ERROR("Strong exception safety failure."); if (allocations != allocations_) BOOST_ERROR("Strong exception failure: extra allocations."); +#endif } }; } From 4de1be89112260f96864398e3384144a081cc32f Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 18 Oct 2022 15:53:40 -0700 Subject: [PATCH 241/279] Add the rest of the exception tests sans swap --- test/Jamfile.v2 | 6 ++ test/exception/insert_exception_tests.cpp | 76 +++++++++++++++++++++-- test/exception/merge_exception_tests.cpp | 52 ++++++++++++++-- 3 files changed, 126 insertions(+), 8 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 58204e16..fa593e24 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -136,3 +136,9 @@ build_foa scary_tests ; run exception/constructor_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ; run exception/copy_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ; +run exception/assign_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_assign_exception_tests ; +run exception/move_assign_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_move_assign_exception_tests ; +run exception/insert_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_insert_exception_tests ; +run exception/erase_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_erase_exception_tests ; +run exception/rehash_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_rehash_exception_tests ; +run exception/merge_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_merge_exception_tests ; diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 0f98e0c4..eee11183 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -221,16 +221,41 @@ struct emplace_lvalue_pos_type } emplace_lvalue_pos; // Run the exception tests in various combinations. +using test::default_generator; +using test::limited_range; +using test::generate_collisions; +#ifdef BOOST_UNORDERED_FOA_TESTS +test_set* test_set_; +test_map* test_map_; + +// clang-format off +UNORDERED_TEST(insert_exception_test, + ((test_set_)(test_map_)) + ((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end) + (insert_lvalue_pos)(insert_single_item_range) + (emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end) + (emplace_lvalue_pos) + ) + ((default_generator)(limited_range)(generate_collisions)) +) + +UNORDERED_TEST(insert_rehash_exception_test, + ((test_set_)(test_map_)) + ((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end) + (insert_lvalue_pos)(insert_single_item_range) + (emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end) + (emplace_lvalue_pos) + ) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on +#else test_set* test_set_; test_multiset* test_multiset_; test_map* test_map_; test_multimap* test_multimap_; -using test::default_generator; -using test::limited_range; -using test::generate_collisions; - // clang-format off UNORDERED_TEST(insert_exception_test, ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) @@ -252,6 +277,7 @@ UNORDERED_TEST(insert_rehash_exception_test, ((default_generator)(limited_range)(generate_collisions)) ) // clang-format on +#endif // Repeat insert tests with pairs @@ -259,8 +285,13 @@ struct pair_emplace_type : inserter_base { template void operator()(T& x, Iterator it) { +#ifdef BOOST_UNORDERED_FOA_TESTS + x.emplace(std::piecewise_construct, std::make_tuple(it->first), + std::make_tuple(it->second)); +#else x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(it->first), boost::make_tuple(it->second)); +#endif } } pair_emplace; @@ -268,12 +299,34 @@ struct pair_emplace2_type : inserter_base { template void operator()(T& x, Iterator it) { +#ifdef BOOST_UNORDERED_FOA_TESTS + x.emplace_hint(x.begin(), std::piecewise_construct, + std::make_tuple(it->first), + std::make_tuple(it->second.tag1_, it->second.tag2_)); +#else x.emplace_hint(x.begin(), boost::unordered::piecewise_construct, boost::make_tuple(it->first), boost::make_tuple(it->second.tag1_, it->second.tag2_)); +#endif } } pair_emplace2; +#ifdef BOOST_UNORDERED_FOA_TESTS +test_pair_set* test_pair_set_; + +// clang-format off +UNORDERED_TEST(insert_exception_test, + ((test_pair_set_)(test_map_)) + ((pair_emplace)(pair_emplace2)) + ((default_generator)(limited_range)(generate_collisions)) +) +UNORDERED_TEST(insert_rehash_exception_test, + ((test_pair_set_)(test_map_)) + ((pair_emplace)(pair_emplace2)) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on +#else test_pair_set* test_pair_set_; test_pair_multiset* test_pair_multiset_; @@ -289,6 +342,7 @@ UNORDERED_TEST(insert_rehash_exception_test, ((default_generator)(limited_range)(generate_collisions)) ) // clang-format on +#endif // Test inserting using operator[] @@ -401,6 +455,19 @@ void insert_range_rehash_exception_test(T*, test::random_generator gen) } } +#ifdef BOOST_UNORDERED_FOA_TESTS +// clang-format off +UNORDERED_TEST(insert_range_exception_test, + ((test_set_)(test_map_)) + ((default_generator)(limited_range)(generate_collisions)) +) + +UNORDERED_TEST(insert_range_rehash_exception_test, + ((test_set_)(test_map_)) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on +#else // clang-format off UNORDERED_TEST(insert_range_exception_test, ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) @@ -412,5 +479,6 @@ UNORDERED_TEST(insert_range_rehash_exception_test, ((default_generator)(limited_range)(generate_collisions)) ) // clang-format on +#endif RUN_TESTS() diff --git a/test/exception/merge_exception_tests.cpp b/test/exception/merge_exception_tests.cpp index 2cf7faf4..a6a7afc7 100644 --- a/test/exception/merge_exception_tests.cpp +++ b/test/exception/merge_exception_tests.cpp @@ -52,6 +52,53 @@ void merge_exception_test(T1 const*, T2 const*, std::size_t count12, int tag12, EXCEPTION_LOOP(merge_exception_test(x, y)) } +using test::default_generator; +using test::generate_collisions; +using test::limited_range; + +#ifdef BOOST_UNORDERED_FOA_TESTS +boost::unordered_flat_set >* test_set_; +boost::unordered_flat_map >* test_map_; + +// clang-format off +UNORDERED_MULTI_TEST(set_merge, merge_exception_test, + ((test_set_)) + ((test_set_)) + ((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232)) + ((0x0000)(0x0001)(0x0102)) + ((default_generator)(limited_range)) + ((default_generator)(limited_range)) +) +UNORDERED_MULTI_TEST(map_merge, merge_exception_test, + ((test_map_)) + ((test_map_)) + ((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232)) + ((0x0101)(0x0200)(0x0201)) + ((default_generator)(limited_range)) + ((default_generator)(limited_range)) +) +// Run fewer generate_collisions tests, as they're slow. +UNORDERED_MULTI_TEST(set_merge_collisions, merge_exception_test, + ((test_set_)) + ((test_set_)) + ((0x0a0a)) + ((0x0202)(0x0100)(0x0201)) + ((generate_collisions)) + ((generate_collisions)) +) +UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test, + ((test_map_)) + ((test_map_)) + ((0x0a0a)) + ((0x0000)(0x0002)(0x0102)) + ((generate_collisions)) + ((generate_collisions)) +) +#else boost::unordered_set >* test_set_; @@ -65,10 +112,6 @@ boost::unordered_multimap >* test_multimap_; -using test::default_generator; -using test::generate_collisions; -using test::limited_range; - // clang-format off UNORDERED_MULTI_TEST(set_merge, merge_exception_test, ((test_set_)(test_multiset_)) @@ -104,5 +147,6 @@ UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test, ((generate_collisions)) ) // clang-format on +#endif RUN_TESTS_QUIET() From 8a1562cc7819925422d82dc5bc0c14b86b100fcc Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 19 Oct 2022 15:46:57 +0200 Subject: [PATCH 242/279] implemented strong exception guarantee on rehash and single insert/emplace --- include/boost/unordered/detail/foa.hpp | 87 +++++++++++++++++++------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index b513b4f7..487c8375 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1455,9 +1455,9 @@ private: alloc_traits::destroy(al(),p); } - struct destroy_on_exit + struct destroy_element_on_exit { - ~destroy_on_exit(){this_->destroy_element(p);} + ~destroy_element_on_exit(){this_->destroy_element(p);} table *this_; value_type *p; }; @@ -1609,15 +1609,32 @@ private: if(it!=end()){ return {it,false}; } - else if(BOOST_UNLIKELY(size_>=ml)){ - unchecked_rehash( - std::size_t(std::ceil(static_cast(size_+1)/mlf))); - pos0=position_for(hash); + if(BOOST_LIKELY(size_(args)...), + true + }; + } + else{ + /* strong exception guarantee -> try insertion before rehash */ + auto new_arrays_=new_arrays( + std::size_t(std::ceil(static_cast(size_+1)/mlf))); + BOOST_TRY{ + it=nosize_unchecked_emplace_at( + new_arrays_,position_for(hash,new_arrays_), + hash,std::forward(args)...); + } + BOOST_CATCH(...){ + delete_arrays(new_arrays_); + BOOST_RETHROW + } + BOOST_CATCH_END + + /* new_arrays_ lifetime taken care of by unchecked_rehash */ + unchecked_rehash(new_arrays_); + ++size_; + return {it,true}; } - return { - unchecked_emplace_at(pos0,hash,std::forward(args)...), - true - }; } static std::size_t capacity_for(std::size_t n) @@ -1627,12 +1644,16 @@ private: BOOST_NOINLINE void unchecked_rehash(std::size_t n) { - auto new_arrays_=new_arrays(n); + auto new_arrays_=new_arrays(n); + unchecked_rehash(new_arrays_); + } + + BOOST_NOINLINE void unchecked_rehash(arrays_type& new_arrays_) + { std::size_t num_destroyed=0; BOOST_TRY{ for_all_elements([&,this](value_type* p){ - ++num_destroyed; /* p destroyed below even if an exception is thrown */ - nosize_transfer_element(p,new_arrays_); + nosize_transfer_element(p,new_arrays_,num_destroyed); }); } BOOST_CATCH(...){ @@ -1647,11 +1668,11 @@ private: mask&=mask-1; } } - continue_: - for_all_elements(new_arrays_,[this](value_type* p){ - destroy_element(p); - }); } + continue_: + for_all_elements(new_arrays_,[this](value_type* p){ + destroy_element(p); + }); delete_arrays(new_arrays_); BOOST_RETHROW } @@ -1686,18 +1707,40 @@ private: unchecked_emplace_at(position_for(hash),hash,std::forward(x)); } - void nosize_transfer_element(value_type* p,const arrays_type& arrays_) + void nosize_transfer_element( + value_type* p,const arrays_type& arrays_,std::size_t& num_destroyed) { - /* Destroy p always to guard us against an exception in the middle of value - * move construction, which could leave the source half-moved. + nosize_transfer_element( + p,hash_for(key_from(*p)),arrays_,num_destroyed, + std::integral_constant< /* std::move_if_noexcept semantics */ + bool, + std::is_nothrow_move_constructible::value|| + !std::is_copy_constructible::value>{}); + } + + void nosize_transfer_element( + value_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 + * construction, which could leave the source half-moved. */ - destroy_on_exit d{this,p}; + ++num_destroyed; + destroy_element_on_exit d{this,p}; (void)d; /* unused var warning */ - auto hash=hash_for(key_from(*p)); nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash,type_policy::move(*p)); } + void nosize_transfer_element( + value_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)); + } + template iterator unchecked_emplace_at( std::size_t pos0,std::size_t hash,Args&&... args) From f3353c9be3f019951c6727252db6a13a67000471 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 19 Oct 2022 17:42:59 +0200 Subject: [PATCH 243/279] made sure source values are destroyed on copy-based rehash --- include/boost/unordered/detail/foa.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 487c8375..6c9e8f69 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1677,6 +1677,14 @@ private: BOOST_RETHROW } BOOST_CATCH_END + + /* either all moved and destroyed or all copied */ + BOOST_ASSERT(num_destroyed=size()||num_destroyed==0); + if(num_destroyed!=size()){ + for_all_elements([this](value_type* p){ + destroy_element(p); + }); + } delete_arrays(arrays); arrays=new_arrays_; ml=max_load(); @@ -1720,7 +1728,7 @@ private: void nosize_transfer_element( value_type* p,std::size_t hash,const arrays_type& arrays_, - std::size_t& num_destroyed,std::true_type /* move */) + std::size_t& num_destroyed,std::true_type /* ->move */) { /* Destroy p even if an an exception is thrown in the middle of move * construction, which could leave the source half-moved. @@ -1734,7 +1742,7 @@ private: void nosize_transfer_element( value_type* p,std::size_t hash,const arrays_type& arrays_, - std::size_t& /*num_destroyed*/,std::false_type /* copy */) + std::size_t& /*num_destroyed*/,std::false_type /* ->copy */) { nosize_unchecked_emplace_at( arrays_,position_for(hash,arrays_),hash, From 2f048ea6aca3b94de9e4711d81925927c79f5606 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 19 Oct 2022 17:50:21 +0200 Subject: [PATCH 244/279] s/=/== --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 6c9e8f69..9dae609f 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1679,7 +1679,7 @@ private: BOOST_CATCH_END /* either all moved and destroyed or all copied */ - BOOST_ASSERT(num_destroyed=size()||num_destroyed==0); + BOOST_ASSERT(num_destroyed==size()||num_destroyed==0); if(num_destroyed!=size()){ for_all_elements([this](value_type* p){ destroy_element(p); From 776935f24dde283f278db6f4288a332f96905951 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 19 Oct 2022 11:04:38 -0700 Subject: [PATCH 245/279] Reintroduce strong guarantee checking --- test/helpers/strong.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/helpers/strong.hpp b/test/helpers/strong.hpp index 26dd2ce3..3c936133 100644 --- a/test/helpers/strong.hpp +++ b/test/helpers/strong.hpp @@ -30,15 +30,11 @@ namespace test { void test(X const& x, unsigned int allocations = 0) const { - (void) x; - (void) allocations; -#ifndef BOOST_UNORDERED_FOA_TESTS if (!(x.size() == values_.size() && test::equal(x.cbegin(), x.cend(), values_.begin(), test::equivalent))) BOOST_ERROR("Strong exception safety failure."); if (allocations != allocations_) BOOST_ERROR("Strong exception failure: extra allocations."); -#endif } }; } From 0ac4aeca507a207512ac9c11d378158cb0208ae7 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 19 Oct 2022 11:05:09 -0700 Subject: [PATCH 246/279] Add swap_exception_tests for FOA, only testing weak exception guarantee --- test/Jamfile.v2 | 1 + test/exception/swap_exception_tests.cpp | 4 ++++ test/helpers/invariants.hpp | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index fa593e24..4d9b4a8e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -141,4 +141,5 @@ run exception/move_assign_exception_tests.cpp : : : 98:no 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_insert_exception_tests ; run exception/erase_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_erase_exception_tests ; run exception/rehash_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_rehash_exception_tests ; +run exception/swap_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_swap_exception_tests ; run exception/merge_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_merge_exception_tests ; diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 1569e814..2745ede5 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -5,6 +5,10 @@ #include "./containers.hpp" +#if defined(BOOST_UNORDERED_FOA_TESTS) +#define BOOST_UNORDERED_FOA_WEAK_GUARANTEE_SWAP_EXCEPTIONS_TESTS +#endif + #include "../helpers/invariants.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index 3a4ddedf..849fe983 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -53,10 +53,20 @@ namespace test { if (test::has_unique_keys::value && count != 1) BOOST_ERROR("Non-unique key."); +#if !defined(BOOST_UNORDERED_FOA_WEAK_GUARANTEE_SWAP_EXCEPTIONS_TESTS) + // we conditionally compile this check because our FOA implementation only + // exhibits the weak guarantee when swapping throws + // + // in this case, the hasher may be changed before the predicate and the + // arrays are swapped in which case, we can can find an element by + // iteration but unfortunately, it's in the wrong slot according to the + // new hash function so count(key) can wind up returning nothing when + // there really is something if (x1.count(key) != count) { BOOST_ERROR("Incorrect output of count."); std::cerr << x1.count(key) << "," << count << "\n"; } +#endif #ifndef BOOST_UNORDERED_FOA_TESTS // Check that the keys are in the correct bucket and are From c1d5902911425f5760dfc7d211c6e738b5c26b6f Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 20 Oct 2022 08:43:42 -0700 Subject: [PATCH 247/279] Remove unnecessary value_type conversion by expanding overloads for value_from() --- include/boost/unordered/detail/foa.hpp | 19 ++++++++++++++++++- .../boost/unordered/unordered_flat_map.hpp | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 9dae609f..3a224714 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1499,13 +1499,30 @@ private: template< typename T, - typename std::enable_if::value>::type* =nullptr + typename Ty=typename std::decay::type, + typename std::enable_if< + !is_init_or_value_type::value&& + std::is_convertible::value + >::type* =nullptr > static inline init_type value_from(T&& x) { return std::forward(x); } + template< + typename T, + typename Ty=typename std::decay::type, + typename std::enable_if< + !is_init_or_value_type::value&& + !std::is_convertible::value + >::type* =nullptr + > + static inline value_type value_from(T&& x) + { + return std::forward(x); + } + template static inline auto key_from(const T& x) ->decltype(type_policy::extract(x)) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index ea90c7e6..bcaa8dce 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -239,7 +239,7 @@ namespace boost { void insert(InputIterator first, InputIterator last) { for (auto pos = first; pos != last; ++pos) { - table_.insert(value_type(*pos)); + table_.insert(*pos); } } From d93875a65e56bf3a3f3642a470116d222c84bcb8 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Thu, 20 Oct 2022 19:48:17 +0200 Subject: [PATCH 248/279] refactored value_from and insert overloads --- include/boost/unordered/detail/foa.hpp | 94 +++++++++++--------------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3a224714..903d3c78 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1084,6 +1084,43 @@ private: static constexpr bool has_mutable_iterator= !std::is_same::value; + template< + typename T, + typename RawT=typename std::remove_cv< + typename std::remove_reference::type>::type + > + using value_from_return_type=typename std::conditional< + std::is_same::value||std::is_same::value, + T, + typename std::conditional< + std::is_convertible::value, + const init_type, + typename std::conditional< + std::is_convertible::value, + const value_type, + typename std::conditional< + std::is_convertible::value, + const init_type&, + typename std::conditional< + std::is_convertible::value, + const value_type&, + void + >::type + >::type + >::type + >::type + >::type; + + template< + typename T, + typename std::enable_if< + !std::is_void>::value>::type* =nullptr + > + static inline value_from_return_type value_from(T&& x) + { + return std::forward(x); + } + public: using hasher=Hash; using key_equal=Pred; @@ -1269,12 +1306,9 @@ public: std::forward_as_tuple(std::forward(args)...)); } - template< - typename T, - typename std::enable_if< - std::is_constructible::value>* =nullptr - > - BOOST_FORCEINLINE std::pair insert(T&& x) + template + BOOST_FORCEINLINE auto insert(T&& x) + ->decltype(value_from(std::forward(x)),std::pair()) { return emplace_impl(value_from(std::forward(x))); } @@ -1475,54 +1509,6 @@ private: } } - template - using is_init_or_value_type=std::integral_constant< - bool, - std::is_same< - init_type, - typename std::remove_cv::type>::type - >::value|| - std::is_same< - value_type, - typename std::remove_cv::type>::type - >::value - >; - - template< - typename T, - typename std::enable_if::value>::type* =nullptr - > - static inline T&& value_from(T&& x) - { - return std::forward(x); - } - - template< - typename T, - typename Ty=typename std::decay::type, - typename std::enable_if< - !is_init_or_value_type::value&& - std::is_convertible::value - >::type* =nullptr - > - static inline init_type value_from(T&& x) - { - return std::forward(x); - } - - template< - typename T, - typename Ty=typename std::decay::type, - typename std::enable_if< - !is_init_or_value_type::value&& - !std::is_convertible::value - >::type* =nullptr - > - static inline value_type value_from(T&& x) - { - return std::forward(x); - } - template static inline auto key_from(const T& x) ->decltype(type_policy::extract(x)) From 99ad45ed77912fad822bf455ce289f029d4f17d5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Thu, 20 Oct 2022 20:02:55 +0200 Subject: [PATCH 249/279] removed spurious consts --- include/boost/unordered/detail/foa.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 903d3c78..3e0399b1 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1094,10 +1094,10 @@ private: T, typename std::conditional< std::is_convertible::value, - const init_type, + init_type, typename std::conditional< std::is_convertible::value, - const value_type, + value_type, typename std::conditional< std::is_convertible::value, const init_type&, From 59f4da0a47d237201ee5c65f79cbba9806a3f1c8 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 20 Oct 2022 14:58:38 -0700 Subject: [PATCH 250/279] Add init_type public typedefs --- include/boost/unordered/unordered_flat_map.hpp | 1 + include/boost/unordered/unordered_flat_set.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index bcaa8dce..b1b2528a 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -67,6 +67,7 @@ namespace boost { using key_type = Key; using mapped_type = T; using value_type = typename map_types::value_type; + using init_type = typename map_types::init_type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using hasher = Hash; diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index fde8605c..fae770ee 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -49,6 +49,7 @@ namespace boost { public: using key_type = Key; using value_type = typename set_types::value_type; + using init_type = typename set_types::init_type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using hasher = Hash; From fe32f153a2b4a40a852a71ae6091803978f24c1a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 20 Oct 2022 14:59:33 -0700 Subject: [PATCH 251/279] Add draft of insert(init_type&&) for unordered_flat_map --- .../boost/unordered/unordered_flat_map.hpp | 8 +- test/Jamfile.v2 | 1 + test/unordered/init_type_insert_tests.cpp | 165 ++++++++++++++++++ 3 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 test/unordered/init_type_insert_tests.cpp diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index b1b2528a..77431650 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -216,12 +216,14 @@ namespace boost { void clear() noexcept { table_.clear(); } - std::pair insert(value_type const& value) + template + auto insert(Ty&& value) + -> decltype(table_.insert(std::forward(value))) { - return table_.insert(value); + return table_.insert(std::forward(value)); } - std::pair insert(value_type&& value) + std::pair insert(init_type&& value) { return table_.insert(std::move(value)); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4d9b4a8e..2c27334b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -133,6 +133,7 @@ build_foa reserve_tests ; build_foa contains_tests ; build_foa erase_if ; build_foa scary_tests ; +build_foa init_type_insert_tests ; run exception/constructor_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ; run exception/copy_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ; diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp new file mode 100644 index 00000000..3bdeb78e --- /dev/null +++ b/test/unordered/init_type_insert_tests.cpp @@ -0,0 +1,165 @@ +#if !defined(BOOST_UNORDERED_FOA_TESTS) +#error "This test is only for the FOA-style conatiners" +#endif + +#include +#include + +#include "../helpers/test.hpp" + +struct move_only +{ + int x_ = -1; + + move_only() = default; + move_only(int x) : x_{x} {} + move_only(move_only const&) = delete; + move_only(move_only&&) = default; + + friend bool operator==(move_only const& lhs, move_only const& rhs) + { + return lhs.x_ == rhs.x_; + } +}; + +template <> struct std::hash +{ + std::size_t operator()(move_only const& mo) const noexcept + { + return std::hash()(mo.x_); + } +}; + +struct raii_tracker +{ + static int move_constructs; + static int copy_constructs; + + int x_ = -1; + + static void reset_counts() + { + move_constructs = 0; + copy_constructs = 0; + } + + raii_tracker() {} + raii_tracker(int x) : x_{x} {} + raii_tracker(raii_tracker const& rhs) : x_{rhs.x_} { ++copy_constructs; } + + raii_tracker(raii_tracker&& rhs) noexcept : x_{rhs.x_} + { + rhs.x_ = -1; + + ++move_constructs; + } + + friend bool operator==(raii_tracker const& lhs, raii_tracker const& rhs) + { + return lhs.x_ == rhs.x_; + } +}; + +template <> struct std::hash +{ + std::size_t operator()(raii_tracker const& rt) const noexcept + { + return std::hash()(rt.x_); + } +}; + +int raii_tracker::move_constructs = 0; +int raii_tracker::copy_constructs = 0; + +static void test_move_only() +{ + int const v = 128; + + boost::unordered_flat_map > map; + + using init_type = decltype(map)::init_type; + static_assert( + std::is_same::value, + ""); + + map.insert(std::make_pair(move_only(1), v)); + map.insert({move_only(2), v}); + + BOOST_TEST_EQ(map.size(), 2); + + map.rehash(1024); + BOOST_TEST_GE(map.bucket_count(), 1024); +} + +static void test_insert_tracking() +{ + raii_tracker::reset_counts(); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 0); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0); + + boost::unordered_flat_map > + map; + + { + std::pair value{1, 2}; + + map.insert(value); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0); + } + + { + std::pair value{2, 3}; + + map.insert(std::move(value)); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2); + } + + { + std::pair value{3, 4}; + + map.insert(value); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 4); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2); + } + + { + std::pair value{4, 5}; + + map.insert(std::move(value)); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 3); + } + + { + map.insert(std::make_pair(5, 6)); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 5); + } + + { + map.insert({6, 7}); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7); + } + + BOOST_TEST_EQ(map.size(), 6); + + map.rehash(1024); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7 + 2 * map.size()); +} + +int main() +{ + test_move_only(); + test_insert_tracking(); + return boost::report_errors(); +} From 703f8d106585bd72f3cfa32d050b8494494c8891 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 20 Oct 2022 15:25:40 -0700 Subject: [PATCH 252/279] Delete boost-level headers as they're no longer considered idiomatic and update all tests to use the test/helpers/unorderd.hpp header where applicable --- include/boost/unordered_flat_map.hpp | 18 ------------------ include/boost/unordered_flat_set.hpp | 18 ------------------ test/helpers/unordered.hpp | 4 ++-- test/unordered/assign_tests.cpp | 12 +----------- test/unordered/at_tests.cpp | 11 +---------- test/unordered/compile_map.cpp | 11 +---------- test/unordered/compile_set.cpp | 11 +---------- test/unordered/constructor_tests.cpp | 12 +----------- test/unordered/contains_tests.cpp | 13 +------------ test/unordered/copy_tests.cpp | 10 +--------- test/unordered/emplace_tests.cpp | 13 +------------ test/unordered/equality_tests.cpp | 13 +------------ test/unordered/equivalent_keys_tests.cpp | 13 +------------ test/unordered/erase_if.cpp | 13 +------------ test/unordered/erase_tests.cpp | 12 +----------- test/unordered/find_tests.cpp | 12 +----------- test/unordered/fwd_set_test.cpp | 2 +- test/unordered/incomplete_test.cpp | 13 +------------ test/unordered/init_type_insert_tests.cpp | 3 +-- test/unordered/insert_hint_tests.cpp | 13 +------------ test/unordered/insert_tests.cpp | 12 +----------- test/unordered/link_test_1.cpp | 13 +------------ test/unordered/link_test_2.cpp | 13 +------------ test/unordered/load_factor_tests.cpp | 13 +------------ test/unordered/merge_tests.cpp | 11 +---------- test/unordered/move_tests.cpp | 12 +----------- test/unordered/noexcept_tests.cpp | 13 +------------ test/unordered/rehash_tests.cpp | 12 +----------- test/unordered/reserve_tests.cpp | 13 +------------ test/unordered/scoped_allocator.cpp | 13 +------------ test/unordered/simple_tests.cpp | 13 +------------ test/unordered/swap_tests.cpp | 13 +------------ test/unordered/transparent_tests.cpp | 13 +------------ 33 files changed, 32 insertions(+), 359 deletions(-) delete mode 100644 include/boost/unordered_flat_map.hpp delete mode 100644 include/boost/unordered_flat_set.hpp diff --git a/include/boost/unordered_flat_map.hpp b/include/boost/unordered_flat_map.hpp deleted file mode 100644 index bed3bc05..00000000 --- a/include/boost/unordered_flat_map.hpp +++ /dev/null @@ -1,18 +0,0 @@ - -// Copyright (C) 2022 Christian Mazakas -// 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) - -// See http://www.boost.org/libs/unordered for documentation - -#ifndef BOOST_UNORDERED_FLAT_MAP_HPP_INCLUDED -#define BOOST_UNORDERED_FLAT_MAP_HPP_INCLUDED - -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include - -#endif // BOOST_UNORDERED_FLAT_MAP_HPP_INCLUDED \ No newline at end of file diff --git a/include/boost/unordered_flat_set.hpp b/include/boost/unordered_flat_set.hpp deleted file mode 100644 index 6e2067f8..00000000 --- a/include/boost/unordered_flat_set.hpp +++ /dev/null @@ -1,18 +0,0 @@ - -// Copyright (C) 2022 Christian Mazakas -// 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) - -// See http://www.boost.org/libs/unordered for documentation - -#ifndef BOOST_UNORDERED_FLAT_SET_HPP_INCLUDED -#define BOOST_UNORDERED_FLAT_SET_HPP_INCLUDED - -#include -#if defined(BOOST_HAS_PRAGMA_ONCE) -#pragma once -#endif - -#include - -#endif // BOOST_UNORDERED_FLAT_SET_HPP_INCLUDED \ No newline at end of file diff --git a/test/helpers/unordered.hpp b/test/helpers/unordered.hpp index 289e79b7..5a2361ea 100644 --- a/test/helpers/unordered.hpp +++ b/test/helpers/unordered.hpp @@ -9,8 +9,8 @@ // clang-format off #include "prefix.hpp" #ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include +#include +#include #include #else #include diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index e38f6e87..b937c57e 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -3,17 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index 921bb8ee..bc5ad921 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -3,16 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 272f7de5..f43476c0 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -6,16 +6,7 @@ // This test creates the containers with members that meet their minimum // requirements. Makes sure everything compiles and is defined correctly. -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/minimal.hpp" diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index dfd40d53..d51bc11e 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -6,16 +6,7 @@ // This test creates the containers with members that meet their minimum // requirements. Makes sure everything compiles and is defined correctly. -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/minimal.hpp" diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 2b9d3d17..b68a7eb5 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -4,17 +4,7 @@ // 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) -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -// clang-format off -#include "../helpers/prefix.hpp" -#include -#include -#include "../helpers/postfix.hpp" -// clang-format on -#endif +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/contains_tests.cpp b/test/unordered/contains_tests.cpp index 39302e17..782e1915 100644 --- a/test/unordered/contains_tests.cpp +++ b/test/unordered/contains_tests.cpp @@ -2,18 +2,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index f8be49b7..05c0f97a 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -4,15 +4,7 @@ // 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) -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/emplace_tests.cpp b/test/unordered/emplace_tests.cpp index ad1245d3..bf79e2c2 100644 --- a/test/unordered/emplace_tests.cpp +++ b/test/unordered/emplace_tests.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include #include "../helpers/test.hpp" diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index c1f0f561..68e021ca 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include #include diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index fe365b66..0a67b768 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include diff --git a/test/unordered/erase_if.cpp b/test/unordered/erase_if.cpp index cc4bcd5c..6033b752 100644 --- a/test/unordered/erase_if.cpp +++ b/test/unordered/erase_if.cpp @@ -2,18 +2,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index e79d83e9..ff02856a 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -3,17 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index f33e9a5e..50dfd79e 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -4,17 +4,7 @@ // 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) -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -// clang-format off -#include "../helpers/prefix.hpp" -#include -#include -#include "../helpers/postfix.hpp" -// clang-format on -#endif +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 58de82d5..ecaaa3b1 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -109,7 +109,7 @@ UNORDERED_AUTO_TEST (use_fwd_declared_trait_without_definition) { } #ifdef BOOST_UNORDERED_FOA_TESTS -#include +#include #else #include #endif diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 76e8c7f5..63058f03 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp index 3bdeb78e..2de991fb 100644 --- a/test/unordered/init_type_insert_tests.cpp +++ b/test/unordered/init_type_insert_tests.cpp @@ -2,8 +2,7 @@ #error "This test is only for the FOA-style conatiners" #endif -#include -#include +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" diff --git a/test/unordered/insert_hint_tests.cpp b/test/unordered/insert_hint_tests.cpp index c3a51c7e..17cfd7ff 100644 --- a/test/unordered/insert_hint_tests.cpp +++ b/test/unordered/insert_hint_tests.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../helpers/invariants.hpp" diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index e60be128..b37b20ca 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -6,17 +6,7 @@ #if !defined(PIECEWISE_TEST_NAME) -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -// clang-format off -#include "../helpers/prefix.hpp" -#include -#include -#include "../helpers/postfix.hpp" -// clang-format on -#endif +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/link_test_1.cpp b/test/unordered/link_test_1.cpp index 2e9b3631..1d1daae7 100644 --- a/test/unordered/link_test_1.cpp +++ b/test/unordered/link_test_1.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #ifdef BOOST_UNORDERED_FOA_TESTS void foo(boost::unordered_flat_set&, boost::unordered_flat_map&); diff --git a/test/unordered/link_test_2.cpp b/test/unordered/link_test_2.cpp index fb42ba0d..fdeb529d 100644 --- a/test/unordered/link_test_2.cpp +++ b/test/unordered/link_test_2.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #ifdef BOOST_UNORDERED_FOA_TESTS void foo( diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index bee0b1e0..26a12e36 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 1d169373..2f1f4302 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -3,16 +3,7 @@ // 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) -#include "../helpers/postfix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/prefix.hpp" +#include "../helpers/unordered.hpp" #include "../helpers/count.hpp" #include "../helpers/helpers.hpp" diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 31b78f81..9e899c19 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -3,17 +3,7 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index 26a189f6..d4bed53f 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../helpers/fwd.hpp" diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 6258e08c..fb122c03 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -3,17 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../helpers/random_values.hpp" diff --git a/test/unordered/reserve_tests.cpp b/test/unordered/reserve_tests.cpp index a67bd39f..ca7f9809 100644 --- a/test/unordered/reserve_tests.cpp +++ b/test/unordered/reserve_tests.cpp @@ -2,18 +2,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" diff --git a/test/unordered/scoped_allocator.cpp b/test/unordered/scoped_allocator.cpp index cde1f96e..f554deff 100644 --- a/test/unordered/scoped_allocator.cpp +++ b/test/unordered/scoped_allocator.cpp @@ -19,18 +19,7 @@ int main() {} // https://github.com/boostorg/unordered/issues/22 // -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index 7c00fdc8..e22f6db6 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -5,18 +5,7 @@ // This test checks the runtime requirements of containers. -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index ed7feade..cee0a42f 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -3,18 +3,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include #include diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 9d230a18..9852fa84 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -2,18 +2,7 @@ // 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) -// clang-format off -#include "../helpers/prefix.hpp" -#ifdef BOOST_UNORDERED_FOA_TESTS -#include -#include -#include -#else -#include -#include -#endif -#include "../helpers/postfix.hpp" -// clang-format on +#include "../helpers/unordered.hpp" #include "../helpers/test.hpp" From 1d553447a00e4bf5408dbddabf6358100e013b2c Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 21 Oct 2022 10:01:51 +0200 Subject: [PATCH 253/279] refactored insert overloads --- include/boost/unordered/detail/foa.hpp | 61 ++++++-------------------- 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 3e0399b1..8342e57c 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1084,43 +1084,6 @@ private: static constexpr bool has_mutable_iterator= !std::is_same::value; - template< - typename T, - typename RawT=typename std::remove_cv< - typename std::remove_reference::type>::type - > - using value_from_return_type=typename std::conditional< - std::is_same::value||std::is_same::value, - T, - typename std::conditional< - std::is_convertible::value, - init_type, - typename std::conditional< - std::is_convertible::value, - value_type, - typename std::conditional< - std::is_convertible::value, - const init_type&, - typename std::conditional< - std::is_convertible::value, - const value_type&, - void - >::type - >::type - >::type - >::type - >::type; - - template< - typename T, - typename std::enable_if< - !std::is_void>::value>::type* =nullptr - > - static inline value_from_return_type value_from(T&& x) - { - return std::forward(x); - } - public: using hasher=Hash; using key_equal=Pred; @@ -1306,17 +1269,21 @@ public: std::forward_as_tuple(std::forward(args)...)); } - template - BOOST_FORCEINLINE auto insert(T&& x) - ->decltype(value_from(std::forward(x)),std::pair()) - { - return emplace_impl(value_from(std::forward(x))); - } + BOOST_FORCEINLINE std::pair + insert(const init_type& x){return emplace_impl(x);} - BOOST_FORCEINLINE std::pair insert(init_type&& x) - { - return emplace_impl(std::move(x)); - } + BOOST_FORCEINLINE std::pair + insert(init_type&& x){return emplace_impl(std::move(x));} + + /* template tilts call ambiguities in favor of init_type */ + + template + BOOST_FORCEINLINE std::pair + insert(const value_type& x){return emplace_impl(x);} + + template + BOOST_FORCEINLINE std::pair + insert(value_type&& x){return emplace_impl(std::move(x));} template< bool dependent_value=false, From c9d1b6009e446b80120c19787b418dae686ab2a8 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 21 Oct 2022 10:02:49 +0200 Subject: [PATCH 254/279] stylistic --- include/boost/unordered/detail/foa.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 8342e57c..f2520871 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -146,7 +146,7 @@ struct group15 inline void set(std::size_t pos,std::size_t hash) { BOOST_ASSERT(pos Date: Fri, 21 Oct 2022 10:46:22 +0200 Subject: [PATCH 255/279] stylistic --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f2520871..9537e9a3 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -892,7 +892,7 @@ struct table_arrays reinterpret_cast(p))%sizeof(group_type); arrays.groups=reinterpret_cast(p); - /* memset is faster/not slower than using group_type default ctor. + /* memset is faster/not slower than initializing groups individually. * This assumes all zeros is group_type's default layout. */ From 8a3e5dd918a2fe0454cf94cd84387b7a24481d20 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 21 Oct 2022 11:13:13 +0200 Subject: [PATCH 256/279] added workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 --- test/unordered/init_type_insert_tests.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp index 2de991fb..1fc2f229 100644 --- a/test/unordered/init_type_insert_tests.cpp +++ b/test/unordered/init_type_insert_tests.cpp @@ -21,7 +21,9 @@ struct move_only } }; -template <> struct std::hash +namespace std{ + +template <> struct hash { std::size_t operator()(move_only const& mo) const noexcept { @@ -29,6 +31,8 @@ template <> struct std::hash } }; +} // namespace std + struct raii_tracker { static int move_constructs; @@ -59,7 +63,9 @@ struct raii_tracker } }; -template <> struct std::hash +namespace std{ + +template <> struct hash { std::size_t operator()(raii_tracker const& rt) const noexcept { @@ -67,6 +73,8 @@ template <> struct std::hash } }; +} // namespace std + int raii_tracker::move_constructs = 0; int raii_tracker::copy_constructs = 0; From 1d15067ef2251bea34c3bbae5f5fb055b185faa5 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Fri, 21 Oct 2022 13:14:39 +0200 Subject: [PATCH 257/279] removed sign conversion warnings --- test/unordered/init_type_insert_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp index 1fc2f229..e995c064 100644 --- a/test/unordered/init_type_insert_tests.cpp +++ b/test/unordered/init_type_insert_tests.cpp @@ -92,10 +92,10 @@ static void test_move_only() map.insert(std::make_pair(move_only(1), v)); map.insert({move_only(2), v}); - BOOST_TEST_EQ(map.size(), 2); + BOOST_TEST_EQ(map.size(), 2u); map.rehash(1024); - BOOST_TEST_GE(map.bucket_count(), 1024); + BOOST_TEST_GE(map.bucket_count(), 1024u); } static void test_insert_tracking() @@ -161,7 +161,7 @@ static void test_insert_tracking() map.rehash(1024); BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); - BOOST_TEST_EQ(raii_tracker::move_constructs, 7 + 2 * map.size()); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size()); } int main() From ad1e3a49a5a728d8468b3d37778c6518190319db Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 21 Oct 2022 11:23:46 -0700 Subject: [PATCH 258/279] Update tracking counts to be unsigned in init_type_insert_tests --- test/unordered/init_type_insert_tests.cpp | 38 +++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp index e995c064..b5e8022c 100644 --- a/test/unordered/init_type_insert_tests.cpp +++ b/test/unordered/init_type_insert_tests.cpp @@ -35,8 +35,8 @@ template <> struct hash struct raii_tracker { - static int move_constructs; - static int copy_constructs; + static unsigned move_constructs; + static unsigned copy_constructs; int x_ = -1; @@ -75,8 +75,8 @@ template <> struct hash } // namespace std -int raii_tracker::move_constructs = 0; -int raii_tracker::copy_constructs = 0; +unsigned raii_tracker::move_constructs = 0; +unsigned raii_tracker::copy_constructs = 0; static void test_move_only() { @@ -102,8 +102,8 @@ static void test_insert_tracking() { raii_tracker::reset_counts(); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 0); - BOOST_TEST_EQ(raii_tracker::move_constructs, 0); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0u); boost::unordered_flat_map > @@ -114,8 +114,8 @@ static void test_insert_tracking() map.insert(value); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 2); - BOOST_TEST_EQ(raii_tracker::move_constructs, 0); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0u); } { @@ -123,8 +123,8 @@ static void test_insert_tracking() map.insert(std::move(value)); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 2); - BOOST_TEST_EQ(raii_tracker::move_constructs, 2); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2u); } { @@ -132,8 +132,8 @@ static void test_insert_tracking() map.insert(value); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 4); - BOOST_TEST_EQ(raii_tracker::move_constructs, 2); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2u); } { @@ -141,26 +141,26 @@ static void test_insert_tracking() map.insert(std::move(value)); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); - BOOST_TEST_EQ(raii_tracker::move_constructs, 3); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 3u); } { map.insert(std::make_pair(5, 6)); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); - BOOST_TEST_EQ(raii_tracker::move_constructs, 5); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 5u); } { map.insert({6, 7}); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); - BOOST_TEST_EQ(raii_tracker::move_constructs, 7); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7u); } BOOST_TEST_EQ(map.size(), 6); map.rehash(1024); - BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size()); } From e0b680ac2964e5cded3fa3f270c55d7cae464cb8 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 21 Oct 2022 11:24:34 -0700 Subject: [PATCH 259/279] Update insert(Iterator, Iterator) overloads to use emplace internally instead of insert()'ing --- include/boost/unordered/detail/foa.hpp | 9 ++++++- .../boost/unordered/unordered_flat_map.hpp | 2 +- .../boost/unordered/unordered_flat_set.hpp | 2 +- test/unordered/insert_tests.cpp | 25 +++++++++++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 9537e9a3..f2867074 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1256,7 +1256,14 @@ public: template BOOST_FORCEINLINE std::pair emplace(Args&&... args) { - return emplace_impl(init_type(std::forward(args)...)); + using emplace_type = typename std::conditional< + std::is_constructible< + init_type, Args... + >::value, + init_type, + value_type + >::type; + return emplace_impl(emplace_type(std::forward(args)...)); } template diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 77431650..2cb4135e 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -242,7 +242,7 @@ namespace boost { void insert(InputIterator first, InputIterator last) { for (auto pos = first; pos != last; ++pos) { - table_.insert(*pos); + table_.emplace(*pos); } } diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index fae770ee..f0129485 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -222,7 +222,7 @@ namespace boost { void insert(InputIterator first, InputIterator last) { for (auto pos = first; pos != last; ++pos) { - table_.insert(*pos); + table_.emplace(*pos); } } diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index b37b20ca..f59d5acd 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -17,6 +17,8 @@ #include "../helpers/input_iterator.hpp" #include "../helpers/helpers.hpp" +#include + namespace insert_tests { test::seed_t initialize_seed(243432); @@ -674,6 +676,23 @@ namespace insert_tests { } } + template void set_tests(X*, test::random_generator) + { + // prove that our insert(iterator, iterator) implementation honors + // Cpp17EmplaceConstructible + // + + X x; + std::vector v; + v.reserve(1000); + for (unsigned i = 0; i < 1000; ++i) { + v.push_back(static_cast(i)); + } + + x.insert(v.begin(), v.end()); + BOOST_TEST_EQ(x.size(), 1000u); + } + template void try_emplace_tests(X*, test::random_generator generator) { @@ -909,6 +928,9 @@ namespace insert_tests { UNORDERED_TEST(map_insert_range_test2, ((test_map))((default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST( + set_tests, ((test_set_std_alloc)(test_set))((default_generator))) #else boost::unordered_set >* test_set_std_alloc; @@ -965,6 +987,9 @@ namespace insert_tests { UNORDERED_TEST(map_insert_range_test2, ((test_multimap_std_alloc)(test_map)(test_multimap))( (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST( + set_tests, ((test_set_std_alloc)(test_set)(test_multiset))((default_generator))) #endif #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) From 2adab2be61eba89e6fe4cac21baa36b018d11781 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 21 Oct 2022 15:37:51 -0700 Subject: [PATCH 260/279] Fix signed-unsigned comparison warning --- test/unordered/init_type_insert_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp index b5e8022c..94afce4b 100644 --- a/test/unordered/init_type_insert_tests.cpp +++ b/test/unordered/init_type_insert_tests.cpp @@ -157,7 +157,7 @@ static void test_insert_tracking() BOOST_TEST_EQ(raii_tracker::move_constructs, 7u); } - BOOST_TEST_EQ(map.size(), 6); + BOOST_TEST_EQ(map.size(), 6u); map.rehash(1024); BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); From 627ffe4ed7a8e6e826fadec63d371a419682e9a6 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 21 Oct 2022 15:38:19 -0700 Subject: [PATCH 261/279] Push up partial refactor for older msvc --- include/boost/unordered/detail/foa.hpp | 127 ++++++++++-------- include/boost/unordered/detail/xmx.hpp | 3 +- .../boost/unordered/unordered_flat_map.hpp | 40 +++--- .../unordered/unordered_flat_map_fwd.hpp | 2 +- .../boost/unordered/unordered_flat_set.hpp | 40 +++--- .../unordered/unordered_flat_set_fwd.hpp | 2 +- 6 files changed, 114 insertions(+), 100 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f2867074..fc7fa9e4 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -134,11 +134,16 @@ namespace foa{ struct group15 { - static constexpr int N=15; + BOOST_STATIC_CONSTEXPR int N=15; struct dummy_group_type { - alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; + BOOST_ALIGNMENT(16) unsigned char storage[N+1]; + + dummy_group_type() { + BOOST_ALIGNMENT(16) unsigned char tmp[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; + std::memcpy(storage, tmp, sizeof(storage)); + } }; inline void initialize(){m=_mm_setzero_si128();} @@ -179,7 +184,7 @@ struct group15 inline bool is_not_overflowed(std::size_t hash)const { - static constexpr unsigned char shift[]={1,2,4,8,16,32,64,128}; + BOOST_STATIC_CONSTEXPR unsigned char shift[]={1,2,4,8,16,32,64,128}; return !(overflow()&shift[hash%8]); } @@ -206,12 +211,12 @@ struct group15 } private: - static constexpr unsigned char available_=0, + BOOST_STATIC_CONSTEXPR unsigned char available_=0, sentinel_=1; inline static int match_word(std::size_t hash) { - static constexpr boost::uint32_t word[]= + BOOST_STATIC_CONSTEXPR boost::uint32_t word[]= { 0x02020202u,0x03030303u,0x02020202u,0x03030303u,0x04040404u,0x05050505u,0x06060606u,0x07070707u, 0x08080808u,0x09090909u,0x0A0A0A0Au,0x0B0B0B0Bu,0x0C0C0C0Cu,0x0D0D0D0Du,0x0E0E0E0Eu,0x0F0F0F0Fu, @@ -275,7 +280,7 @@ private: return at(N); } - alignas(16) __m128i m; + BOOST_ALIGNMENT(16) __m128i m; }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) @@ -642,7 +647,8 @@ struct pow2_size_policy return std::size_t(1)<<(sizeof(std::size_t)*CHAR_BIT-size_index_); } - static constexpr std::size_t min_size(){return 2;} + // static BOOST_CONSTEXPR std::size_t min_size(){return 2;} + BOOST_STATIC_CONSTEXPR std::size_t min_size = 2; static inline std::size_t position(std::size_t hash,std::size_t size_index_) { @@ -776,10 +782,10 @@ public: 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 table_iterator& operator++()noexcept{increment();return *this;} - inline table_iterator operator++(int)noexcept + inline reference operator*()const BOOST_NOEXCEPT{return *p;} + inline pointer operator->()const BOOST_NOEXCEPT{return p;} + inline table_iterator& operator++()BOOST_NOEXCEPT{increment();return *this;} + inline table_iterator operator++(int)BOOST_NOEXCEPT {auto x=*this;increment();return x;} friend inline bool operator==( const table_iterator& x,const table_iterator& y) @@ -797,14 +803,14 @@ private: p{const_cast(p_)} {} - inline std::size_t rebase() noexcept + inline std::size_t rebase() BOOST_NOEXCEPT { std::size_t off=reinterpret_cast(pc)%sizeof(Group); pc-=off; return off; } - inline void increment()noexcept + inline void increment()BOOST_NOEXCEPT { std::size_t n0=rebase(); @@ -852,7 +858,7 @@ Group* dummy_groups() * insertion as the container's capacity is precisely zero. */ - static constexpr typename Group::dummy_group_type + BOOST_STATIC_CONSTEXPR typename Group::dummy_group_type storage[Size]={typename Group::dummy_group_type(),}; return reinterpret_cast( @@ -864,7 +870,7 @@ struct table_arrays { using value_type=Value; using group_type=Group; - static constexpr auto N=group_type::N; + BOOST_STATIC_CONSTEXPR auto N=group_type::N; using size_policy=SizePolicy; template @@ -877,7 +883,7 @@ struct table_arrays table_arrays arrays{groups_size_index,groups_size-1,nullptr,nullptr}; if(!n){ - arrays.groups=dummy_groups(); + arrays.groups=dummy_groups(); } else{ arrays.elements= @@ -903,7 +909,7 @@ struct table_arrays } template - static void delete_(Allocator& al,table_arrays& arrays)noexcept + static void delete_(Allocator& al,table_arrays& arrays)BOOST_NOEXCEPT { using alloc_traits=boost::allocator_traits; using pointer=typename alloc_traits::pointer; @@ -1049,7 +1055,7 @@ inline void prefetch(const void* p) /* We pull this out so the tests don't have to rely on a magic constant or * instantiate the table class template as it can be quite gory. */ -constexpr static float const mlf = 0.875f; +BOOST_STATIC_CONSTEXPR float mlf = 0.875f; template class @@ -1065,7 +1071,7 @@ table:empty_value,empty_value,empty_value using allocator_base=empty_value; using type_policy=TypePolicy; using group_type=group15; - static constexpr auto N=group_type::N; + BOOST_STATIC_CONSTEXPR auto N=group_type::N; using size_policy=pow2_size_policy; using prober=pow2_quadratic_prober; using mix_policy=typename std::conditional< @@ -1081,7 +1087,7 @@ public: using value_type=typename type_policy::value_type; private: - static constexpr bool has_mutable_iterator= + BOOST_STATIC_CONSTEXPR bool has_mutable_iterator= !std::is_same::value; public: @@ -1112,7 +1118,7 @@ public: table{x,alloc_traits::select_on_container_copy_construction(x.al())}{} table(table&& x) - noexcept( + BOOST_NOEXCEPT_IF( std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value): @@ -1156,9 +1162,9 @@ public: } } - ~table()noexcept + ~table()BOOST_NOEXCEPT { - for_all_elements([this](value_type* p){ + for_all_elements([this](group_type*,unsigned int,value_type* p){ destroy_element(p); }); delete_arrays(arrays); @@ -1192,19 +1198,19 @@ public: #endif table& operator=(table&& x) - noexcept( + BOOST_NOEXCEPT_IF( alloc_traits::is_always_equal::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_assignable::value) { - static constexpr auto pocma= + BOOST_STATIC_CONSTEXPR auto pocma= alloc_traits::propagate_on_container_move_assignment::value; if(this!=std::addressof(x)){ clear(); h()=std::move(x.h()); pred()=std::move(x.pred()); - if(pocma||al()==x.al()){ + if_constexpr(pocma||al()==x.al()){ using std::swap; reserve(0); move_assign_if(al(),x.al()); @@ -1233,25 +1239,25 @@ public: #pragma warning(pop) /* C4127 */ #endif - allocator_type get_allocator()const noexcept{return al();} + allocator_type get_allocator()const BOOST_NOEXCEPT{return al();} - iterator begin()noexcept + iterator begin()BOOST_NOEXCEPT { iterator it{arrays.groups,0,arrays.elements}; if(!(arrays.groups[0].match_occupied()&0x1))++it; return it; } - const_iterator begin()const noexcept + const_iterator begin()const BOOST_NOEXCEPT {return const_cast(this)->begin();} - iterator end()noexcept{return {};} - const_iterator end()const noexcept{return const_cast(this)->end();} - const_iterator cbegin()const noexcept{return begin();} - const_iterator cend()const noexcept{return end();} + iterator end()BOOST_NOEXCEPT{return {};} + const_iterator end()const BOOST_NOEXCEPT{return const_cast(this)->end();} + const_iterator cbegin()const BOOST_NOEXCEPT{return begin();} + const_iterator cend()const BOOST_NOEXCEPT{return end();} - bool empty()const noexcept{return size()==0;} - std::size_t size()const noexcept{return size_;} - std::size_t max_size()const noexcept{return SIZE_MAX;} + bool empty()const BOOST_NOEXCEPT{return size()==0;} + std::size_t size()const BOOST_NOEXCEPT{return size_;} + std::size_t max_size()const BOOST_NOEXCEPT{return SIZE_MAX;} template BOOST_FORCEINLINE std::pair emplace(Args&&... args) @@ -1297,9 +1303,9 @@ public: typename std::enable_if< has_mutable_iterator||dependent_value>::type* =nullptr > - void erase(iterator pos)noexcept{return erase(const_iterator(pos));} + void erase(iterator pos)BOOST_NOEXCEPT{return erase(const_iterator(pos));} - void erase(const_iterator pos)noexcept + void erase(const_iterator pos)BOOST_NOEXCEPT { destroy_element(pos.p); group_type::reset(pos.pc); @@ -1320,12 +1326,12 @@ public: } void swap(table& x) - noexcept( + BOOST_NOEXCEPT_IF( alloc_traits::is_always_equal::value&& boost::is_nothrow_swappable::value&& boost::is_nothrow_swappable::value) { - static constexpr auto pocs= + BOOST_STATIC_CONSTEXPR auto pocs= alloc_traits::propagate_on_container_swap::value; using std::swap; @@ -1343,7 +1349,7 @@ public: swap(ml,x.ml); } - void clear()noexcept + void clear()BOOST_NOEXCEPT { auto p=arrays.elements; if(p){ @@ -1392,18 +1398,18 @@ public: return const_cast(this)->find(x); } - std::size_t capacity()const noexcept + std::size_t capacity()const BOOST_NOEXCEPT { return arrays.elements?(arrays.groups_size_mask+1)*N-1:0; } - float load_factor()const noexcept + float load_factor()const BOOST_NOEXCEPT { if (capacity() == 0) { return 0; } return float(size())/float(capacity()); } - float max_load_factor()const noexcept{return mlf;} + float max_load_factor()const BOOST_NOEXCEPT{return mlf;} void rehash(std::size_t n) { @@ -1431,7 +1437,14 @@ private: struct clear_on_exit { + clear_on_exit(table& x_) : x(x_) {} ~clear_on_exit(){x.clear();} + + clear_on_exit& + operator=(clear_on_exit const&) { + return *this; + } + table& x; }; @@ -1447,7 +1460,7 @@ private: return arrays_type::new_(al(),n); } - void delete_arrays(arrays_type& arrays_)noexcept + void delete_arrays(arrays_type& arrays_)BOOST_NOEXCEPT { arrays_type::delete_(al(),arrays_); } @@ -1458,7 +1471,7 @@ private: alloc_traits::construct(al(),p,std::forward(args)...); } - void destroy_element(value_type* p)noexcept + void destroy_element(value_type* p)BOOST_NOEXCEPT { alloc_traits::destroy(al(),p); } @@ -1472,7 +1485,7 @@ private: std::size_t max_load()const { - static constexpr std::size_t small_capacity=2*N-1; + BOOST_STATIC_CONSTEXPR std::size_t small_capacity=2*N-1; auto capacity_=capacity(); if(capacity_<=small_capacity){ @@ -1629,7 +1642,7 @@ private: { std::size_t num_destroyed=0; BOOST_TRY{ - for_all_elements([&,this](value_type* p){ + for_all_elements([&,this](group_type*,unsigned int,value_type* p){ nosize_transfer_element(p,new_arrays_,num_destroyed); }); } @@ -1647,7 +1660,7 @@ private: } } continue_: - for_all_elements(new_arrays_,[this](value_type* p){ + for_all_elements(new_arrays_,[this](group_type*,unsigned int,value_type* p){ destroy_element(p); }); delete_arrays(new_arrays_); @@ -1658,7 +1671,7 @@ private: /* either all moved and destroyed or all copied */ BOOST_ASSERT(num_destroyed==size()||num_destroyed==0); if(num_destroyed!=size()){ - for_all_elements([this](value_type* p){ + for_all_elements([this](group_type*,unsigned int,value_type* p){ destroy_element(p); }); } @@ -1804,13 +1817,13 @@ private: for_all_elements(arrays,f); } - template - static auto for_all_elements(const arrays_type& arrays_,F f) - ->decltype(f(nullptr),void()) - { - for_all_elements( - arrays_,[&](group_type*,unsigned int,value_type* p){return f(p);}); - } + // template + // static auto for_all_elements(const arrays_type& arrays_,F f) + // ->decltype(f(nullptr),void()) + // { + // for_all_elements( + // arrays_,[&](group_type*,unsigned int,value_type* p){return f(p);}); + // } template static auto for_all_elements(const arrays_type& arrays_,F f) diff --git a/include/boost/unordered/detail/xmx.hpp b/include/boost/unordered/detail/xmx.hpp index 4b24fd80..81bff8be 100644 --- a/include/boost/unordered/detail/xmx.hpp +++ b/include/boost/unordered/detail/xmx.hpp @@ -13,6 +13,7 @@ #define BOOST_UNORDERED_DETAIL_XMX_HPP #include +#include #include #include @@ -41,7 +42,7 @@ namespace detail{ #endif #endif -static inline std::size_t xmx(std::size_t x)noexcept +static inline std::size_t xmx(std::size_t x)BOOST_NOEXCEPT { #if defined(BOOST_UNORDERED_64B_ARCHITECTURE) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 2cb4135e..99de4976 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -136,7 +136,7 @@ namespace boost { } unordered_flat_map(unordered_flat_map&& other) - noexcept(std::is_nothrow_move_constructible::value&& + BOOST_NOEXCEPT_IF(std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value) : table_(std::move(other.table_)) @@ -176,14 +176,14 @@ namespace boost { return *this; } - unordered_flat_map& operator=(unordered_flat_map&& other) noexcept( - noexcept(std::declval() = std::declval())) + unordered_flat_map& operator=(unordered_flat_map&& other) BOOST_NOEXCEPT_IF( + BOOST_NOEXCEPT_EXPR(std::declval() = std::declval())) { table_ = std::move(other.table_); return *this; } - allocator_type get_allocator() const noexcept + allocator_type get_allocator() const BOOST_NOEXCEPT { return table_.get_allocator(); } @@ -191,30 +191,30 @@ namespace boost { /// Iterators /// - iterator begin() noexcept { return table_.begin(); } - const_iterator begin() const noexcept { return table_.begin(); } - const_iterator cbegin() const noexcept { return table_.cbegin(); } + iterator begin() BOOST_NOEXCEPT { return table_.begin(); } + const_iterator begin() const BOOST_NOEXCEPT { return table_.begin(); } + const_iterator cbegin() const BOOST_NOEXCEPT { return table_.cbegin(); } - iterator end() noexcept { return table_.end(); } - const_iterator end() const noexcept { return table_.end(); } - const_iterator cend() const noexcept { return table_.cend(); } + iterator end() BOOST_NOEXCEPT { return table_.end(); } + const_iterator end() const BOOST_NOEXCEPT { return table_.end(); } + const_iterator cend() const BOOST_NOEXCEPT { return table_.cend(); } /// Capacity /// - BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept + BOOST_ATTRIBUTE_NODISCARD bool empty() const BOOST_NOEXCEPT { return table_.empty(); } - size_type size() const noexcept { return table_.size(); } + size_type size() const BOOST_NOEXCEPT { return table_.size(); } - size_type max_size() const noexcept { return table_.max_size(); } + size_type max_size() const BOOST_NOEXCEPT { return table_.max_size(); } /// Modifiers /// - void clear() noexcept { table_.clear(); } + void clear() BOOST_NOEXCEPT { table_.clear(); } template auto insert(Ty&& value) @@ -344,8 +344,8 @@ namespace boost { return table_.erase(key); } - void swap(unordered_flat_map& rhs) noexcept( - noexcept(std::declval().swap(std::declval()))) + void swap(unordered_flat_map& rhs) BOOST_NOEXCEPT_IF( + BOOST_NOEXCEPT_EXPR(std::declval().swap(std::declval()))) { table_.swap(rhs.table_); } @@ -519,11 +519,11 @@ namespace boost { /// Hash Policy /// - size_type bucket_count() const noexcept { return table_.capacity(); } + size_type bucket_count() const BOOST_NOEXCEPT { return table_.capacity(); } - float load_factor() const noexcept { return table_.load_factor(); } + float load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } - float max_load_factor() const noexcept + float max_load_factor() const BOOST_NOEXCEPT { return table_.max_load_factor(); } @@ -573,7 +573,7 @@ namespace boost { template void swap(unordered_flat_map& lhs, unordered_flat_map& rhs) - noexcept(noexcept(lhs.swap(rhs))) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))) { lhs.swap(rhs); } diff --git a/include/boost/unordered/unordered_flat_map_fwd.hpp b/include/boost/unordered/unordered_flat_map_fwd.hpp index 2c34d0fb..7461d4bf 100644 --- a/include/boost/unordered/unordered_flat_map_fwd.hpp +++ b/include/boost/unordered/unordered_flat_map_fwd.hpp @@ -36,7 +36,7 @@ namespace boost { template void swap(unordered_flat_map& lhs, unordered_flat_map& rhs) - noexcept(noexcept(lhs.swap(rhs))); + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))); } // namespace unordered using boost::unordered::unordered_flat_map; diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index f0129485..c62a7b85 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -118,7 +118,7 @@ namespace boost { } unordered_flat_set(unordered_flat_set&& other) - noexcept(std::is_nothrow_move_constructible::value&& + BOOST_NOEXCEPT_IF(std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value) : table_(std::move(other.table_)) @@ -158,14 +158,14 @@ namespace boost { return *this; } - unordered_flat_set& operator=(unordered_flat_set&& other) noexcept( - noexcept(std::declval() = std::declval())) + unordered_flat_set& operator=(unordered_flat_set&& other) BOOST_NOEXCEPT_IF( + BOOST_NOEXCEPT_EXPR(std::declval() = std::declval())) { table_ = std::move(other.table_); return *this; } - allocator_type get_allocator() const noexcept + allocator_type get_allocator() const BOOST_NOEXCEPT { return table_.get_allocator(); } @@ -173,30 +173,30 @@ namespace boost { /// Iterators /// - iterator begin() noexcept { return table_.begin(); } - const_iterator begin() const noexcept { return table_.begin(); } - const_iterator cbegin() const noexcept { return table_.cbegin(); } + iterator begin() BOOST_NOEXCEPT { return table_.begin(); } + const_iterator begin() const BOOST_NOEXCEPT { return table_.begin(); } + const_iterator cbegin() const BOOST_NOEXCEPT { return table_.cbegin(); } - iterator end() noexcept { return table_.end(); } - const_iterator end() const noexcept { return table_.end(); } - const_iterator cend() const noexcept { return table_.cend(); } + iterator end() BOOST_NOEXCEPT { return table_.end(); } + const_iterator end() const BOOST_NOEXCEPT { return table_.end(); } + const_iterator cend() const BOOST_NOEXCEPT { return table_.cend(); } /// Capacity /// - BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept + BOOST_ATTRIBUTE_NODISCARD bool empty() const BOOST_NOEXCEPT { return table_.empty(); } - size_type size() const noexcept { return table_.size(); } + size_type size() const BOOST_NOEXCEPT { return table_.size(); } - size_type max_size() const noexcept { return table_.max_size(); } + size_type max_size() const BOOST_NOEXCEPT { return table_.max_size(); } /// Modifiers /// - void clear() noexcept { table_.clear(); } + void clear() BOOST_NOEXCEPT { table_.clear(); } std::pair insert(value_type const& value) { @@ -262,8 +262,8 @@ namespace boost { return table_.erase(key); } - void swap(unordered_flat_set& rhs) noexcept( - noexcept(std::declval().swap(std::declval()))) + void swap(unordered_flat_set& rhs) BOOST_NOEXCEPT_IF( + BOOST_NOEXCEPT_EXPR(std::declval().swap(std::declval()))) { table_.swap(rhs.table_); } @@ -400,11 +400,11 @@ namespace boost { /// Hash Policy /// - size_type bucket_count() const noexcept { return table_.capacity(); } + size_type bucket_count() const BOOST_NOEXCEPT { return table_.capacity(); } - float load_factor() const noexcept { return table_.load_factor(); } + float load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } - float max_load_factor() const noexcept + float max_load_factor() const BOOST_NOEXCEPT { return table_.max_load_factor(); } @@ -454,7 +454,7 @@ namespace boost { template void swap(unordered_flat_set& lhs, unordered_flat_set& rhs) - noexcept(noexcept(lhs.swap(rhs))) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))) { lhs.swap(rhs); } diff --git a/include/boost/unordered/unordered_flat_set_fwd.hpp b/include/boost/unordered/unordered_flat_set_fwd.hpp index 51f534ef..f66dbed6 100644 --- a/include/boost/unordered/unordered_flat_set_fwd.hpp +++ b/include/boost/unordered/unordered_flat_set_fwd.hpp @@ -36,7 +36,7 @@ namespace boost { template void swap(unordered_flat_set& lhs, unordered_flat_set& rhs) - noexcept(noexcept(lhs.swap(rhs))); + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))); } // namespace unordered using boost::unordered::unordered_flat_set; From d8f226d429809ea41f0b6c8ac83499c018717335 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sat, 22 Oct 2022 12:28:04 +0200 Subject: [PATCH 262/279] reverted "Push up partial refactor for older msvc" This reverts commit 627ffe4ed7a8e6e826fadec63d371a419682e9a6. --- include/boost/unordered/detail/foa.hpp | 127 ++++++++---------- include/boost/unordered/detail/xmx.hpp | 3 +- .../boost/unordered/unordered_flat_map.hpp | 40 +++--- .../unordered/unordered_flat_map_fwd.hpp | 2 +- .../boost/unordered/unordered_flat_set.hpp | 40 +++--- .../unordered/unordered_flat_set_fwd.hpp | 2 +- 6 files changed, 100 insertions(+), 114 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index fc7fa9e4..f2867074 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -134,16 +134,11 @@ namespace foa{ struct group15 { - BOOST_STATIC_CONSTEXPR int N=15; + static constexpr int N=15; struct dummy_group_type { - BOOST_ALIGNMENT(16) unsigned char storage[N+1]; - - dummy_group_type() { - BOOST_ALIGNMENT(16) unsigned char tmp[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; - std::memcpy(storage, tmp, sizeof(storage)); - } + alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; }; inline void initialize(){m=_mm_setzero_si128();} @@ -184,7 +179,7 @@ struct group15 inline bool is_not_overflowed(std::size_t hash)const { - BOOST_STATIC_CONSTEXPR unsigned char shift[]={1,2,4,8,16,32,64,128}; + static constexpr unsigned char shift[]={1,2,4,8,16,32,64,128}; return !(overflow()&shift[hash%8]); } @@ -211,12 +206,12 @@ struct group15 } private: - BOOST_STATIC_CONSTEXPR unsigned char available_=0, + static constexpr unsigned char available_=0, sentinel_=1; inline static int match_word(std::size_t hash) { - BOOST_STATIC_CONSTEXPR boost::uint32_t word[]= + static constexpr boost::uint32_t word[]= { 0x02020202u,0x03030303u,0x02020202u,0x03030303u,0x04040404u,0x05050505u,0x06060606u,0x07070707u, 0x08080808u,0x09090909u,0x0A0A0A0Au,0x0B0B0B0Bu,0x0C0C0C0Cu,0x0D0D0D0Du,0x0E0E0E0Eu,0x0F0F0F0Fu, @@ -280,7 +275,7 @@ private: return at(N); } - BOOST_ALIGNMENT(16) __m128i m; + alignas(16) __m128i m; }; #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON) @@ -647,8 +642,7 @@ struct pow2_size_policy return std::size_t(1)<<(sizeof(std::size_t)*CHAR_BIT-size_index_); } - // static BOOST_CONSTEXPR std::size_t min_size(){return 2;} - BOOST_STATIC_CONSTEXPR std::size_t min_size = 2; + static constexpr std::size_t min_size(){return 2;} static inline std::size_t position(std::size_t hash,std::size_t size_index_) { @@ -782,10 +776,10 @@ public: const_iterator_cast_tag, const table_iterator& x): pc{x.pc},p{x.p}{} - inline reference operator*()const BOOST_NOEXCEPT{return *p;} - inline pointer operator->()const BOOST_NOEXCEPT{return p;} - inline table_iterator& operator++()BOOST_NOEXCEPT{increment();return *this;} - inline table_iterator operator++(int)BOOST_NOEXCEPT + inline reference operator*()const noexcept{return *p;} + inline pointer operator->()const noexcept{return p;} + inline table_iterator& operator++()noexcept{increment();return *this;} + inline table_iterator operator++(int)noexcept {auto x=*this;increment();return x;} friend inline bool operator==( const table_iterator& x,const table_iterator& y) @@ -803,14 +797,14 @@ private: p{const_cast(p_)} {} - inline std::size_t rebase() BOOST_NOEXCEPT + inline std::size_t rebase() noexcept { std::size_t off=reinterpret_cast(pc)%sizeof(Group); pc-=off; return off; } - inline void increment()BOOST_NOEXCEPT + inline void increment()noexcept { std::size_t n0=rebase(); @@ -858,7 +852,7 @@ Group* dummy_groups() * insertion as the container's capacity is precisely zero. */ - BOOST_STATIC_CONSTEXPR typename Group::dummy_group_type + static constexpr typename Group::dummy_group_type storage[Size]={typename Group::dummy_group_type(),}; return reinterpret_cast( @@ -870,7 +864,7 @@ struct table_arrays { using value_type=Value; using group_type=Group; - BOOST_STATIC_CONSTEXPR auto N=group_type::N; + static constexpr auto N=group_type::N; using size_policy=SizePolicy; template @@ -883,7 +877,7 @@ struct table_arrays table_arrays arrays{groups_size_index,groups_size-1,nullptr,nullptr}; if(!n){ - arrays.groups=dummy_groups(); + arrays.groups=dummy_groups(); } else{ arrays.elements= @@ -909,7 +903,7 @@ struct table_arrays } template - static void delete_(Allocator& al,table_arrays& arrays)BOOST_NOEXCEPT + static void delete_(Allocator& al,table_arrays& arrays)noexcept { using alloc_traits=boost::allocator_traits; using pointer=typename alloc_traits::pointer; @@ -1055,7 +1049,7 @@ inline void prefetch(const void* p) /* We pull this out so the tests don't have to rely on a magic constant or * instantiate the table class template as it can be quite gory. */ -BOOST_STATIC_CONSTEXPR float mlf = 0.875f; +constexpr static float const mlf = 0.875f; template class @@ -1071,7 +1065,7 @@ table:empty_value,empty_value,empty_value using allocator_base=empty_value; using type_policy=TypePolicy; using group_type=group15; - BOOST_STATIC_CONSTEXPR auto N=group_type::N; + static constexpr auto N=group_type::N; using size_policy=pow2_size_policy; using prober=pow2_quadratic_prober; using mix_policy=typename std::conditional< @@ -1087,7 +1081,7 @@ public: using value_type=typename type_policy::value_type; private: - BOOST_STATIC_CONSTEXPR bool has_mutable_iterator= + static constexpr bool has_mutable_iterator= !std::is_same::value; public: @@ -1118,7 +1112,7 @@ public: table{x,alloc_traits::select_on_container_copy_construction(x.al())}{} table(table&& x) - BOOST_NOEXCEPT_IF( + noexcept( std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value): @@ -1162,9 +1156,9 @@ public: } } - ~table()BOOST_NOEXCEPT + ~table()noexcept { - for_all_elements([this](group_type*,unsigned int,value_type* p){ + for_all_elements([this](value_type* p){ destroy_element(p); }); delete_arrays(arrays); @@ -1198,19 +1192,19 @@ public: #endif table& operator=(table&& x) - BOOST_NOEXCEPT_IF( + noexcept( alloc_traits::is_always_equal::value&& std::is_nothrow_move_assignable::value&& std::is_nothrow_move_assignable::value) { - BOOST_STATIC_CONSTEXPR auto pocma= + static constexpr auto pocma= alloc_traits::propagate_on_container_move_assignment::value; if(this!=std::addressof(x)){ clear(); h()=std::move(x.h()); pred()=std::move(x.pred()); - if_constexpr(pocma||al()==x.al()){ + if(pocma||al()==x.al()){ using std::swap; reserve(0); move_assign_if(al(),x.al()); @@ -1239,25 +1233,25 @@ public: #pragma warning(pop) /* C4127 */ #endif - allocator_type get_allocator()const BOOST_NOEXCEPT{return al();} + allocator_type get_allocator()const noexcept{return al();} - iterator begin()BOOST_NOEXCEPT + iterator begin()noexcept { iterator it{arrays.groups,0,arrays.elements}; if(!(arrays.groups[0].match_occupied()&0x1))++it; return it; } - const_iterator begin()const BOOST_NOEXCEPT + const_iterator begin()const noexcept {return const_cast(this)->begin();} - iterator end()BOOST_NOEXCEPT{return {};} - const_iterator end()const BOOST_NOEXCEPT{return const_cast(this)->end();} - const_iterator cbegin()const BOOST_NOEXCEPT{return begin();} - const_iterator cend()const BOOST_NOEXCEPT{return end();} + iterator end()noexcept{return {};} + const_iterator end()const noexcept{return const_cast(this)->end();} + const_iterator cbegin()const noexcept{return begin();} + const_iterator cend()const noexcept{return end();} - bool empty()const BOOST_NOEXCEPT{return size()==0;} - std::size_t size()const BOOST_NOEXCEPT{return size_;} - std::size_t max_size()const BOOST_NOEXCEPT{return SIZE_MAX;} + bool empty()const noexcept{return size()==0;} + std::size_t size()const noexcept{return size_;} + std::size_t max_size()const noexcept{return SIZE_MAX;} template BOOST_FORCEINLINE std::pair emplace(Args&&... args) @@ -1303,9 +1297,9 @@ public: typename std::enable_if< has_mutable_iterator||dependent_value>::type* =nullptr > - void erase(iterator pos)BOOST_NOEXCEPT{return erase(const_iterator(pos));} + void erase(iterator pos)noexcept{return erase(const_iterator(pos));} - void erase(const_iterator pos)BOOST_NOEXCEPT + void erase(const_iterator pos)noexcept { destroy_element(pos.p); group_type::reset(pos.pc); @@ -1326,12 +1320,12 @@ public: } void swap(table& x) - BOOST_NOEXCEPT_IF( + noexcept( alloc_traits::is_always_equal::value&& boost::is_nothrow_swappable::value&& boost::is_nothrow_swappable::value) { - BOOST_STATIC_CONSTEXPR auto pocs= + static constexpr auto pocs= alloc_traits::propagate_on_container_swap::value; using std::swap; @@ -1349,7 +1343,7 @@ public: swap(ml,x.ml); } - void clear()BOOST_NOEXCEPT + void clear()noexcept { auto p=arrays.elements; if(p){ @@ -1398,18 +1392,18 @@ public: return const_cast(this)->find(x); } - std::size_t capacity()const BOOST_NOEXCEPT + std::size_t capacity()const noexcept { return arrays.elements?(arrays.groups_size_mask+1)*N-1:0; } - float load_factor()const BOOST_NOEXCEPT + float load_factor()const noexcept { if (capacity() == 0) { return 0; } return float(size())/float(capacity()); } - float max_load_factor()const BOOST_NOEXCEPT{return mlf;} + float max_load_factor()const noexcept{return mlf;} void rehash(std::size_t n) { @@ -1437,14 +1431,7 @@ private: struct clear_on_exit { - clear_on_exit(table& x_) : x(x_) {} ~clear_on_exit(){x.clear();} - - clear_on_exit& - operator=(clear_on_exit const&) { - return *this; - } - table& x; }; @@ -1460,7 +1447,7 @@ private: return arrays_type::new_(al(),n); } - void delete_arrays(arrays_type& arrays_)BOOST_NOEXCEPT + void delete_arrays(arrays_type& arrays_)noexcept { arrays_type::delete_(al(),arrays_); } @@ -1471,7 +1458,7 @@ private: alloc_traits::construct(al(),p,std::forward(args)...); } - void destroy_element(value_type* p)BOOST_NOEXCEPT + void destroy_element(value_type* p)noexcept { alloc_traits::destroy(al(),p); } @@ -1485,7 +1472,7 @@ private: std::size_t max_load()const { - BOOST_STATIC_CONSTEXPR std::size_t small_capacity=2*N-1; + static constexpr std::size_t small_capacity=2*N-1; auto capacity_=capacity(); if(capacity_<=small_capacity){ @@ -1642,7 +1629,7 @@ private: { std::size_t num_destroyed=0; BOOST_TRY{ - for_all_elements([&,this](group_type*,unsigned int,value_type* p){ + for_all_elements([&,this](value_type* p){ nosize_transfer_element(p,new_arrays_,num_destroyed); }); } @@ -1660,7 +1647,7 @@ private: } } continue_: - for_all_elements(new_arrays_,[this](group_type*,unsigned int,value_type* p){ + for_all_elements(new_arrays_,[this](value_type* p){ destroy_element(p); }); delete_arrays(new_arrays_); @@ -1671,7 +1658,7 @@ private: /* either all moved and destroyed or all copied */ BOOST_ASSERT(num_destroyed==size()||num_destroyed==0); if(num_destroyed!=size()){ - for_all_elements([this](group_type*,unsigned int,value_type* p){ + for_all_elements([this](value_type* p){ destroy_element(p); }); } @@ -1817,13 +1804,13 @@ private: for_all_elements(arrays,f); } - // template - // static auto for_all_elements(const arrays_type& arrays_,F f) - // ->decltype(f(nullptr),void()) - // { - // for_all_elements( - // arrays_,[&](group_type*,unsigned int,value_type* p){return f(p);}); - // } + template + static auto for_all_elements(const arrays_type& arrays_,F f) + ->decltype(f(nullptr),void()) + { + for_all_elements( + arrays_,[&](group_type*,unsigned int,value_type* p){return f(p);}); + } template static auto for_all_elements(const arrays_type& arrays_,F f) diff --git a/include/boost/unordered/detail/xmx.hpp b/include/boost/unordered/detail/xmx.hpp index 81bff8be..4b24fd80 100644 --- a/include/boost/unordered/detail/xmx.hpp +++ b/include/boost/unordered/detail/xmx.hpp @@ -13,7 +13,6 @@ #define BOOST_UNORDERED_DETAIL_XMX_HPP #include -#include #include #include @@ -42,7 +41,7 @@ namespace detail{ #endif #endif -static inline std::size_t xmx(std::size_t x)BOOST_NOEXCEPT +static inline std::size_t xmx(std::size_t x)noexcept { #if defined(BOOST_UNORDERED_64B_ARCHITECTURE) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 99de4976..2cb4135e 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -136,7 +136,7 @@ namespace boost { } unordered_flat_map(unordered_flat_map&& other) - BOOST_NOEXCEPT_IF(std::is_nothrow_move_constructible::value&& + noexcept(std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value) : table_(std::move(other.table_)) @@ -176,14 +176,14 @@ namespace boost { return *this; } - unordered_flat_map& operator=(unordered_flat_map&& other) BOOST_NOEXCEPT_IF( - BOOST_NOEXCEPT_EXPR(std::declval() = std::declval())) + unordered_flat_map& operator=(unordered_flat_map&& other) noexcept( + noexcept(std::declval() = std::declval())) { table_ = std::move(other.table_); return *this; } - allocator_type get_allocator() const BOOST_NOEXCEPT + allocator_type get_allocator() const noexcept { return table_.get_allocator(); } @@ -191,30 +191,30 @@ namespace boost { /// Iterators /// - iterator begin() BOOST_NOEXCEPT { return table_.begin(); } - const_iterator begin() const BOOST_NOEXCEPT { return table_.begin(); } - const_iterator cbegin() const BOOST_NOEXCEPT { return table_.cbegin(); } + iterator begin() noexcept { return table_.begin(); } + const_iterator begin() const noexcept { return table_.begin(); } + const_iterator cbegin() const noexcept { return table_.cbegin(); } - iterator end() BOOST_NOEXCEPT { return table_.end(); } - const_iterator end() const BOOST_NOEXCEPT { return table_.end(); } - const_iterator cend() const BOOST_NOEXCEPT { return table_.cend(); } + iterator end() noexcept { return table_.end(); } + const_iterator end() const noexcept { return table_.end(); } + const_iterator cend() const noexcept { return table_.cend(); } /// Capacity /// - BOOST_ATTRIBUTE_NODISCARD bool empty() const BOOST_NOEXCEPT + BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept { return table_.empty(); } - size_type size() const BOOST_NOEXCEPT { return table_.size(); } + size_type size() const noexcept { return table_.size(); } - size_type max_size() const BOOST_NOEXCEPT { return table_.max_size(); } + size_type max_size() const noexcept { return table_.max_size(); } /// Modifiers /// - void clear() BOOST_NOEXCEPT { table_.clear(); } + void clear() noexcept { table_.clear(); } template auto insert(Ty&& value) @@ -344,8 +344,8 @@ namespace boost { return table_.erase(key); } - void swap(unordered_flat_map& rhs) BOOST_NOEXCEPT_IF( - BOOST_NOEXCEPT_EXPR(std::declval().swap(std::declval()))) + void swap(unordered_flat_map& rhs) noexcept( + noexcept(std::declval().swap(std::declval()))) { table_.swap(rhs.table_); } @@ -519,11 +519,11 @@ namespace boost { /// Hash Policy /// - size_type bucket_count() const BOOST_NOEXCEPT { return table_.capacity(); } + size_type bucket_count() const noexcept { return table_.capacity(); } - float load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } + float load_factor() const noexcept { return table_.load_factor(); } - float max_load_factor() const BOOST_NOEXCEPT + float max_load_factor() const noexcept { return table_.max_load_factor(); } @@ -573,7 +573,7 @@ namespace boost { template void swap(unordered_flat_map& lhs, unordered_flat_map& rhs) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))) + noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } diff --git a/include/boost/unordered/unordered_flat_map_fwd.hpp b/include/boost/unordered/unordered_flat_map_fwd.hpp index 7461d4bf..2c34d0fb 100644 --- a/include/boost/unordered/unordered_flat_map_fwd.hpp +++ b/include/boost/unordered/unordered_flat_map_fwd.hpp @@ -36,7 +36,7 @@ namespace boost { template void swap(unordered_flat_map& lhs, unordered_flat_map& rhs) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))); + noexcept(noexcept(lhs.swap(rhs))); } // namespace unordered using boost::unordered::unordered_flat_map; diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index c62a7b85..f0129485 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -118,7 +118,7 @@ namespace boost { } unordered_flat_set(unordered_flat_set&& other) - BOOST_NOEXCEPT_IF(std::is_nothrow_move_constructible::value&& + noexcept(std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value&& std::is_nothrow_move_constructible::value) : table_(std::move(other.table_)) @@ -158,14 +158,14 @@ namespace boost { return *this; } - unordered_flat_set& operator=(unordered_flat_set&& other) BOOST_NOEXCEPT_IF( - BOOST_NOEXCEPT_EXPR(std::declval() = std::declval())) + unordered_flat_set& operator=(unordered_flat_set&& other) noexcept( + noexcept(std::declval() = std::declval())) { table_ = std::move(other.table_); return *this; } - allocator_type get_allocator() const BOOST_NOEXCEPT + allocator_type get_allocator() const noexcept { return table_.get_allocator(); } @@ -173,30 +173,30 @@ namespace boost { /// Iterators /// - iterator begin() BOOST_NOEXCEPT { return table_.begin(); } - const_iterator begin() const BOOST_NOEXCEPT { return table_.begin(); } - const_iterator cbegin() const BOOST_NOEXCEPT { return table_.cbegin(); } + iterator begin() noexcept { return table_.begin(); } + const_iterator begin() const noexcept { return table_.begin(); } + const_iterator cbegin() const noexcept { return table_.cbegin(); } - iterator end() BOOST_NOEXCEPT { return table_.end(); } - const_iterator end() const BOOST_NOEXCEPT { return table_.end(); } - const_iterator cend() const BOOST_NOEXCEPT { return table_.cend(); } + iterator end() noexcept { return table_.end(); } + const_iterator end() const noexcept { return table_.end(); } + const_iterator cend() const noexcept { return table_.cend(); } /// Capacity /// - BOOST_ATTRIBUTE_NODISCARD bool empty() const BOOST_NOEXCEPT + BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept { return table_.empty(); } - size_type size() const BOOST_NOEXCEPT { return table_.size(); } + size_type size() const noexcept { return table_.size(); } - size_type max_size() const BOOST_NOEXCEPT { return table_.max_size(); } + size_type max_size() const noexcept { return table_.max_size(); } /// Modifiers /// - void clear() BOOST_NOEXCEPT { table_.clear(); } + void clear() noexcept { table_.clear(); } std::pair insert(value_type const& value) { @@ -262,8 +262,8 @@ namespace boost { return table_.erase(key); } - void swap(unordered_flat_set& rhs) BOOST_NOEXCEPT_IF( - BOOST_NOEXCEPT_EXPR(std::declval().swap(std::declval()))) + void swap(unordered_flat_set& rhs) noexcept( + noexcept(std::declval().swap(std::declval()))) { table_.swap(rhs.table_); } @@ -400,11 +400,11 @@ namespace boost { /// Hash Policy /// - size_type bucket_count() const BOOST_NOEXCEPT { return table_.capacity(); } + size_type bucket_count() const noexcept { return table_.capacity(); } - float load_factor() const BOOST_NOEXCEPT { return table_.load_factor(); } + float load_factor() const noexcept { return table_.load_factor(); } - float max_load_factor() const BOOST_NOEXCEPT + float max_load_factor() const noexcept { return table_.max_load_factor(); } @@ -454,7 +454,7 @@ namespace boost { template void swap(unordered_flat_set& lhs, unordered_flat_set& rhs) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))) + noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } diff --git a/include/boost/unordered/unordered_flat_set_fwd.hpp b/include/boost/unordered/unordered_flat_set_fwd.hpp index f66dbed6..51f534ef 100644 --- a/include/boost/unordered/unordered_flat_set_fwd.hpp +++ b/include/boost/unordered/unordered_flat_set_fwd.hpp @@ -36,7 +36,7 @@ namespace boost { template void swap(unordered_flat_set& lhs, unordered_flat_set& rhs) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(lhs.swap(rhs))); + noexcept(noexcept(lhs.swap(rhs))); } // namespace unordered using boost::unordered::unordered_flat_set; From 01053738ebd950a7ad90b072a482841c83659557 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 08:21:54 -0700 Subject: [PATCH 263/279] Rewrite test constraints in terms of config checks --- test/Jamfile.v2 | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2c27334b..e520ec30 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -97,9 +97,13 @@ run exception/merge_exception_tests.cpp ; run quick.cpp ; +import ../../config/checks/config : requires ; + +CPP11 = [ requires cxx11_constexpr cxx11_noexcept cxx11_decltype ] ; + rule build_foa ( name ) { - run unordered/$(name).cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_$(name) ; + run unordered/$(name).cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_$(name) ; } build_foa fwd_set_test ; @@ -107,7 +111,7 @@ build_foa fwd_map_test ; build_foa compile_set ; build_foa compile_map ; build_foa noexcept_tests ; -run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_link_test ; +run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_link_test ; build_foa incomplete_test ; build_foa simple_tests ; build_foa equivalent_keys_tests ; @@ -127,7 +131,7 @@ build_foa load_factor_tests ; build_foa rehash_tests ; build_foa equality_tests ; build_foa swap_tests ; -run unordered/scoped_allocator.cpp : : : 98:no 03:no 0x:no msvc-14.0:no BOOST_UNORDERED_FOA_TESTS : foa_scoped_allocator ; +run unordered/scoped_allocator.cpp : : : $(CPP11) msvc-14.0:no BOOST_UNORDERED_FOA_TESTS : foa_scoped_allocator ; build_foa transparent_tests ; build_foa reserve_tests ; build_foa contains_tests ; @@ -135,12 +139,12 @@ build_foa erase_if ; build_foa scary_tests ; build_foa init_type_insert_tests ; -run exception/constructor_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ; -run exception/copy_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ; -run exception/assign_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_assign_exception_tests ; -run exception/move_assign_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_move_assign_exception_tests ; -run exception/insert_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_insert_exception_tests ; -run exception/erase_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_erase_exception_tests ; -run exception/rehash_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_rehash_exception_tests ; -run exception/swap_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_swap_exception_tests ; -run exception/merge_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_merge_exception_tests ; +run exception/constructor_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ; +run exception/copy_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ; +run exception/assign_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_assign_exception_tests ; +run exception/move_assign_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_move_assign_exception_tests ; +run exception/insert_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_insert_exception_tests ; +run exception/erase_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_erase_exception_tests ; +run exception/rehash_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_rehash_exception_tests ; +run exception/swap_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_swap_exception_tests ; +run exception/merge_exception_tests.cpp : : : $(CPP11) BOOST_UNORDERED_FOA_TESTS : foa_merge_exception_tests ; From 375d7157b64471d6d9cbe57d847732038a1a2019 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 09:54:57 -0700 Subject: [PATCH 264/279] Add tests for missing typedefs in flat containers --- include/boost/unordered/unordered_flat_map.hpp | 3 +++ include/boost/unordered/unordered_flat_set.hpp | 3 +++ test/unordered/compile_tests.hpp | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 2cb4135e..82aa4f16 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -75,6 +75,9 @@ namespace boost { using allocator_type = Allocator; using reference = value_type&; using const_reference = value_type const&; + using pointer = typename boost::allocator_pointer::type; + using const_pointer = + typename boost::allocator_const_pointer::type; using iterator = typename table_type::iterator; using const_iterator = typename table_type::const_iterator; diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index f0129485..a58151bb 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -57,6 +57,9 @@ namespace boost { using allocator_type = Allocator; using reference = value_type&; using const_reference = value_type const&; + using pointer = typename boost::allocator_pointer::type; + using const_pointer = + typename boost::allocator_const_pointer::type; using iterator = typename table_type::iterator; using const_iterator = typename table_type::const_iterator; diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 65509e79..4aeaf61f 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -75,6 +75,14 @@ template void container_test(X& r, T const&) #endif typedef typename X::allocator_type allocator_type; + typedef typename X::pointer pointer; + typedef typename X::const_pointer const_pointer; + + BOOST_STATIC_ASSERT((boost::is_same::type>::value)); + + BOOST_STATIC_ASSERT((boost::is_same::type>::value)); // value_type From 955dab463756989f34bd02f89791aefa303f2741 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 11:17:05 -0700 Subject: [PATCH 265/279] Add missing init_type overloads for insert(hint) --- .../boost/unordered/unordered_flat_map.hpp | 8 ++- test/unordered/init_type_insert_tests.cpp | 67 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 82aa4f16..aa39fcfd 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -231,12 +231,14 @@ namespace boost { return table_.insert(std::move(value)); } - iterator insert(const_iterator, value_type const& value) + template + auto insert(const_iterator, Ty&& value) + -> decltype(table_.insert(std::forward(value)).first) { - return table_.insert(value).first; + return table_.insert(std::forward(value)).first; } - iterator insert(const_iterator, value_type&& value) + iterator insert(const_iterator, init_type&& value) { return table_.insert(std::move(value)).first; } diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp index 94afce4b..efa1df37 100644 --- a/test/unordered/init_type_insert_tests.cpp +++ b/test/unordered/init_type_insert_tests.cpp @@ -164,9 +164,76 @@ static void test_insert_tracking() BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size()); } +static void test_insert_hint_tracking() +{ + raii_tracker::reset_counts(); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0u); + + boost::unordered_flat_map > + map; + + { + std::pair value{1, 2}; + + map.insert(map.begin(), value); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0u); + } + + { + std::pair value{2, 3}; + + map.insert(std::move(value)); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2u); + } + + { + std::pair value{3, 4}; + + map.insert(map.begin(), value); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2u); + } + + { + std::pair value{4, 5}; + + map.insert(map.begin(), std::move(value)); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 3u); + } + + { + map.insert(map.begin(), std::make_pair(5, 6)); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 5u); + } + + { + map.insert(map.begin(), {6, 7}); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7u); + } + + BOOST_TEST_EQ(map.size(), 6u); + + map.rehash(1024); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size()); +} + int main() { test_move_only(); test_insert_tracking(); + test_insert_hint_tracking(); return boost::report_errors(); } From 6c0d121e5bcc912285ea847ff7c2c868f7417924 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 11:17:24 -0700 Subject: [PATCH 266/279] Update requirements for testing to include support for alignas(N) --- test/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e520ec30..200976ad 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -99,7 +99,7 @@ run quick.cpp ; import ../../config/checks/config : requires ; -CPP11 = [ requires cxx11_constexpr cxx11_noexcept cxx11_decltype ] ; +CPP11 = [ requires cxx11_constexpr cxx11_noexcept cxx11_decltype cxx11_alignas ] ; rule build_foa ( name ) { From 222f0a737d5c44530b4b55b4826c93248849872a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 11:17:37 -0700 Subject: [PATCH 267/279] Split AppVeyor jobs to avoid timeouts --- .appveyor.yml | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 7c4042a2..5dfa6c5d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -42,7 +42,12 @@ environment: - FLAVOR: Visual Studio 2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - B2_CXXSTD: 14,17,latest + B2_CXXSTD: 14,17 + B2_TOOLSET: msvc-14.1 + + - FLAVOR: Visual Studio 2017 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_CXXSTD: latest B2_TOOLSET: msvc-14.1 - FLAVOR: cygwin (32-bit) @@ -63,7 +68,7 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 ADDPATH: C:\cygwin64\bin; B2_ADDRESS_MODEL: 64 - B2_CXXSTD: 03,11 + B2_CXXSTD: 03 B2_TOOLSET: gcc B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception" @@ -71,14 +76,37 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 ADDPATH: C:\cygwin64\bin; B2_ADDRESS_MODEL: 64 - B2_CXXSTD: 14,1z + B2_CXXSTD: 11 + B2_TOOLSET: gcc + B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception" + + - FLAVOR: cygwin (64-bit, latest) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + ADDPATH: C:\cygwin64\bin; + B2_ADDRESS_MODEL: 64 + B2_CXXSTD: 14 + B2_TOOLSET: gcc + B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception" + + - FLAVOR: cygwin (64-bit, latest) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + ADDPATH: C:\cygwin64\bin; + B2_ADDRESS_MODEL: 64 + B2_CXXSTD: 1z B2_TOOLSET: gcc B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception" - FLAVOR: mingw-w64, 32 bit APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin; - B2_CXXSTD: 03,11,14,17,2a + B2_CXXSTD: 03,11,14 + B2_TOOLSET: gcc + B2_ADDRESS_MODEL: 32 + + - FLAVOR: mingw-w64, 32 bit + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin; + B2_CXXSTD: 17,2a B2_TOOLSET: gcc B2_ADDRESS_MODEL: 32 From fb1b1dfe2d42b70c5f8ae125c2e30084b8aaa707 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 11:31:25 -0700 Subject: [PATCH 268/279] Add missing copyright updates --- test/exception/containers.hpp | 1 + test/exception/insert_exception_tests.cpp | 1 + test/exception/merge_exception_tests.cpp | 1 + test/exception/swap_exception_tests.cpp | 1 + test/helpers/invariants.hpp | 1 + test/unordered/assign_tests.cpp | 1 + test/unordered/at_tests.cpp | 1 + test/unordered/compile_map.cpp | 1 + test/unordered/compile_set.cpp | 1 + test/unordered/compile_tests.hpp | 1 + test/unordered/contains_tests.cpp | 2 +- test/unordered/emplace_tests.cpp | 1 + test/unordered/equality_tests.cpp | 1 + test/unordered/equivalent_keys_tests.cpp | 1 + test/unordered/erase_tests.cpp | 1 + test/unordered/fwd_map_test.cpp | 1 + test/unordered/fwd_set_test.cpp | 1 + test/unordered/incomplete_test.cpp | 1 + test/unordered/init_type_insert_tests.cpp | 5 +++++ test/unordered/insert_hint_tests.cpp | 1 + test/unordered/link_test_1.cpp | 1 + test/unordered/link_test_2.cpp | 1 + test/unordered/load_factor_tests.cpp | 1 + test/unordered/merge_tests.cpp | 1 + test/unordered/move_tests.cpp | 1 + test/unordered/noexcept_tests.cpp | 1 + test/unordered/rehash_tests.cpp | 1 + test/unordered/simple_tests.cpp | 1 + test/unordered/swap_tests.cpp | 1 + 29 files changed, 33 insertions(+), 1 deletion(-) diff --git a/test/exception/containers.hpp b/test/exception/containers.hpp index 9f78923d..e6eb267b 100644 --- a/test/exception/containers.hpp +++ b/test/exception/containers.hpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index eee11183..27f95f7f 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) #include "./containers.hpp" diff --git a/test/exception/merge_exception_tests.cpp b/test/exception/merge_exception_tests.cpp index a6a7afc7..e824fdde 100644 --- a/test/exception/merge_exception_tests.cpp +++ b/test/exception/merge_exception_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2017-2018 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 2745ede5..545d607a 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index 849fe983..7fbe25a5 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index b937c57e..b000e42f 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index bc5ad921..b06dfddb 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2007-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index f43476c0..c4c8d7ce 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index d51bc11e..aa3721c6 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 4aeaf61f..6c72e26d 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -1,5 +1,6 @@ // Copyright 2005-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/contains_tests.cpp b/test/unordered/contains_tests.cpp index 782e1915..870de2a3 100644 --- a/test/unordered/contains_tests.cpp +++ b/test/unordered/contains_tests.cpp @@ -1,4 +1,4 @@ -// Copyright 2021 Christian Mazakas. +// Copyright 2021-2022 Christian Mazakas. // 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) diff --git a/test/unordered/emplace_tests.cpp b/test/unordered/emplace_tests.cpp index bf79e2c2..60aceb32 100644 --- a/test/unordered/emplace_tests.cpp +++ b/test/unordered/emplace_tests.cpp @@ -1,5 +1,6 @@ // // Copyright 2016 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index 68e021ca..d10d07f2 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2008-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index 0a67b768..b279a8c6 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index ff02856a..d030c6aa 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/fwd_map_test.cpp b/test/unordered/fwd_map_test.cpp index 30acf14e..5ce1fb94 100644 --- a/test/unordered/fwd_map_test.cpp +++ b/test/unordered/fwd_map_test.cpp @@ -1,5 +1,6 @@ // Copyright 2008-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index ecaaa3b1..86f4a9d1 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -1,5 +1,6 @@ // Copyright 2008-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 63058f03..3c5b09fa 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -1,5 +1,6 @@ // Copyright 2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp index efa1df37..e9920d38 100644 --- a/test/unordered/init_type_insert_tests.cpp +++ b/test/unordered/init_type_insert_tests.cpp @@ -1,3 +1,8 @@ + +// Copyright 2022 Christian Mazakas. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) + #if !defined(BOOST_UNORDERED_FOA_TESTS) #error "This test is only for the FOA-style conatiners" #endif diff --git a/test/unordered/insert_hint_tests.cpp b/test/unordered/insert_hint_tests.cpp index 17cfd7ff..ebde259c 100644 --- a/test/unordered/insert_hint_tests.cpp +++ b/test/unordered/insert_hint_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2016 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/link_test_1.cpp b/test/unordered/link_test_1.cpp index 1d1daae7..d8032e73 100644 --- a/test/unordered/link_test_1.cpp +++ b/test/unordered/link_test_1.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/link_test_2.cpp b/test/unordered/link_test_2.cpp index fdeb529d..74de87c9 100644 --- a/test/unordered/link_test_2.cpp +++ b/test/unordered/link_test_2.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 26a12e36..461f883d 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 2f1f4302..32f4d685 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2016 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 9e899c19..53cac2ce 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2008-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index d4bed53f..0cb4b521 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2013 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index fb122c03..d543cdda 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index e22f6db6..dbbf7a48 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index cee0a42f..6f41c876 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -1,5 +1,6 @@ // Copyright 2006-2009 Daniel James. +// Copyright 2022 Christian Mazakas. // 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) From ef54c6bd14f2b09b34fa1635c9b241bc97a39c9f Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 15:04:24 -0700 Subject: [PATCH 269/279] Clean up u64 benchmarks --- benchmark/uint64.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/benchmark/uint64.cpp b/benchmark/uint64.cpp index 4abc4a3e..e6eb18d0 100644 --- a/benchmark/uint64.cpp +++ b/benchmark/uint64.cpp @@ -316,8 +316,25 @@ template using boost_unordered_map = template struct map_types { using key_type = Key; - using value_type = std::pair; - static auto& extract(const value_type& x) { return x.first; } + using raw_key_type = typename std::remove_const::type; + using raw_mapped_type = typename std::remove_const::type; + + using init_type = std::pair; + using moved_type = std::pair; + using value_type = std::pair; + + template + static raw_key_type const& extract(std::pair const& kv) + { + return kv.first; + } + + static moved_type move(value_type& x) + { + // TODO: we probably need to launder here + return {std::move(const_cast(x.first)), + std::move(const_cast(x.second))}; + } }; template From 1f781a407e82d39d0b18826d710637fbd7c637f1 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 24 Oct 2022 15:05:49 -0700 Subject: [PATCH 270/279] Test cleanup --- test/helpers/unordered.hpp | 1 + test/unordered/compile_tests.hpp | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/helpers/unordered.hpp b/test/helpers/unordered.hpp index 5a2361ea..a3af9452 100644 --- a/test/helpers/unordered.hpp +++ b/test/helpers/unordered.hpp @@ -17,5 +17,6 @@ #include #endif #include "postfix.hpp" +// clang-format on #endif diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 6c72e26d..e45a4570 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -518,13 +518,11 @@ template void equality_test(X& r) template void unordered_unique_test(X& r, T const& t) { - (void) r; - (void) t; -#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::iterator iterator; test::check_return_type >::equals(r.insert(t)); test::check_return_type >::equals(r.emplace(t)); +#ifndef BOOST_UNORDERED_FOA_TESTS typedef typename X::node_type node_type; typedef typename X::insert_return_type insert_return_type; From 7db310f6d27fbd2b37c5e831f00a515a21cd6b67 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 25 Oct 2022 11:48:41 +0200 Subject: [PATCH 271/279] reverted 0b575dc98304af2b8e8f565783f0f85898df3b52 (may affect performance) --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f2867074..132301e2 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -387,7 +387,7 @@ private: static inline int simde_mm_movemask_epi8(uint8x16_t a) { - static constexpr uint8_t md[16]={ + static const uint8_t md[16]={ 1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7, 1 << 0, 1 << 1, 1 << 2, 1 << 3, From e29bf7a4a06adb97743fba1a79a8e893ca497f35 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 25 Oct 2022 14:31:27 +0200 Subject: [PATCH 272/279] reverted --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 132301e2..f2867074 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -387,7 +387,7 @@ private: static inline int simde_mm_movemask_epi8(uint8x16_t a) { - static const uint8_t md[16]={ + static constexpr uint8_t md[16]={ 1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7, 1 << 0, 1 << 1, 1 << 2, 1 << 3, From 492df9c9c6644ac964880c3f3369ea280c037afa Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 25 Oct 2022 14:33:07 +0200 Subject: [PATCH 273/279] restored uint64.cpp --- benchmark/uint64.cpp | 47 +------------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/benchmark/uint64.cpp b/benchmark/uint64.cpp index e6eb18d0..a2c1b3a3 100644 --- a/benchmark/uint64.cpp +++ b/benchmark/uint64.cpp @@ -5,14 +5,12 @@ #define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING #include -#include #include #include #include #include #include #include -#include #ifdef HAVE_ABSEIL # include "absl/container/node_hash_map.h" # include "absl/container/flat_hash_map.h" @@ -313,46 +311,6 @@ template using std_unordered_map = template using boost_unordered_map = boost::unordered_map, std::equal_to, allocator_for>; -template struct map_types -{ - using key_type = Key; - using raw_key_type = typename std::remove_const::type; - using raw_mapped_type = typename std::remove_const::type; - - using init_type = std::pair; - using moved_type = std::pair; - using value_type = std::pair; - - template - static raw_key_type const& extract(std::pair const& kv) - { - return kv.first; - } - - static moved_type move(value_type& x) - { - // TODO: we probably need to launder here - return {std::move(const_cast(x.first)), - std::move(const_cast(x.second))}; - } -}; - -template -using boost_unordered_detail_foa_table = - boost::unordered::detail::foa::table, - absl::container_internal::hash_default_hash, std::equal_to, - allocator_for >; - -template -using boost_unordered_flat_map = boost::unordered::unordered_flat_map, std::equal_to, - allocator_for >; - -template -using rc15_flat_map = foa_unordered_rc_map, std::equal_to, - allocator_for >; - #ifdef HAVE_ABSEIL template using absl_node_hash_map = @@ -389,9 +347,6 @@ int main() test( "std::unordered_map" ); test( "boost::unordered_map" ); - test( "boost_unordered_detail_foa_table" ); - test( "boost::unordered_flat_map" ); - test( "rc15_flat_map" ); test( "multi_index_map" ); #ifdef HAVE_ABSEIL @@ -419,7 +374,7 @@ int main() for( auto const& x: times ) { - std::cout << std::setw( 34 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n"; + std::cout << std::setw( 25 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n"; } } From 2afd1c5c9a63af345385943bedce8d1fb9224403 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 25 Oct 2022 14:45:38 +0200 Subject: [PATCH 274/279] copied Neon group15::is_sentinel from foa_unordered_rc.hpp (possible performance impact) --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index f2867074..a120e7da 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -305,7 +305,7 @@ struct group15 inline bool is_sentinel(std::size_t pos)const { BOOST_ASSERT(pos Date: Tue, 25 Oct 2022 09:01:38 -0700 Subject: [PATCH 275/279] Decorate containers with more BOOST_FORCEINLINE --- include/boost/unordered/detail/foa.hpp | 2 + .../boost/unordered/unordered_flat_map.hpp | 52 +++++++++++++------ .../boost/unordered/unordered_flat_set.hpp | 39 ++++++++++---- 3 files changed, 68 insertions(+), 25 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index a120e7da..df9dba2b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1299,6 +1299,7 @@ public: > void erase(iterator pos)noexcept{return erase(const_iterator(pos));} + BOOST_FORCEINLINE void erase(const_iterator pos)noexcept { destroy_element(pos.p); @@ -1307,6 +1308,7 @@ public: } template + BOOST_FORCEINLINE auto erase(Key&& x) -> typename std::enable_if< !std::is_convertible::value&& !std::is_convertible::value, std::size_t>::type diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index aa39fcfd..5d4fc28f 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -26,6 +26,12 @@ namespace boost { namespace unordered { + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4714) /* marked as __forceinline not inlined */ +#endif + template class unordered_flat_map { @@ -220,7 +226,7 @@ namespace boost { void clear() noexcept { table_.clear(); } template - auto insert(Ty&& value) + BOOST_FORCEINLINE auto insert(Ty&& value) -> decltype(table_.insert(std::forward(value))) { return table_.insert(std::forward(value)); @@ -232,19 +238,19 @@ namespace boost { } template - auto insert(const_iterator, Ty&& value) + BOOST_FORCEINLINE auto insert(const_iterator, Ty&& value) -> decltype(table_.insert(std::forward(value)).first) { return table_.insert(std::forward(value)).first; } - iterator insert(const_iterator, init_type&& value) + BOOST_FORCEINLINE iterator insert(const_iterator, init_type&& value) { return table_.insert(std::move(value)).first; } template - void insert(InputIterator first, InputIterator last) + BOOST_FORCEINLINE void insert(InputIterator first, InputIterator last) { for (auto pos = first; pos != last; ++pos) { table_.emplace(*pos); @@ -292,44 +298,52 @@ namespace boost { .first; } - template std::pair emplace(Args&&... args) + template + BOOST_FORCEINLINE std::pair emplace(Args&&... args) { return table_.emplace(std::forward(args)...); } template - iterator emplace_hint(const_iterator, Args&&... args) + BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args) { - return this->emplace(std::forward(args)...).first; + return table_.emplace(std::forward(args)...).first; } template - std::pair try_emplace(key_type const& key, Args&&... args) + BOOST_FORCEINLINE std::pair try_emplace( + key_type const& key, Args&&... args) { return table_.try_emplace(key, std::forward(args)...); } template - std::pair try_emplace(key_type&& key, Args&&... args) + BOOST_FORCEINLINE std::pair try_emplace( + key_type&& key, Args&&... args) { return table_.try_emplace(std::move(key), std::forward(args)...); } template - iterator try_emplace(const_iterator, key_type const& key, Args&&... args) + BOOST_FORCEINLINE iterator try_emplace( + const_iterator, key_type const& key, Args&&... args) { return table_.try_emplace(key, std::forward(args)...).first; } template - iterator try_emplace(const_iterator, key_type&& key, Args&&... args) + BOOST_FORCEINLINE iterator try_emplace( + const_iterator, key_type&& key, Args&&... args) { return table_.try_emplace(std::move(key), std::forward(args)...) .first; } - void erase(iterator pos) { table_.erase(pos); } - void erase(const_iterator pos) { return table_.erase(pos); } + BOOST_FORCEINLINE void erase(iterator pos) { table_.erase(pos); } + BOOST_FORCEINLINE void erase(const_iterator pos) + { + return table_.erase(pos); + } iterator erase(const_iterator first, const_iterator last) { while (first != last) { @@ -338,10 +352,13 @@ namespace boost { return iterator{detail::foa::const_iterator_cast_tag{}, last}; } - size_type erase(key_type const& key) { return table_.erase(key); } + BOOST_FORCEINLINE size_type erase(key_type const& key) + { + return table_.erase(key); + } template - typename std::enable_if< + BOOST_FORCEINLINE typename std::enable_if< detail::transparent_non_iterable::value, size_type>::type erase(K const& key) @@ -591,6 +608,11 @@ namespace boost { { return erase_if(map.table_, pred); } + +#if defined(BOOST_MSVC) +#pragma warning(pop) /* C4714 */ +#endif + } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index a58151bb..1950dfb3 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -24,6 +24,12 @@ namespace boost { namespace unordered { + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4714) /* marked as __forceinline not inlined */ +#endif + template class unordered_flat_set { @@ -201,22 +207,23 @@ namespace boost { void clear() noexcept { table_.clear(); } - std::pair insert(value_type const& value) + BOOST_FORCEINLINE std::pair insert( + value_type const& value) { return table_.insert(value); } - std::pair insert(value_type&& value) + BOOST_FORCEINLINE std::pair insert(value_type&& value) { return table_.insert(std::move(value)); } - iterator insert(const_iterator, value_type const& value) + BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value) { return table_.insert(value).first; } - iterator insert(const_iterator, value_type&& value) + BOOST_FORCEINLINE iterator insert(const_iterator, value_type&& value) { return table_.insert(std::move(value)).first; } @@ -234,18 +241,22 @@ namespace boost { this->insert(ilist.begin(), ilist.end()); } - template std::pair emplace(Args&&... args) + template + BOOST_FORCEINLINE std::pair emplace(Args&&... args) { return table_.emplace(std::forward(args)...); } template - iterator emplace_hint(const_iterator, Args&&... args) + BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args) { - return this->emplace(std::forward(args)...).first; + return table_.emplace(std::forward(args)...).first; } - void erase(const_iterator pos) { return table_.erase(pos); } + BOOST_FORCEINLINE void erase(const_iterator pos) + { + return table_.erase(pos); + } iterator erase(const_iterator first, const_iterator last) { while (first != last) { @@ -254,10 +265,13 @@ namespace boost { return iterator{detail::foa::const_iterator_cast_tag{}, last}; } - size_type erase(key_type const& key) { return table_.erase(key); } + BOOST_FORCEINLINE size_type erase(key_type const& key) + { + return table_.erase(key); + } template - typename std::enable_if< + BOOST_FORCEINLINE typename std::enable_if< detail::transparent_non_iterable::value, size_type>::type erase(K const& key) @@ -469,6 +483,11 @@ namespace boost { { return erase_if(set.table_, pred); } + +#if defined(BOOST_MSVC) +#pragma warning(pop) /* C4714 */ +#endif + } // namespace unordered } // namespace boost From 49fc08b93426a515f915a1e0e32f11d81d06eed3 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 25 Oct 2022 19:48:19 +0200 Subject: [PATCH 276/279] refactored emplace_impl to improve inlining --- include/boost/unordered/detail/foa.hpp | 47 ++++++++++++++++---------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index df9dba2b..142dda06 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1595,24 +1595,10 @@ private: }; } else{ - /* strong exception guarantee -> try insertion before rehash */ - auto new_arrays_=new_arrays( - std::size_t(std::ceil(static_cast(size_+1)/mlf))); - BOOST_TRY{ - it=nosize_unchecked_emplace_at( - new_arrays_,position_for(hash,new_arrays_), - hash,std::forward(args)...); - } - BOOST_CATCH(...){ - delete_arrays(new_arrays_); - BOOST_RETHROW - } - BOOST_CATCH_END - - /* new_arrays_ lifetime taken care of by unchecked_rehash */ - unchecked_rehash(new_arrays_); - ++size_; - return {it,true}; + return { + unchecked_emplace_with_rehash(hash,std::forward(args)...), + true + }; } } @@ -1621,6 +1607,31 @@ private: return size_policy::size(size_index_for(n))*N-1; } + template + BOOST_NOINLINE iterator + unchecked_emplace_with_rehash(std::size_t hash,Args&&... args) + { + /* strong exception guarantee -> try insertion before rehash */ + auto new_arrays_=new_arrays( + std::size_t(std::ceil(static_cast(size_+1)/mlf))); + iterator it; + BOOST_TRY{ + it=nosize_unchecked_emplace_at( + new_arrays_,position_for(hash,new_arrays_), + hash,std::forward(args)...); + } + BOOST_CATCH(...){ + delete_arrays(new_arrays_); + BOOST_RETHROW + } + BOOST_CATCH_END + + /* new_arrays_ lifetime taken care of by unchecked_rehash */ + unchecked_rehash(new_arrays_); + ++size_; + return it; + } + BOOST_NOINLINE void unchecked_rehash(std::size_t n) { auto new_arrays_=new_arrays(n); From d12ed06c3d700237c6a1056bcf18268745583279 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 25 Oct 2022 19:53:03 +0200 Subject: [PATCH 277/279] removed #ifdef'd out code --- include/boost/unordered/detail/foa.hpp | 32 -------------------------- 1 file changed, 32 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 142dda06..d1a2aedf 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1749,37 +1749,6 @@ private: return res; } -#if 0 - template - iterator nosize_unchecked_emplace_at( - const arrays_type& arrays_,std::size_t pos0,std::size_t hash, - Args&&... args) - { - auto pn=insert_position(arrays_,pos0,hash); - auto &pos=pn.first; - auto &n=pn.second; - auto pg=arrays_.groups+pos; - auto p=arrays_.elements+pos*N+n; - construct_element(p,std::forward(args)...); - pg->set(n,hash); - return {pg,n,p}; - } - - std::pair - static insert_position( - const arrays_type& arrays_,std::size_t pos0,std::size_t hash) - { - for(prober pb(pos0);;pb.next(arrays_.groups_size_mask)){ - auto pos=pb.get(); - auto pg=arrays_.groups+pos; - auto mask=pg->match_available(); - if(BOOST_LIKELY(mask!=0)){ - return {pos,unchecked_countr_zero(mask)}; - } - else pg->mark_overflow(hash); - } - } -#else template iterator nosize_unchecked_emplace_at( const arrays_type& arrays_,std::size_t pos0,std::size_t hash, @@ -1799,7 +1768,6 @@ private: else pg->mark_overflow(hash); } } -#endif template std::size_t erase_if_impl(Predicate pr) From fb315252b39b37f9e502854e66a4e4b12e1e0cd7 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 25 Oct 2022 19:53:18 +0200 Subject: [PATCH 278/279] added missing BOOST_FORCEINLINE --- include/boost/unordered/unordered_flat_map.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 5d4fc28f..dd464eb2 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -232,7 +232,7 @@ namespace boost { return table_.insert(std::forward(value)); } - std::pair insert(init_type&& value) + BOOST_FORCEINLINE std::pair insert(init_type&& value) { return table_.insert(std::move(value)); } From 5e639a97a44b8b3b030cb1523ae91b45fad7aadc Mon Sep 17 00:00:00 2001 From: joaquintides Date: Wed, 26 Oct 2022 10:39:34 +0200 Subject: [PATCH 279/279] passed BOOST_UNORDERED_ASSUME a true boolean --- include/boost/unordered/detail/foa.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index d1a2aedf..ec74aa5b 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -721,7 +721,7 @@ inline unsigned int unchecked_countr_zero(int x) _BitScanForward(&r,(unsigned long)x); return (unsigned int)r; #else - BOOST_UNORDERED_ASSUME(x); + BOOST_UNORDERED_ASSUME(x!=0); return (unsigned int)boost::core::countr_zero((unsigned int)x); #endif }