169  constexpr static float EMH_DEFAULT_LOAD_FACTOR = 0.80f;
 
  170  constexpr static float EMH_MIN_LOAD_FACTOR = 0.25f; 
 
  171  constexpr static uint32_t EMH_CACHE_LINE_SIZE = 64; 
 
  175  using htype = HashTableMap2<KeyT, ValueT, HashT, EqT>;
 
  176  using value_type = std::pair<KeyT, ValueT>;
 
  177  using key_type = KeyT;
 
  178  using mapped_type = ValueT;
 
  179  using hasher = HashT;
 
  180  using key_equal = EqT;
 
  182  constexpr static size_type INACTIVE = 0xFFFFFFFF;
 
  183  constexpr static size_type END = 0xFFFFFFFF;
 
  190    using iterator_category = std::bidirectional_iterator_tag;
 
  191    using difference_type = std::ptrdiff_t;
 
  192    using value_type = 
typename htype::value_type;
 
  193    using pointer = value_type*;
 
  194    using const_pointer = 
const value_type*;
 
  195    using reference = value_type&;
 
  196    using const_reference = 
const value_type&;
 
  206    iterator(
const htype* hash_map, size_type bucket)
 
  208      kv_ = hash_map->m_pairs + (int)bucket;
 
  211    iterator& operator++()
 
  217    iterator operator++(
int)
 
  224    iterator& operator--()
 
  230    iterator operator--(
int)
 
  237    reference operator*()
 const { 
return *kv_; }
 
  238    pointer operator->()
 const { 
return kv_; }
 
  240    bool operator==(
const iterator& rhs)
 const { 
return kv_ == rhs.kv_; }
 
  241    bool operator!=(
const iterator& rhs)
 const { 
return kv_ != rhs.kv_; }
 
  242    bool operator==(
const const_iterator& rhs)
 const { 
return kv_ == rhs.kv_; }
 
  243    bool operator!=(
const const_iterator& rhs)
 const { 
return kv_ != rhs.kv_; }
 
 
  254    using iterator_category = std::bidirectional_iterator_tag;
 
  255    using value_type = 
typename htype::value_type;
 
  256    using difference_type = std::ptrdiff_t;
 
  257    using pointer = value_type*;
 
  258    using const_pointer = 
const value_type*;
 
  259    using reference = value_type&;
 
  260    using const_reference = 
