[map] Templatize hb_map_t

Template name is hb_hashmap_t<K,V>.
This commit is contained in:
Behdad Esfahbod 2019-03-30 14:30:22 -07:00
parent 4b7f4dbc0c
commit c98f51da71
1 changed files with 37 additions and 28 deletions

View File

@ -31,22 +31,28 @@
/*
* hb_map_t
* hb_hashmap_t
*/
struct hb_map_t
template <typename K, typename V,
K kINVALID = hb_is_pointer (K) ? 0 : (K) -1,
V vINVALID = hb_is_pointer (V) ? 0 : (V) -1>
struct hb_hashmap_t
{
HB_NO_COPY_ASSIGN (hb_map_t);
hb_map_t () { init (); }
~hb_map_t () { fini (); }
HB_NO_COPY_ASSIGN (hb_hashmap_t);
hb_hashmap_t () { init (); }
~hb_hashmap_t () { fini (); }
static_assert (hb_is_integer (K) || hb_is_pointer (K), "");
static_assert (hb_is_integer (V) || hb_is_pointer (V), "");
struct item_t
{
hb_codepoint_t key;
hb_codepoint_t value;
K key;
V value;
bool is_unused () const { return key == INVALID; }
bool is_tombstone () const { return key != INVALID && value == INVALID; }
bool is_unused () const { return key == kINVALID; }
bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
};
hb_object_header_t header;
@ -110,7 +116,7 @@ struct hb_map_t
/* Insert back old items. */
if (old_items)
for (unsigned int i = 0; i < old_size; i++)
if (old_items[i].key != INVALID && old_items[i].value != INVALID)
if (old_items[i].key != kINVALID && old_items[i].value != vINVALID)
set (old_items[i].key, old_items[i].value);
free (old_items);
@ -118,14 +124,14 @@ struct hb_map_t
return true;
}
void set (hb_codepoint_t key, hb_codepoint_t value)
void set (K key, V value)
{
if (unlikely (!successful)) return;
if (unlikely (key == INVALID)) return;
if (unlikely (key == kINVALID)) return;
if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
unsigned int i = bucket_for (key);
if (value == INVALID && items[i].key != key)
if (value == vINVALID && items[i].key != key)
return; /* Trying to delete non-existent key. */
if (!items[i].is_unused ())
@ -143,24 +149,22 @@ struct hb_map_t
population++;
}
hb_codepoint_t get (hb_codepoint_t key) const
V get (K key) const
{
if (unlikely (!items)) return INVALID;
if (unlikely (!items)) return vINVALID;
unsigned int i = bucket_for (key);
return items[i].key == key ? items[i].value : INVALID;
return items[i].key == key ? items[i].value : vINVALID;
}
void del (hb_codepoint_t key) { set (key, INVALID); }
static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
void del (K key) { set (key, vINVALID); }
/* Has interface. */
static constexpr hb_codepoint_t SENTINEL = INVALID;
typedef hb_codepoint_t value_t;
value_t operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
static constexpr V SENTINEL = vINVALID;
typedef V value_t;
value_t operator [] (K k) const { return get (k); }
bool has (K k) const { return (*this)[k] != SENTINEL; }
/* Projection. */
hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
V operator () (K k) const { return get (k); }
void clear ()
{
@ -174,20 +178,20 @@ struct hb_map_t
protected:
unsigned int bucket_for (hb_codepoint_t key) const
unsigned int bucket_for (K key) const
{
unsigned int i = hb_hash (key) % prime;
unsigned int step = 0;
unsigned int tombstone = INVALID;
unsigned int tombstone = (unsigned) -1;
while (!items[i].is_unused ())
{
if (items[i].key == key)
return i;
if (tombstone == INVALID && items[i].is_tombstone ())
if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
tombstone = i;
i = (i + ++step) & mask;
}
return tombstone == INVALID ? i : tombstone;
return tombstone == (unsigned) -1 ? i : tombstone;
}
static unsigned int prime_for (unsigned int shift)
@ -242,5 +246,10 @@ struct hb_map_t
}
};
struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
hb_codepoint_t,
HB_MAP_VALUE_INVALID,
HB_MAP_VALUE_INVALID> {};
#endif /* HB_MAP_HH */