[set] Cache population

Part of https://github.com/harfbuzz/harfbuzz/issues/1017
This commit is contained in:
Behdad Esfahbod 2018-05-01 18:27:41 -04:00
parent 93b03119da
commit bd5f918e2f
2 changed files with 24 additions and 1 deletions

View File

@ -189,12 +189,14 @@ struct hb_set_t
hb_object_header_t header; hb_object_header_t header;
ASSERT_POD (); ASSERT_POD ();
bool in_error; bool in_error;
mutable unsigned int population;
hb_prealloced_array_t<page_map_t, 8> page_map; hb_prealloced_array_t<page_map_t, 8> page_map;
hb_prealloced_array_t<page_t, 1> pages; hb_prealloced_array_t<page_t, 1> pages;
inline void init (void) inline void init (void)
{ {
in_error = false; in_error = false;
population = 0;
page_map.init (); page_map.init ();
pages.init (); pages.init ();
} }
@ -220,6 +222,7 @@ struct hb_set_t
if (unlikely (hb_object_is_inert (this))) if (unlikely (hb_object_is_inert (this)))
return; return;
in_error = false; in_error = false;
population = 0;
page_map.resize (0); page_map.resize (0);
pages.resize (0); pages.resize (0);
} }
@ -231,10 +234,13 @@ struct hb_set_t
return true; return true;
} }
inline void dirty (void) { population = (unsigned int) -1; }
inline void add (hb_codepoint_t g) inline void add (hb_codepoint_t g)
{ {
if (unlikely (in_error)) return; if (unlikely (in_error)) return;
if (unlikely (g == INVALID)) return; if (unlikely (g == INVALID)) return;
dirty ();
page_t *page = page_for_insert (g); if (unlikely (!page)) return; page_t *page = page_for_insert (g); if (unlikely (!page)) return;
page->add (g); page->add (g);
} }
@ -242,6 +248,7 @@ struct hb_set_t
{ {
if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */ if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
if (unlikely (a > b || a == INVALID || b == INVALID)) return false; if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
dirty ();
unsigned int ma = get_major (a); unsigned int ma = get_major (a);
unsigned int mb = get_major (b); unsigned int mb = get_major (b);
if (ma == mb) if (ma == mb)
@ -271,6 +278,7 @@ struct hb_set_t
{ {
if (unlikely (in_error)) return; if (unlikely (in_error)) return;
if (!count) return; if (!count) return;
dirty ();
hb_codepoint_t g = *array; hb_codepoint_t g = *array;
while (count) while (count)
{ {
@ -296,6 +304,7 @@ struct hb_set_t
{ {
if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */ if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
if (!count) return true; if (!count) return true;
dirty ();
hb_codepoint_t g = *array; hb_codepoint_t g = *array;
hb_codepoint_t last_g = g; hb_codepoint_t last_g = g;
while (count) while (count)
@ -325,6 +334,7 @@ struct hb_set_t
page_t *p = page_for (g); page_t *p = page_for (g);
if (!p) if (!p)
return; return;
dirty ();
p->del (g); p->del (g);
} }
inline void del_range (hb_codepoint_t a, hb_codepoint_t b) inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
@ -353,13 +363,18 @@ struct hb_set_t
unsigned int count = other->pages.len; unsigned int count = other->pages.len;
if (!resize (count)) if (!resize (count))
return; return;
population = other->population;
memcpy (pages.array, other->pages.array, count * sizeof (pages.array[0])); memcpy (pages.array, other->pages.array, count * sizeof (pages.array[0]));
memcpy (page_map.array, other->page_map.array, count * sizeof (page_map.array[0])); memcpy (page_map.array, other->page_map.array, count * sizeof (page_map.array[0]));
} }
inline bool is_equal (const hb_set_t *other) const inline bool is_equal (const hb_set_t *other) const
{ {
if (population != (unsigned int) -1 &&
other->population != (unsigned int) -1 &&
population != other->population)
return false;
unsigned int na = pages.len; unsigned int na = pages.len;
unsigned int nb = other->pages.len; unsigned int nb = other->pages.len;
@ -387,6 +402,8 @@ struct hb_set_t
{ {
if (unlikely (in_error)) return; if (unlikely (in_error)) return;
dirty ();
unsigned int na = pages.len; unsigned int na = pages.len;
unsigned int nb = other->pages.len; unsigned int nb = other->pages.len;
unsigned int next_page = na; unsigned int next_page = na;
@ -592,10 +609,15 @@ struct hb_set_t
inline unsigned int get_population (void) const inline unsigned int get_population (void) const
{ {
if (population != (unsigned int) -1)
return population;
unsigned int pop = 0; unsigned int pop = 0;
unsigned int count = pages.len; unsigned int count = pages.len;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
pop += pages[i].get_population (); pop += pages[i].get_population ();
population = pop;
return pop; return pop;
} }
inline hb_codepoint_t get_min (void) const inline hb_codepoint_t get_min (void) const

View File

@ -53,6 +53,7 @@ hb_set_create (void)
static const hb_set_t _hb_set_nil = { static const hb_set_t _hb_set_nil = {
HB_OBJECT_HEADER_STATIC, HB_OBJECT_HEADER_STATIC,
true, /* in_error */ true, /* in_error */
0, /* population */
{0} /* elts */ {0} /* elts */
}; };