[map] Track population and occupancy separately

This commit is contained in:
Behdad Esfahbod 2018-05-29 17:00:02 -07:00
parent 8a978790cb
commit 686476a8ae
2 changed files with 22 additions and 9 deletions

View File

@ -57,6 +57,7 @@ struct hb_map_t
hb_object_header_t header; hb_object_header_t header;
ASSERT_POD (); ASSERT_POD ();
bool in_error; bool in_error;
unsigned int population; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */ unsigned int occupancy; /* Including tombstones. */
unsigned int mask; unsigned int mask;
unsigned int prime; unsigned int prime;
@ -65,6 +66,7 @@ struct hb_map_t
inline void init_shallow (void) inline void init_shallow (void)
{ {
in_error = false; in_error = false;
population = 0;
occupancy = 0; occupancy = 0;
mask = 0; mask = 0;
prime = 0; prime = 0;
@ -89,7 +91,7 @@ struct hb_map_t
{ {
if (unlikely (in_error)) return false; if (unlikely (in_error)) return false;
unsigned int power = _hb_bit_storage (occupancy * 2 + 8) - 1; unsigned int power = _hb_bit_storage (population * 2 + 8) - 1;
unsigned int new_size = 1u << power; unsigned int new_size = 1u << power;
item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t)); item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
if (unlikely (!new_items)) if (unlikely (!new_items))
@ -103,6 +105,7 @@ struct hb_map_t
item_t *old_items = items; item_t *old_items = items;
/* Switch to new, empty, array. */ /* Switch to new, empty, array. */
population = 0;
occupancy = 0; occupancy = 0;
mask = new_size - 1; mask = new_size - 1;
prime = prime_for (power); prime = prime_for (power);
@ -121,14 +124,26 @@ struct hb_map_t
inline void set (hb_codepoint_t key, hb_codepoint_t value) inline void set (hb_codepoint_t key, hb_codepoint_t value)
{ {
if (unlikely (in_error)) return; if (unlikely (in_error)) return;
if (unlikely (key == INVALID)) 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 (items[i].key != key)
if (value == INVALID && items[i].key != key)
return; /* Trying to delete non-existent key. */
/* Accounting. */
if (items[i].is_tombstone ())
occupancy--;
else if (!items[i].is_unused ())
{ {
if (items[i].key == INVALID && key != INVALID) population--;
occupancy++; occupancy--;
items[i].key = key;
} }
occupancy++;
if (value != INVALID)
population++;
items[i].key = key;
items[i].value = value; items[i].value = value;
} }
inline hb_codepoint_t get (hb_codepoint_t key) const inline hb_codepoint_t get (hb_codepoint_t key) const
@ -141,10 +156,7 @@ struct hb_map_t
inline void del (hb_codepoint_t key) inline void del (hb_codepoint_t key)
{ {
if (unlikely (in_error)) return; set (key, INVALID);
if (unlikely (!items)) return;
unsigned int i = bucket_for (key);
items[i].value = INVALID;
} }
inline bool has (hb_codepoint_t key) const inline bool has (hb_codepoint_t key) const
{ {

View File

@ -53,6 +53,7 @@ hb_map_create (void)
static const hb_map_t _hb_map_nil = { static const hb_map_t _hb_map_nil = {
HB_OBJECT_HEADER_STATIC, HB_OBJECT_HEADER_STATIC,
true, /* in_error */ true, /* in_error */
0, /* population */
0, /* occupancy */ 0, /* occupancy */
0, /* mask */ 0, /* mask */
0, /* prime */ 0, /* prime */