[map] Allow invalid items to be pointer to static object

By derefencing them when necessary.

Also, we do not rely on trivially-copyable, so remove that assertion.
This commit is contained in:
Behdad Esfahbod 2022-01-13 13:33:07 -07:00
parent 98b26eedf5
commit 985b63b3ee
2 changed files with 18 additions and 17 deletions

View File

@ -211,8 +211,11 @@ struct
} }
HB_FUNCOBJ (hb_bool); HB_FUNCOBJ (hb_bool);
template <typename T> T hb_coerce (const T v) { return v; } template <typename T>
template <typename T> T hb_coerce (const T *v) { return *v; } T hb_coerce (const T v) { return v; }
template <typename T, typename V,
hb_enable_if (!hb_is_same (hb_decay<T>, hb_decay<V>) && hb_is_pointer(V))>
T hb_coerce (const V v) { return *v; }
struct struct
{ {

View File

@ -61,8 +61,6 @@ struct hb_hashmap_t
hb_copy (o, *this); hb_copy (o, *this);
} }
static_assert (std::is_trivially_copyable<K>::value, "");
static_assert (std::is_trivially_copyable<V>::value, "");
static_assert (std::is_trivially_destructible<K>::value, ""); static_assert (std::is_trivially_destructible<K>::value, "");
static_assert (std::is_trivially_destructible<V>::value, ""); static_assert (std::is_trivially_destructible<V>::value, "");
@ -75,9 +73,9 @@ struct hb_hashmap_t
void clear () void clear ()
{ {
new (hb_addressof (key)) K (); new (hb_addressof (key)) K ();
key = kINVALID; key = hb_coerce<K> (kINVALID);
new (hb_addressof (value)) V (); new (hb_addressof (value)) V ();
value = vINVALID; value = hb_coerce<V> (vINVALID);
hash = 0; hash = 0;
} }
@ -85,19 +83,19 @@ struct hb_hashmap_t
bool operator == (const item_t &o) { return *this == o.key; } bool operator == (const item_t &o) { return *this == o.key; }
bool is_unused () const bool is_unused () const
{ {
const K inv = kINVALID; const K inv = hb_coerce<K> (kINVALID);
return key == inv; return key == inv;
} }
bool is_tombstone () const bool is_tombstone () const
{ {
const K kinv = kINVALID; const K kinv = hb_coerce<K> (kINVALID);
const V vinv = vINVALID; const V vinv = hb_coerce<V> (vINVALID);
return key != kinv && value == vinv; return key != kinv && value == vinv;
} }
bool is_real () const bool is_real () const
{ {
const K kinv = kINVALID; const K kinv = hb_coerce<K> (kINVALID);
const V vinv = vINVALID; const V vinv = hb_coerce<V> (vINVALID);
return key != kinv && value != vinv; return key != kinv && value != vinv;
} }
hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); } hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
@ -196,12 +194,12 @@ struct hb_hashmap_t
V get (K key) const V get (K key) const
{ {
if (unlikely (!items)) return vINVALID; if (unlikely (!items)) return hb_coerce<V> (vINVALID);
unsigned int i = bucket_for (key); unsigned int i = bucket_for (key);
return items[i].is_real () && items[i] == key ? items[i].value : vINVALID; return items[i].is_real () && items[i] == key ? items[i].value : hb_coerce<V> (vINVALID);
} }
void del (K key) { set (key, vINVALID); } void del (K key) { set (key, hb_coerce<V> (vINVALID)); }
/* Has interface. */ /* Has interface. */
typedef V value_t; typedef V value_t;
@ -210,7 +208,7 @@ struct hb_hashmap_t
{ {
V v = (*this)[k]; V v = (*this)[k];
if (vp) *vp = v; if (vp) *vp = v;
const V vinv = vINVALID; const V vinv = hb_coerce<V> (vINVALID);
return v != vinv; return v != vinv;
} }
/* Projection. */ /* Projection. */
@ -266,12 +264,12 @@ struct hb_hashmap_t
bool set_with_hash (K key, uint32_t hash, VV&& value) bool set_with_hash (K key, uint32_t hash, VV&& value)
{ {
if (unlikely (!successful)) return false; if (unlikely (!successful)) return false;
const K kinv = kINVALID; const K kinv = hb_coerce<K> (kINVALID);
if (unlikely (key == kinv)) return true; if (unlikely (key == kinv)) return true;
if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
unsigned int i = bucket_for_hash (key, hash); unsigned int i = bucket_for_hash (key, hash);
const V vinv = vINVALID; const V vinv = hb_coerce<V> (vINVALID);
if (value == vinv && items[i].key != key) if (value == vinv && items[i].key != key)
return true; /* Trying to delete non-existent key. */ return true; /* Trying to delete non-existent key. */