diff --git a/src/hb-set.hh b/src/hb-set.hh index 048f09933..822111d59 100644 --- a/src/hb-set.hh +++ b/src/hb-set.hh @@ -89,6 +89,23 @@ struct hb_set_t } } + void del_range (hb_codepoint_t a, hb_codepoint_t b) + { + elt_t *la = &elt (a); + elt_t *lb = &elt (b); + if (la == lb) + *la &= ~((mask (b) << 1) - mask(a)); + else + { + *la &= mask (a) - 1; + la++; + + memset (la, 0, (char *) lb - (char *) la); + + *lb &= ~((mask (b) << 1) - 1); + } + } + bool is_equal (const page_t *other) const { return 0 == hb_memcmp (&v, &other->v, sizeof (v)); @@ -366,14 +383,47 @@ struct hb_set_t dirty (); page->del (g); } + void del_range (hb_codepoint_t a, hb_codepoint_t b) { /* TODO perform op even if !successful. */ - /* TODO Optimize, like add_range(). */ if (unlikely (!successful)) return; - for (unsigned int i = a; i < b + 1; i++) - del (i); + if (unlikely (a > b || a == INVALID || b == INVALID)) return; + dirty (); + unsigned int ma = get_major (a); + unsigned int mb = get_major (b); + unsigned int mds = (a == major_start (ma))? ma: (ma + 1); + int mde = (b + 1 == major_start (mb + 1))? (int)mb: ((int)mb - 1); + if (ma < mds) + { + page_t *page = page_for (a); + if (page) + { + if (ma == mb) + page->del_range (a, b); + else + page->del_range (a, major_start (ma + 1) - 1); + } + } + if (mde < (int)mb && ma != mb) + { + page_t *page = page_for (b); + if (page) + page->del_range (major_start (mb), b); + } + if ((int)mds <= mde) + { + unsigned int write_index = 0; + for (unsigned int i = 0; i < page_map.length; i++) + { + unsigned int m = page_map[i].major; + if (m < mds || mde < (int)m) + page_map[write_index++] = page_map[i]; + } + compact (write_index); + } } + bool get (hb_codepoint_t g) const { const page_t *page = page_for (g); diff --git a/test/api/test-set.c b/test/api/test-set.c index d4e49f753..d80ee8b7d 100644 --- a/test/api/test-set.c +++ b/test/api/test-set.c @@ -470,6 +470,34 @@ test_set_empty (void) hb_set_destroy (b); } +static void +test_set_delrange (void) +{ + hb_set_t *s = hb_set_create (); + + test_empty (s); + for (unsigned int g = 0; g < 2100; g += 10) + hb_set_add (s, g); + + hb_set_add (s, 2047); /* (=512*4-1) edge case */ + + hb_set_del_range (s, 55, 705); + hb_set_del_range (s, 795, 2047); + + g_assert ( hb_set_has (s, 50)); + g_assert (!hb_set_has (s, 60)); + g_assert (!hb_set_has (s, 600)); + g_assert ( hb_set_has (s, 710)); + g_assert ( hb_set_has (s, 790)); + g_assert (!hb_set_has (s, 800)); + g_assert (!hb_set_has (s, 1500)); + g_assert (!hb_set_has (s, 2040)); + g_assert (!hb_set_has (s, 2047)); + g_assert ( hb_set_has (s, 2050)); + + hb_set_destroy (s); +} + int main (int argc, char **argv) { @@ -479,6 +507,7 @@ main (int argc, char **argv) hb_test_add (test_set_algebra); hb_test_add (test_set_iter); hb_test_add (test_set_empty); + hb_test_add (test_set_delrange); hb_test_add (test_set_intersect_empty); hb_test_add (test_set_intersect_page_reduction);