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