[set] Compute is_subset by comparing pages.

Test subsets one page at a time instead of by codepoints. On my machine
this is about 250x faster than the previous implementation.
This commit is contained in:
Kurt Kartaltepe 2021-05-19 00:34:09 -07:00 committed by Behdad Esfahbod
parent 1dffb55361
commit 2000f47ae5
2 changed files with 90 additions and 7 deletions

View File

@ -506,14 +506,44 @@ struct hb_set_t
bool is_subset (const hb_set_t *larger_set) const
{
if (get_population () > larger_set->get_population ())
return false;
if (unlikely(larger_set->is_empty ()))
{
return is_empty ();
}
/* TODO Optimize to use pages. */
hb_codepoint_t c = INVALID;
while (next (&c))
if (!larger_set->has (c))
uint32_t spi = 0;
for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set->page_map.length; lpi++)
{
uint32_t spm = page_map[spi].major;
uint32_t lpm = larger_set->page_map[lpi].major;
auto sp = page_at (spi);
auto lp = larger_set->page_at (lpi);
if (spm < lpm && !sp.is_empty ())
{
return false;
}
if (lpm < spm)
{
continue;
}
for (int j = 0; j < ARRAY_LENGTH_CONST (sp.v); j++)
{
if ((~lp.v[j] & sp.v[j]) != 0) { return false; }
}
spi++;
}
while (spi < page_map.length)
{
if (!page_at (spi++).is_empty ())
{
return false;
}
}
return true;
}

View File

@ -215,6 +215,58 @@ static void test_set_union (void)
hb_set_destroy (u);
}
static void
test_set_subsets (void)
{
hb_set_t *s = hb_set_create ();
hb_set_t *l = hb_set_create ();
hb_set_add (l, 0x0FFFF);
hb_set_add (s, 0x1FFFF);
g_assert (!hb_set_is_subset (s, l));
hb_set_clear (s);
hb_set_add (s, 0x0FFF0);
g_assert (!hb_set_is_subset (s, l));
hb_set_clear (s);
hb_set_add (s, 0x0AFFF);
g_assert (!hb_set_is_subset (s, l));
hb_set_clear (s);
g_assert (hb_set_is_subset (s, l));
hb_set_clear (l);
g_assert (hb_set_is_subset (s, l));
hb_set_add (s, 0x1FFFF);
g_assert (!hb_set_is_subset (s, l));
hb_set_clear (s);
hb_set_add (s, 0xFF);
hb_set_add (s, 0x1FFFF);
hb_set_add (s, 0x2FFFF);
hb_set_add (l, 0xFF);
hb_set_add (l, 0x1FFFF);
hb_set_add (l, 0x2FFFF);
g_assert (hb_set_is_subset (s, l));
hb_set_del (l, 0xFF);
g_assert (!hb_set_is_subset (s, l));
hb_set_add (l, 0xFF);
hb_set_del (l, 0x2FFFF);
g_assert (!hb_set_is_subset (s, l));
hb_set_add (l, 0x2FFFF);
hb_set_del (l, 0x1FFFF);
g_assert (!hb_set_is_subset (s, l));
hb_set_destroy (s);
hb_set_destroy (l);
}
static void
test_set_algebra (void)
{
@ -528,6 +580,7 @@ main (int argc, char **argv)
hb_test_init (&argc, &argv);
hb_test_add (test_set_basic);
hb_test_add (test_set_subsets);
hb_test_add (test_set_algebra);
hb_test_add (test_set_iter);
hb_test_add (test_set_empty);