parameterized group15 and core

This commit is contained in:
joaquintides
2023-03-11 18:36:09 +01:00
committed by Christian Mazakas
parent b33b354818
commit 3a8bea9e1d
2 changed files with 91 additions and 45 deletions

View File

@@ -22,6 +22,7 @@
#include <boost/core/pointer_traits.hpp>
#include <boost/cstdint.hpp>
#include <boost/predef.h>
#include <boost/static_assert.hpp>
#include <boost/type_traits/has_trivial_copy.hpp>
#include <boost/type_traits/is_nothrow_swappable.hpp>
#include <boost/unordered/detail/narrow_cast.hpp>
@@ -158,6 +159,7 @@ static constexpr std::size_t default_bucket_count=0;
#if defined(BOOST_UNORDERED_SSE2)
template<template<typename> class IntegralWrapper>
struct group15
{
static constexpr int N=15;
@@ -168,7 +170,11 @@ 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 initialize()
{
_mm_store_si128(
reinterpret_cast<__m128i*>(m),_mm_setzero_si128());
}
inline void set(std::size_t pos,std::size_t hash)
{
@@ -200,13 +206,14 @@ struct group15
static inline void reset(unsigned char* pc)
{
*pc=available_;
*reinterpret_cast<slot_type*>(pc)=available_;
}
inline int match(std::size_t hash)const
{
auto w=_mm_load_si128(reinterpret_cast<const __m128i*>(m));
return _mm_movemask_epi8(
_mm_cmpeq_epi8(m,_mm_set1_epi32(match_word(hash))))&0x7FFF;
_mm_cmpeq_epi8(w,_mm_set1_epi32(match_word(hash))))&0x7FFF;
}
inline bool is_not_overflowed(std::size_t hash)const
@@ -218,12 +225,7 @@ struct group15
inline void mark_overflow(std::size_t hash)
{
#if BOOST_WORKAROUND(BOOST_GCC,>=50000 && BOOST_GCC<60000)
overflow()=static_cast<unsigned char>(
overflow()|static_cast<unsigned char>(1<<(hash%8)));
#else
overflow()|=static_cast<unsigned char>(1<<(hash%8));
#endif
}
static inline bool maybe_caused_overflow(unsigned char* pc)
@@ -235,13 +237,14 @@ struct group15
inline int match_available()const
{
auto w=_mm_load_si128(reinterpret_cast<const __m128i*>(m));
return _mm_movemask_epi8(
_mm_cmpeq_epi8(m,_mm_setzero_si128()))&0x7FFF;
_mm_cmpeq_epi8(w,_mm_setzero_si128()))&0x7FFF;
}
static inline bool is_occupied(unsigned char* pc)noexcept
{
return *pc!=available_;
return *reinterpret_cast<slot_type*>(pc)!=available_;
}
inline int match_occupied()const
@@ -255,6 +258,9 @@ struct group15
}
private:
using slot_type=IntegralWrapper<unsigned char>;
BOOST_STATIC_ASSERT(sizeof(slot_type)==1);
static constexpr unsigned char available_=0,
sentinel_=1;
@@ -304,31 +310,32 @@ private:
return narrow_cast<unsigned char>(match_word(hash));
}
inline unsigned char& at(std::size_t pos)
inline slot_type& at(std::size_t pos)
{
return reinterpret_cast<unsigned char*>(&m)[pos];
return m[pos];
}
inline unsigned char at(std::size_t pos)const
inline const slot_type& at(std::size_t pos)const
{
return reinterpret_cast<const unsigned char*>(&m)[pos];
return m[pos];
}
inline unsigned char& overflow()
inline slot_type& overflow()
{
return at(N);
}
inline unsigned char overflow()const
inline const slot_type& overflow()const
{
return at(N);
}
alignas(16) __m128i m;
alignas(16) slot_type m[16];
};
#elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON)
template<template<typename> class IntegralWrapper>
struct group15
{
static constexpr int N=15;
@@ -339,7 +346,10 @@ 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=vdupq_n_s8(0);}
inline void initialize()
{
vst1q_u8(reinterpret_cast<uint8_t*>(m),vdupq_n_s8(0));
}
inline void set(std::size_t pos,std::size_t hash)
{
@@ -360,7 +370,7 @@ struct group15
static inline bool is_sentinel(unsigned char* pc)noexcept
{
return *pc==sentinel_;
return *reinterpret_cast<slot_type*>(pc)==sentinel_;
}
inline void reset(std::size_t pos)
@@ -371,13 +381,14 @@ struct group15
static inline void reset(unsigned char* pc)
{
*pc=available_;
*reinterpret_cast<slot_type*>(pc)=available_;
}
inline int match(std::size_t hash)const
{
return simde_mm_movemask_epi8(vceqq_s8(
m,vdupq_n_s8(static_cast<signed char>(reduced_hash(hash)))))&0x7FFF;
vld1q_u8(reinterpret_cast<const uint8_t*>(m)),
vdupq_n_s8(static_cast<signed char>(reduced_hash(hash)))))&0x7FFF;
}
inline bool is_not_overflowed(std::size_t hash)const
@@ -401,18 +412,21 @@ struct group15
inline int match_available()const
{
return simde_mm_movemask_epi8(vceqq_s8(m,vdupq_n_s8(0)))&0x7FFF;
return simde_mm_movemask_epi8(vceqq_s8(
vld1q_u8(reinterpret_cast<const uint8_t*>(m)),
vdupq_n_s8(0)))&0x7FFF;
}
static inline bool is_occupied(unsigned char* pc)noexcept
{
return *pc!=available_;
return *reinterpret_cast<slot_typ<EFBFBD>*>(pc)!=available_;
}
inline int match_occupied()const
{
return simde_mm_movemask_epi8(
vcgtq_u8(vreinterpretq_u8_s8(m),vdupq_n_u8(0)))&0x7FFF;
return simde_mm_movemask_epi8(vcgtq_u8(
vreinterpretq_u8_s8(vld1q_u8(reinterpret_cast<const uint8_t*>(m))),
vdupq_n_u8(0)))&0x7FFF;
}
inline int match_really_occupied()const /* excluding sentinel */
@@ -421,6 +435,9 @@ struct group15
}
private:
using slot_type=IntegralWrapper<unsigned char>;
BOOST_STATIC_ASSERT(sizeof(slot_type)==1);
static constexpr unsigned char available_=0,
sentinel_=1;
@@ -473,31 +490,32 @@ private:
#endif
}
inline unsigned char& at(std::size_t pos)
inline slot_type& at(std::size_t pos)
{
return reinterpret_cast<unsigned char*>(&m)[pos];
return m[pos];
}
inline unsigned char at(std::size_t pos)const
inline const slot_type& at(std::size_t pos)const
{
return reinterpret_cast<const unsigned char*>(&m)[pos];
return m[pos];
}
inline unsigned char& overflow()
inline slot_type& overflow()
{
return at(N);
}
inline unsigned char overflow()const
inline const slot_type& overflow()const
{
return at(N);
}
alignas(16) int8x16_t m;
alignas(16) slot_type m[16];
};
#else /* non-SIMD */
template<template<typename> class IntegralWrapper>
struct group15
{
static constexpr int N=15;
@@ -590,6 +608,9 @@ struct group15
}
private:
using word_type=IntegralWrapper<uint64_t>;
BOOST_STATIC_ASSERT(sizeof(slot_type)==1);
static constexpr unsigned char available_=0,
sentinel_=1;
@@ -624,7 +645,7 @@ private:
set_impl(m[1],pos,n>>4);
}
static inline void set_impl(boost::uint64_t& x,std::size_t pos,std::size_t n)
static inline void set_impl(word_type& x,std::size_t pos,std::size_t n)
{
static constexpr boost::uint64_t mask[]=
{
@@ -670,7 +691,7 @@ private:
return y&0x7FFF;
}
alignas(16) boost::uint64_t m[2];
alignas(16) word_type m[2];
};
#endif
@@ -1064,7 +1085,10 @@ struct try_emplace_args_t{};
#pragma warning(disable:4702)
#endif
template<typename TypePolicy,typename Hash,typename Pred,typename Allocator>
template<
typename TypePolicy,typename Group,typename Hash,typename Pred,
typename Allocator
>
class
#if defined(_MSC_VER)&&_MSC_FULL_VER>=190023918
@@ -1075,7 +1099,7 @@ table_core:empty_value<Hash,0>,empty_value<Pred,1>,empty_value<Allocator,2>
{
public:
using type_policy=TypePolicy;
using group_type=group15;
using group_type=Group;
static constexpr auto N=group_type::N;
using size_policy=pow2_size_policy;
using prober=pow2_quadratic_prober;
@@ -1103,8 +1127,8 @@ public:
using locator=table_locator<group_type,element_type>;
table_core(
std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(),
const Allocator& al_=Allocator()):
std::size_t n=default_bucket_count,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{initial_max_load()}
@@ -1576,7 +1600,8 @@ public:
std::size_t ml;
private:
template<typename,typename,typename,typename> friend class table_core;
template<typename,typename,typename,typename,typename>
friend class table_core;
using hash_base=empty_value<Hash,0>;
using pred_base=empty_value<Pred,1>;

View File

@@ -14,6 +14,7 @@
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/unordered/detail/foa/core.hpp>
#include <cstddef>
#include <iterator>
@@ -26,6 +27,24 @@ namespace unordered{
namespace detail{
namespace foa{
template<typename Integral>
struct plain_integral
{
operator Integral()const{return n;}
void operator=(Integral m){n=m;}
void operator|=(Integral m)
{
#if BOOST_WORKAROUND(BOOST_GCC,>=50000 && BOOST_GCC<60000)
n=static_cast<Integral>(n|m);
#else
n|=m;
#endif
}
Integral n;
};
template<typename,typename,typename,typename>
class table;
@@ -81,7 +100,8 @@ public:
const_iterator_cast_tag, const table_iterator<TypePolicy,Group,true>& x):
pc{x.pc},p{x.p}{}
inline reference operator*()const noexcept{return type_policy::value_from(*p);}
inline reference operator*()const noexcept
{return type_policy::value_from(*p);}
inline pointer operator->()const noexcept
{return std::addressof(type_policy::value_from(*p));}
inline table_iterator& operator++()noexcept{increment();return *this;}
@@ -181,7 +201,7 @@ union uninitialized_storage
/* foa::table interface departs in a number of ways from that of C++ unordered
* associative containers because it's not for end-user consumption
* (boost::unordered_[flat|node]_[map|set]) wrappers complete it as
* (boost::unordered_[flat|node]_[map|set] wrappers complete it as
* appropriate).
*
* The table supports two main modes of operation: flat and node-based. In the
@@ -208,9 +228,10 @@ union uninitialized_storage
#include <boost/unordered/detail/foa/ignore_wshadow.hpp>
template<typename TypePolicy,typename Hash,typename Pred,typename Allocator>
class table:table_core<TypePolicy,Hash,Pred,Allocator>
class table:table_core<TypePolicy,group15<plain_integral>,Hash,Pred,Allocator>
{
using super=table_core<TypePolicy,Hash,Pred,Allocator>;
using super=
table_core<TypePolicy,group15<plain_integral>,Hash,Pred,Allocator>;
using type_policy=typename super::type_policy;
using group_type=typename super::group_type;
using super::N;
@@ -244,8 +265,8 @@ public:
const_iterator>::type;
table(
std::size_t n=0,const Hash& h_=Hash(),const Pred& pred_=Pred(),
const Allocator& al_=Allocator()):
std::size_t n=default_bucket_count,const Hash& h_=Hash(),
const Pred& pred_=Pred(),const Allocator& al_=Allocator()):
super{n,h_,pred_,al_}
{}