const value_type&;
 
  267    const_iterator(
const htype* hash_map, size_type bucket)
 
  269      kv_ = hash_map->m_pairs + (int)bucket;
 
  272    const_iterator& operator++()
 
  278    const_iterator operator++(
int)
 
  285    const_iterator& operator--()
 
  291    const_iterator operator--(
int)
 
  298    const_reference operator*()
 const { 
return *kv_; }
 
  299    const_pointer operator->()
 const { 
return kv_; }
 
  301    bool operator==(
const iterator& rhs)
 const { 
return kv_ == rhs.kv_; }
 
  302    bool operator!=(
const iterator& rhs)
 const { 
return kv_ != rhs.kv_; }
 
  303    bool operator==(
const const_iterator& rhs)
 const { 
return kv_ == rhs.kv_; }
 
  304    bool operator!=(
const const_iterator& rhs)
 const { 
return kv_ != rhs.kv_; }
 
  308    const value_type* kv_;
 
 
  311  void init(size_type bucket, 
float mlf = EMH_DEFAULT_LOAD_FACTOR)
 
  315    m_mask = m_num_buckets = 0;
 
  317    m_mlf = (uint32_t)((1 << 27) / EMH_DEFAULT_LOAD_FACTOR);
 
  318    max_load_factor(mlf);
 
  327  HashTableMap2(
const HashTableMap2& rhs)
 
  329    if (rhs.load_factor() > EMH_MIN_LOAD_FACTOR) {
 
  330      m_pairs = _allocBucket((
size_type)(rhs.m_num_buckets * rhs.max_load_factor()) + 4);
 
  331      _allocIndex(rhs.m_num_buckets);
 
  335      init(rhs.m_num_filled + 2, rhs.max_load_factor());
 
  336      for (
auto it = rhs.begin(); it != rhs.end(); ++it)
 
  337        insert_unique(it->first, it->second);
 
  341  HashTableMap2(HashTableMap2&& rhs) 
noexcept 
  344    *
this = std::move(rhs);
 
  347  HashTableMap2(std::initializer_list<value_type> ilist)
 
  349    init((size_type)ilist.size());
 
  350    for (
auto it = ilist.begin(); it != ilist.end(); ++it)
 
  354  template <
class InputIt>
 
  355  HashTableMap2(InputIt first, InputIt last, size_type bucket_count = 4)
 
  357    init(std::distance(first, last) + bucket_count);
 
  358    for (; first != last; ++first)
 
  362  HashTableMap2& operator=(
const HashTableMap2& rhs)
 
  367    if (rhs.load_factor() < EMH_MIN_LOAD_FACTOR) {
 
  370      rehash(rhs.m_num_filled + 2);
 
  371      for (
auto it = rhs.begin(); it != rhs.end(); ++it)
 
  372        insert_unique(it->first, it->second);
 
  378    if (m_num_buckets != rhs.m_num_buckets) {
 
  381      _allocIndex(rhs.m_num_buckets);
 
  382      m_pairs = _allocBucket((size_type)(rhs.m_num_buckets * rhs.max_load_factor()) + 4);
 
  389  HashTableMap2& operator=(HashTableMap2&& rhs) 
noexcept 
  398  template <
typename Con>
 
  399  bool operator==(
const Con& rhs)
 const 
  401    if (size() != rhs.size())
 
  404    for (
auto it = begin(), last = end(); it != last; ++it) {
 
  405      auto oi = rhs.find(it->first);
 
  406      if (oi == rhs.end() || it->second != oi->second)
 
  412  template <
typename Con>
 
  413  bool operator!=(
const Con& rhs)
 const 
  415    return !(*
this == rhs);
 
  418  ~HashTableMap2() noexcept
 
  425  void clone(
const HashTableMap2& rhs)
 
  428    m_hasher = rhs.m_hasher;
 
  429    m_pairs_allocated_size = rhs.m_pairs_allocated_size;
 
  431    auto opairs = rhs.m_pairs;
 
  432    memcpy((
char*)m_index, (
char*)rhs.m_index, (m_num_buckets + EAD) * 
sizeof(
Index));
 
  434    if (is_copy_trivially()) {
 
  435      memcpy((
char*)m_pairs, (
char*)opairs, m_num_filled * 
sizeof(value_type));
 
  438      for (size_type slot = 0; slot < m_num_filled; slot++)
 
  439        new (m_pairs + slot) value_type(opairs[slot]);
 
  443  void swap(HashTableMap2& rhs)
 
  446    std::swap(m_hasher, rhs.m_hasher);
 
  447    std::swap(m_pairs, rhs.m_pairs);
 
  448    std::swap(m_pairs_allocated_size, rhs.m_pairs_allocated_size);
 
  458    return { 
this, m_num_filled - 1 };
 
  465  const value_type& front()
 const 
  471    return m_pairs[m_num_filled - 1];
 
  473  const value_type& back()
 const 
  475    return m_pairs[m_num_filled - 1];
 
  502    return { 
this, m_num_filled };
 
  506    return { 
this, m_num_filled };
 
  513  const value_type* values()
 const 
  517  const Index* index()
 const 
  522  size_type size()
 const 
  528    return m_num_filled == 0;
 
  530  size_type bucket_count()
 const 
  532    return m_num_buckets;
 
  538    return static_cast<double>(m_num_filled) / (m_mask + 1);
 
 
  541  HashT& hash_function()
 const 
  550  void max_load_factor(
double mlf)
 
  552    if (mlf < 0.992 && mlf > EMH_MIN_LOAD_FACTOR) {
 
  553      m_mlf = (uint32_t)((1 << 27) / mlf);
 
  554      if (m_num_buckets > 0)
 
  555        rehash(m_num_buckets);
 
  559  constexpr double max_load_factor()
 const 
  561    return (1 << 27) / 
static_cast<double>(m_mlf);
 
  563  constexpr size_type max_size()
 const 
  565    return (1ull << (
sizeof(size_type) * 8 - 1));
 
  567  constexpr size_type max_bucket_count()
 const 
  573  template <
typename K = KeyT>
 
  574  iterator find(
const K& key) 
noexcept 
  576    return { 
this, find_filled_slot(key) };
 
  579  template <
typename K = KeyT>
 
  582    return { 
this, find_filled_slot(key) };
 
  585  template <
typename K = KeyT>
 
  586  ValueT& at(
const K& key)
 
  588    const auto slot = find_filled_slot(key);
 
  590    return m_pairs[slot].second;
 
  593  template <
typename K = KeyT>
 
  594  const ValueT& at(
const K& key)
 const 
  596    const auto slot = find_filled_slot(key);
 
  598    return m_pairs[slot].second;
 
  601  const ValueT& index(
const uint32_t index)
 const 
  603    return m_pairs[index].second;
 
  606  ValueT& index(
const uint32_t index)
 
  608    return m_pairs[index].second;
 
  611  template <
typename K = KeyT>
 
  612  bool contains(
const K& key) 
const noexcept 
  614    return find_filled_slot(key) != m_num_filled;
 
  617  template <
typename K = KeyT>
 
  618  size_type count(
const K& key) 
const noexcept 
  620    return find_filled_slot(key) == m_num_filled ? 0 : 1;
 
  623  template <
typename K = KeyT>
 
  624  std::pair<iterator, iterator> equal_range(
const K& key)
 
  626    const auto found = find(key);
 
  627    if (found.second == m_num_filled)
 
  628      return { found, found };
 
  630      return { found, std::next(found) };
 
  633  void merge(HashTableMap2& rhs)
 
  636      *
this = std::move(rhs);
 
  640    for (
auto rit = rhs.begin(); rit != rhs.end();) {
 
  641      auto fit = find(rit->first);
 
  643        insert_unique(rit->first, std::move(rit->second));
 
  644        rit = rhs.erase(rit);
 
  652  std::pair<iterator, bool> add(
const KeyT& key, 
const ValueT& value)
 
  654    return insert(std::make_pair(key, value));
 
  657  std::pair<iterator, bool> insert(
const value_type& p)
 
  663  std::pair<iterator, bool> insert(value_type&& p)
 
  666    return _doInsert(std::move(p));
 
  669  void insert(std::initializer_list<value_type> ilist)
 
  671    reserve(ilist.size() + m_num_filled, 
false);
 
  672    for (
auto it = ilist.begin(); it != ilist.end(); ++it)
 
  676  template <
typename Iter>
 
  677  void insert(Iter first, Iter last)
 
  679    reserve(std::distance(first, last) + m_num_filled, 
false);
 
  680    for (; first != last; ++first)
 
  681      _doInsert(first->first, first->second);
 
  684  template <
class... Args>
 
  685  std::pair<iterator, bool> emplace(Args&&... args) 
noexcept 
  688    return _doInsert(std::forward<Args>(args)...);
 
  692  template <
class... Args>
 
  697    return _doInsert(std::forward<Args>(args)...).first;
 
  700  template <
class... Args>
 
  701  std::pair<iterator, bool> try_emplace(
const KeyT& k, Args&&... args)
 
  704    return _doInsert(k, std::forward<Args>(args)...);
 
  707  template <
class... Args>
 
  708  std::pair<iterator, bool> try_emplace(KeyT&& k, Args&&... args)
 
  711    return _doInsert(std::move(k), std::forward<Args>(args)...);
 
  714  template <
class... Args>
 
  715  size_type emplace_unique(Args&&... args)
 
  717    return insert_unique(std::forward<Args>(args)...);
 
  720  std::pair<iterator, bool> insert_or_assign(
const KeyT& key, ValueT&& val)
 
  722    return do_assign(key, std::forward<ValueT>(val));
 
  724  std::pair<iterator, bool> insert_or_assign(KeyT&& key, ValueT&& val)
 
  726    return do_assign(std::move(key), std::forward<ValueT>(val));
 
  730  ValueT 
set_get(
const KeyT& key, 
const ValueT& val)
 
  733    const auto key_hash = hash_key(key);
 
  734    const auto bucket = _findOrAllocate(key, key_hash);
 
  735    if (EMH_EMPTY(bucket)) {
 
  736      EMH_NEW(key, val, bucket, key_hash);
 
  740      const auto slot = m_index[bucket].slot & m_mask;
 
  741      ValueT old_value(val);
 
  742      std::swap(m_pairs[slot].second, old_value);
 
 
  751    const auto key_hash = hash_key(key);
 
  752    const auto bucket = _findOrAllocate(key, key_hash);
 
  753    if (EMH_EMPTY(bucket)) {
 
  755      EMH_NEW(key, std::move(ValueT()), bucket, key_hash);
 
  758    const auto slot = m_index[bucket].slot & m_mask;
 
  759    return m_pairs[slot].second;
 
 
  765    const auto key_hash = hash_key(key);
 
  766    const auto bucket = _findOrAllocate(key, key_hash);
 
  767    if (EMH_EMPTY(bucket)) {
 
  768      EMH_NEW(std::move(key), std::move(ValueT()), bucket, key_hash);
 
  771    const auto slot = m_index[bucket].slot & m_mask;
 
  772    return m_pairs[slot].second;
 
  777  size_type 
erase(
const KeyT& key) 
noexcept 
  779    const auto key_hash = hash_key(key);
 
  780    const auto sbucket = find_filled_bucket(key, key_hash);
 
  781    if (sbucket == INACTIVE)
 
  784    const auto main_bucket = key_hash & m_mask;
 
  785    erase_slot(sbucket, (size_type)main_bucket);
 
 
  790  iterator 
erase(
const const_iterator& cit) 
noexcept 
  792    const auto slot = (
size_type)(cit.kv_ - m_pairs);
 
  794    const auto sbucket = find_slot_bucket(slot, main_bucket); 
 
  795    erase_slot(sbucket, main_bucket);
 
  796    return { 
this, slot };
 
  800  iterator 
erase(const_iterator first, const_iterator last) 
noexcept 
  802    auto esize = long(last.kv_ - first.kv_);
 
  803    auto tsize = long((m_pairs + m_num_filled) - last.kv_); 
 
  805    while (tsize-- > 0) {
 
  808      next = ++
erase(next);
 
  814      next = --
erase(next);
 
  816    return { 
this, size_type(next.kv_ - m_pairs) };
 
  819  template <
typename Pred>
 
  820  size_type erase_if(Pred pred)
 
  822    auto old_size = size();
 
  823    for (
auto it = begin(); it != end();) {
 
  829    return old_size - size();
 
  832  static constexpr bool is_triviall_destructable()
 
  834#if __cplusplus >= 201402L || _MSC_VER > 1600 
  835    return !(std::is_trivially_destructible<KeyT>::value && std::is_trivially_destructible<ValueT>::value);
 
  837    return !(std::is_pod<KeyT>::value && std::is_pod<ValueT>::value);
 
  841  static constexpr bool is_copy_trivially()
 
  843#if __cplusplus >= 201103L || _MSC_VER > 1600 
  844    return (std::is_trivially_copyable<KeyT>::value && std::is_trivially_copyable<ValueT>::value);
 
  846    return (std::is_pod<KeyT>::value && std::is_pod<ValueT>::value);
 
  855    if (m_num_filled > 0)
 
  856      memset((
char*)m_index, INACTIVE, 
sizeof(m_index[0]) * m_num_buckets);
 
  858    m_last = m_num_filled = 0;
 
 
  863  void shrink_to_fit(
const float min_factor = EMH_DEFAULT_LOAD_FACTOR / 4)
 
  865    if (
load_factor() < min_factor && bucket_count() > 10) 
 
  866      rehash(m_num_filled + 1);
 
  874    const auto required_buckets = num_elems * m_mlf >> 27;
 
  875    if (EMH_LIKELY(required_buckets < m_mask)) 
 
  879    rehash(required_buckets + 2);
 
 
  885    if (m_num_filled != required_buckets)
 
  886      return reserve(required_buckets, 
true);
 
  890    memset((
char*)m_index, INACTIVE, 
sizeof(m_index[0]) * m_num_buckets);
 
  891    for (
size_type slot = 0; slot < m_num_filled; slot++) {
 
  892      const auto& key = m_pairs[slot].first;
 
  893      const auto key_hash = hash_key(key);
 
  894      const auto bucket = 
size_type(key_hash & m_mask);
 
  895      auto& next_bucket = m_index[bucket].next;
 
  896      if ((
int)next_bucket < 0)
 
  897        m_index[bucket] = { 1, slot | ((
size_type)(key_hash) & ~m_mask) };
 
  899        m_index[bucket].slot |= (
size_type)(key_hash) & ~m_mask;
 
  906  void rehash(uint64_t required_buckets)
 
  908    if (required_buckets < m_num_filled)
 
  911    assert(required_buckets < max_size());
 
  912    auto num_buckets = m_num_filled > (1u << 16) ? (1u << 16) : 4u;
 
  913    while (num_buckets < required_buckets) {
 
  918    m_mask = num_buckets - 1;
 
  921    num_buckets += num_buckets * EMH_PACK_TAIL / 100; 
 
  923    m_num_buckets = num_buckets;
 
  925    rebuild(num_buckets);
 
  928    for (size_type slot = 0; slot < m_num_filled; ++slot) {
 
  929      const auto& key = m_pairs[slot].first;
 
  930      const auto key_hash = hash_key(key);
 
  931      const auto bucket = _findUniqueBucket(key_hash);
 
  932      m_index[bucket] = { bucket, slot | ((size_type)(key_hash) & ~m_mask) };
 
  940    if (is_triviall_destructable()) {
 
  941      while (m_num_filled--)
 
  942        m_pairs[m_num_filled].~value_type();
 
  946  void rebuild(size_type num_buckets) 
noexcept 
  949    auto new_pairs = _allocBucket((size_type)(num_buckets * max_load_factor()) + 4);
 
  950    if (is_copy_trivially()) {
 
  952        memcpy((
char*)new_pairs, (
char*)m_pairs, m_num_filled * 
sizeof(value_type));
 
  955      for (size_type slot = 0; slot < m_num_filled; slot++) {
 
  956        new (new_pairs + slot) value_type(std::move(m_pairs[slot]));
 
  957        if (is_triviall_destructable())
 
  958          m_pairs[slot].~value_type();
 
  963    _allocIndex(num_buckets);
 
  965    memset((
char*)m_index, INACTIVE, 
sizeof(m_index[0]) * num_buckets);
 
  966    memset((
char*)(m_index + num_buckets), 0, 
sizeof(m_index[0]) * EAD);
 
  969  void pack_zero(ValueT zero)
 
  971    m_pairs[m_num_filled] = { KeyT(), zero };
 
  975  bool try_get(
const KeyT& key, ValueT& val) 
const noexcept 
  977    const auto slot = find_filled_slot(key);
 
  978    const auto found = slot != m_num_filled;
 
  980      val = m_pairs[slot].second;
 
  986  ValueT* try_get(
const KeyT& key) 
noexcept 
  988    const auto slot = find_filled_slot(key);
 
  989    return slot != m_num_filled ? &m_pairs[slot].second : 
nullptr;
 
  993  ValueT* try_get(
const KeyT& key) 
const noexcept 
  995    const auto slot = find_filled_slot(key);
 
  996    return slot != m_num_filled ? &m_pairs[slot].second : 
nullptr;
 
 1000  bool try_set(
const KeyT& key, 
const ValueT& val) 
noexcept 
 1002    const auto slot = find_filled_slot(key);
 
 1003    if (slot == m_num_filled)
 
 1006    m_pairs[slot].second = val;
 
 1011  bool try_set(
const KeyT& key, ValueT&& val) 
noexcept 
 1013    const auto slot = find_filled_slot(key);
 
 1014    if (slot == m_num_filled)
 
 1017    m_pairs[slot].second = std::move(val);
 
 1022  ValueT get_or_return_default(
const KeyT& key) 
const noexcept 
 1024    const auto slot = find_filled_slot(key);
 
 1025    return slot == m_num_filled ? ValueT() : m_pairs[slot].second;
 
 1029  std::pair<iterator, bool> _doInsert(
const value_type& value) 
noexcept 
 1031    const auto key_hash = hash_key(value.first);
 
 1032    const auto bucket = _findOrAllocate(value.first, key_hash);
 
 1033    const auto bempty = EMH_EMPTY(bucket);
 
 1035      EMH_NEW(value.first, value.second, bucket, key_hash);
 
 1038    const auto slot = m_index[bucket].slot & m_mask;
 
 1039    return { { 
this, slot }, bempty };
 
 1042  std::pair<iterator, bool> _doInsert(value_type&& value) 
noexcept 
 1044    const auto key_hash = hash_key(value.first);
 
 1045    const auto bucket = _findOrAllocate(value.first, key_hash);
 
 1046    const auto bempty = EMH_EMPTY(bucket);
 
 1048      EMH_NEW(std::move(value.first), std::move(value.second), bucket, key_hash);
 
 1051    const auto slot = m_index[bucket].slot & m_mask;
 
 1052    return { { 
this, slot }, bempty };
 
 1055  template <
typename K, 
typename V>
 
 1056  std::pair<iterator, bool> _doInsert(K&& key, V&& val) 
noexcept 
 1058    const auto key_hash = hash_key(key);
 
 1059    const auto bucket = _findOrAllocate(key, key_hash);
 
 1060    const auto bempty = EMH_EMPTY(bucket);
 
 1062      EMH_NEW(std::forward<K>(key), std::forward<V>(val), bucket, key_hash);
 
 1065    const auto slot = m_index[bucket].slot & m_mask;
 
 1066    return { { 
this, slot }, bempty };
 
 1069  template <
typename K, 
typename V>
 
 1070  std::pair<iterator, bool> do_assign(K&& key, V&& val) 
noexcept 
 1072    check_expand_need();
 
 1073    const auto key_hash = hash_key(key);
 
 1074    const auto bucket = _findOrAllocate(key, key_hash);
 
 1075    const auto bempty = EMH_EMPTY(bucket);
 
 1077      EMH_NEW(std::forward<K>(key), std::forward<V>(val), bucket, key_hash);
 
 1080      m_pairs[m_index[bucket].slot & m_mask].second = std::forward(val);
 
 1083    const auto slot = m_index[bucket].slot & m_mask;
 
 1084    return { { 
this, slot }, bempty };
 
 1087  template <
typename K, 
typename V>
 
 1088  size_type insert_unique(K&& key, V&& val)
 
 1090    check_expand_need();
 
 1091    const auto key_hash = hash_key(key);
 
 1092    auto bucket = _findUniqueBucket(key_hash);
 
 1093    EMH_NEW(std::forward<K>(key), std::forward<V>(val), bucket, key_hash);
 
 1097  size_type insert_unique(value_type&& value)
 
 1099    return insert_unique(std::move(value.first), std::move(value.second));
 
 1102  size_type insert_unique(
const value_type& value)
 
 1104    return insert_unique(value.first, value.second);
 
 1108  bool check_expand_need()
 
 1110    return reserve(m_num_filled, 
false);
 
 1113  static void prefetch_heap_block(
char* ctrl)
 
 1118    __builtin_prefetch(
static_cast<const void*
>(ctrl));
 
 1126  size_type slot_to_bucket(
const size_type slot) 
const noexcept 
 1128    size_type main_bucket;
 
 1129    return find_slot_bucket(slot, main_bucket); 
 
 1133  void erase_slot(
const size_type sbucket, 
const size_type main_bucket) 
noexcept 
 1135    const auto slot = m_index[sbucket].slot & m_mask;
 
 1136    const auto ebucket = erase_bucket(sbucket, main_bucket);
 
 1137    const auto last_slot = --m_num_filled;
 
 1138    if (EMH_LIKELY(slot != last_slot)) {
 
 1139      const auto last_bucket = (m_etail == INACTIVE || ebucket == m_etail)
 
 1140      ? slot_to_bucket(last_slot)
 
 1143      m_pairs[slot] = std::move(m_pairs[last_slot]);
 
 1144      m_index[last_bucket].slot = slot | (m_index[last_bucket].slot & ~m_mask);
 
 1147    if (is_triviall_destructable())
 
 1148      m_pairs[last_slot].~value_type();
 
 1151    m_index[ebucket] = { INACTIVE, 0 };
 
 1154  size_type erase_bucket(
const size_type bucket, 
const size_type main_bucket) 
noexcept 
 1156    const auto next_bucket = m_index[bucket].next;
 
 1157    if (bucket == main_bucket) {
 
 1158      if (main_bucket != next_bucket) {
 
 1159        const auto nbucket = m_index[next_bucket].next;
 
 1160        m_index[main_bucket] = {
 
 1161          (nbucket == next_bucket) ? main_bucket : nbucket,
 
 1162          m_index[next_bucket].slot
 
 1168    const auto prev_bucket = find_prev_bucket(main_bucket, bucket);
 
 1169    m_index[prev_bucket].next = (bucket == next_bucket) ? prev_bucket : next_bucket;
 
 1174  size_type find_slot_bucket(
const size_type slot, size_type& main_bucket)
 const 
 1176    const auto key_hash = hash_key(m_pairs[slot].first);
 
 1177    const auto bucket = main_bucket = size_type(key_hash & m_mask);
 
 1178    if (slot == (m_index[bucket].slot & m_mask))
 
 1181    auto next_bucket = m_index[bucket].next;
 
 1183      if (EMH_LIKELY(slot == (m_index[next_bucket].slot & m_mask)))
 
 1185      next_bucket = m_index[next_bucket].next;
 
 1192  size_type find_filled_bucket(
const KeyT& key, uint64_t key_hash) 
const noexcept 
 1194    const auto bucket = size_type(key_hash & m_mask);
 
 1195    auto next_bucket = m_index[bucket].next;
 
 1196    if (EMH_UNLIKELY((
int)next_bucket < 0))
 
 1199    const auto slot = m_index[bucket].slot & m_mask;
 
 1201    if (EMH_EQHASH(bucket, key_hash)) {
 
 1202      if (EMH_LIKELY(m_eq(key, m_pairs[slot].first)))
 
 1205    if (next_bucket == bucket)
 
 1209      if (EMH_EQHASH(next_bucket, key_hash)) {
 
 1210        const auto slot = m_index[next_bucket].slot & m_mask;
 
 1211        if (EMH_LIKELY(m_eq(key, m_pairs[slot].first)))
 
 1215      const auto nbucket = m_index[next_bucket].next;
 
 1216      if (nbucket == next_bucket)
 
 1218      next_bucket = nbucket;
 
 1225  template <
typename K = KeyT>
 
 1226  size_type find_filled_slot(
const K& key) 
const noexcept 
 1228    const auto key_hash = hash_key(key);
 
 1229    const auto bucket = size_type(key_hash & m_mask);
 
 1230    auto next_bucket = m_index[bucket].next;
 
 1231    if ((
int)next_bucket < 0)
 
 1232      return m_num_filled;
 
 1234    const auto slot = m_index[bucket].slot & m_mask;
 
 1236    if (EMH_EQHASH(bucket, key_hash)) {
 
 1237      if (EMH_LIKELY(m_eq(key, m_pairs[slot].first)))
 
 1240    if (next_bucket == bucket)
 
 1241      return m_num_filled;
 
 1244      if (EMH_EQHASH(next_bucket, key_hash)) {
 
 1245        const auto slot = m_index[next_bucket].slot & m_mask;
 
 1246        if (EMH_LIKELY(m_eq(key, m_pairs[slot].first)))
 
 1250      const auto nbucket = m_index[next_bucket].next;
 
 1251      if (nbucket == next_bucket)
 
 1252        return m_num_filled;
 
 1253      next_bucket = nbucket;
 
 1256    return m_num_filled;
 
 1263  size_type kickout_bucket(
const size_type kmain, 
const size_type bucket) 
noexcept 
 1265    const auto next_bucket = m_index[bucket].next;
 
 1266    const auto new_bucket = _findEmptyBucket(next_bucket, 2);
 
 1267    const auto prev_bucket = find_prev_bucket(kmain, bucket);
 
 1269    const auto last = next_bucket == bucket ? new_bucket : next_bucket;
 
 1270    m_index[new_bucket] = { last, m_index[bucket].slot };
 
 1272    m_index[prev_bucket].next = new_bucket;
 
 1273    m_index[bucket].next = INACTIVE;
 
 1285  template <
typename K = KeyT>
 
 1286  size_type _findOrAllocate(
const K& key, uint64_t key_hash) 
noexcept 
 1288    const auto bucket = size_type(key_hash & m_mask);
 
 1289    auto next_bucket = m_index[bucket].next;
 
 1290    prefetch_heap_block((
char*)&m_pairs[bucket]);
 
 1291    if ((
int)next_bucket < 0) {
 
 1295    const auto slot = m_index[bucket].slot & m_mask;
 
 1296    if (EMH_EQHASH(bucket, key_hash))
 
 1297      if (EMH_LIKELY(m_eq(key, m_pairs[slot].first)))
 
 1301    const auto kmain = hash_bucket(m_pairs[slot].first);
 
 1302    if (kmain != bucket)
 
 1303      return kickout_bucket(kmain, bucket);
 
 1304    else if (next_bucket == bucket)
 
 1305      return m_index[next_bucket].next = _findEmptyBucket(next_bucket, 1);
 
 1310      const auto eslot = m_index[next_bucket].slot & m_mask;
 
 1311      if (EMH_EQHASH(next_bucket, key_hash)) {
 
 1312        if (EMH_LIKELY(m_eq(key, m_pairs[eslot].first)))
 
 1317      const auto nbucket = m_index[next_bucket].next;
 
 1318      if (nbucket == next_bucket)
 
 1320      next_bucket = nbucket;
 
 1324    const auto new_bucket = _findEmptyBucket(next_bucket, csize);
 
 1325    prefetch_heap_block((
char*)&m_pairs[new_bucket]);
 
 1326    return m_index[next_bucket].next = new_bucket;
 
 1329  size_type _findUniqueBucket(uint64_t key_hash) 
noexcept 
 1331    const auto bucket = size_type(key_hash & m_mask);
 
 1332    auto next_bucket = m_index[bucket].next;
 
 1333    if ((
int)next_bucket < 0) {
 
 1338    const auto kmain = hash_main(bucket);
 
 1339    if (EMH_UNLIKELY(kmain != bucket))
 
 1340      return kickout_bucket(kmain, bucket);
 
 1341    else if (EMH_UNLIKELY(next_bucket != bucket))
 
 1342      next_bucket = find_last_bucket(next_bucket);
 
 1344    return m_index[next_bucket].next = _findEmptyBucket(next_bucket, 2);
 
 1361  size_type _findEmptyBucket(
const size_type bucket_from, uint32_t csize) 
noexcept 
 1365    auto bucket = bucket_from;
 
 1366    if (EMH_EMPTY(++bucket) || EMH_EMPTY(++bucket))
 
 1370    constexpr size_type linear_probe_length = 2 * EMH_CACHE_LINE_SIZE / 
sizeof(
Index); 
 
 1371    for (size_type offset = csize + 2, step = 4; offset <= linear_probe_length;) {
 
 1372      bucket = (bucket_from + offset) & m_mask;
 
 1373      if (EMH_EMPTY(bucket) || EMH_EMPTY(++bucket))
 
 1378    constexpr size_type quadratic_probe_length = 6u;
 
 1379    for (size_type offset = 4u, step = 3u; step < quadratic_probe_length;) {
 
 1380      bucket = (bucket_from + offset) & m_mask;
 
 1381      if (EMH_EMPTY(bucket) || EMH_EMPTY(++bucket))
 
 1388    __builtin_prefetch(
static_cast<const void*
>(_index + m_last + 1), 0, EMH_PREFETCH);
 
 1393      if (EMH_EMPTY(++m_last)) 
 
 1396      auto medium = (m_num_buckets / 2 + m_last) & m_mask;
 
 1397      if (EMH_EMPTY(medium)) 
 
 1404  size_type find_last_bucket(size_type main_bucket)
 const 
 1406    auto next_bucket = m_index[main_bucket].next;
 
 1407    if (next_bucket == main_bucket)
 
 1411      const auto nbucket = m_index[next_bucket].next;
 
 1412      if (nbucket == next_bucket)
 
 1414      next_bucket = nbucket;
 
 1418  size_type find_prev_bucket(
const size_type main_bucket, 
const size_type bucket)
 const 
 1420    auto next_bucket = m_index[main_bucket].next;
 
 1421    if (next_bucket == bucket)
 
 1425      const auto nbucket = m_index[next_bucket].next;
 
 1426      if (nbucket == bucket)
 
 1428      next_bucket = nbucket;
 
 1432  size_type hash_bucket(
const KeyT& key) 
const noexcept 
 1434    return (size_type)hash_key(key) & m_mask;
 
 1437  size_type hash_main(
const size_type bucket) 
const noexcept 
 1439    const auto slot = m_index[bucket].slot & m_mask;
 
 1440    return (size_type)hash_key(m_pairs[slot].first) & m_mask;
 
 1445  template <typename UType, typename std::enable_if<std::is_integral<UType>::value, uint32_t>::type = 0>
 
 1446  inline uint64_t hash_key(
const UType key)
 const 
 1448    return m_hasher(key);
 
 1451  template <typename UType, typename std::enable_if<std::is_same<UType, std::string>::value, uint32_t>::type = 0>
 
 1452  inline uint64_t hash_key(
const UType& key)
 const 
 1454    return m_hasher(key);
 
 1457  template <typename UType, typename std::enable_if<!std::is_integral<UType>::value && !std::is_same<UType, std::string>::value, uint32_t>::type = 0>
 
 1458  inline uint64_t hash_key(
const UType& key)
 const 
 1460    return m_hasher(key);
 
 1465  value_type* m_pairs = 
nullptr;
 
 1468  Int64 m_pairs_allocated_size = 0;
 
 1472  value_type* _allocBucket(size_type num_buckets)
 
 1474    m_pairs_allocated_size = (uint64_t)num_buckets * 
sizeof(value_type);
 
 1475    AllocatedMemoryInfo mem_info = m_memory_allocator->allocate({}, m_pairs_allocated_size);
 
 1476    return reinterpret_cast<value_type*
>(mem_info.baseAddress());
 
 1481    m_memory_allocator->deallocate({}, { m_pairs, m_pairs_allocated_size });
 
 1483    m_pairs_allocated_size = 0;