From 2d7de7ce500d2b559e51743c946b05f5d4ea0af5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 10 Nov 2023 19:10:51 -0700 Subject: [PATCH] [set] Speed up next_range() --- src/hb-algs.hh | 2 +- src/hb-bit-page.hh | 36 ++++++++++++++++++++++++----- src/hb-bit-set.hh | 56 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index ea9705716..847e0a492 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -1417,7 +1417,7 @@ struct template constexpr auto operator () (const T &a) const HB_AUTO_RETURN (~a) } -HB_FUNCOBJ (hb_bitwise_neg); +HB_FUNCOBJ (hb_bitwise_not); struct { HB_PARTIALIZE(2); diff --git a/src/hb-bit-page.hh b/src/hb-bit-page.hh index 869c67895..b85d01254 100644 --- a/src/hb-bit-page.hh +++ b/src/hb-bit-page.hh @@ -76,7 +76,7 @@ struct hb_vector_size_t hb_vector_size_t operator ^ (const hb_vector_size_t &o) const { return process (hb_bitwise_xor, o); } hb_vector_size_t operator ~ () const - { return process (hb_bitwise_neg); } + { return process (hb_bitwise_not); } hb_array_t iter () const { return hb_array (v); } @@ -106,6 +106,15 @@ struct hb_bit_page_t | hb_none ; } + bool is_full () const + { + if (has_population ()) return population == PAGE_BITS; + return + + hb_iter (v) + | hb_filter (hb_bitwise_not) + | hb_none + ; + } uint32_t hash () const { return hb_bytes_t ((const char *) &v, sizeof (v)).hash (); @@ -251,7 +260,7 @@ struct hb_bit_page_t return population; } - bool next (hb_codepoint_t *codepoint) const + bool next (hb_codepoint_t *codepoint, unsigned bit = 1) const { unsigned int m = (*codepoint + 1) & MASK; if (!m) @@ -262,12 +271,27 @@ struct hb_bit_page_t unsigned int i = m / ELT_BITS; unsigned int j = m & ELT_MASK; - const elt_t vv = v[i] & ~((elt_t (1) << j) - 1); + elt_t vv; + if (bit) + vv = v[i] & ~((elt_t (1) << j) - 1); + else + vv = v[i] | ((elt_t (1) << j) - 1); for (const elt_t *p = &vv; i < len (); p = &v[++i]) - if (*p) + if (bit) { - *codepoint = i * ELT_BITS + elt_get_min (*p); - return true; + if (*p) + { + *codepoint = i * ELT_BITS + elt_get_min (*p); + return true; + } + } + else + { + if (~*p) + { + *codepoint = i * ELT_BITS + elt_get_min (~*p); + return true; + } } *codepoint = INVALID; diff --git a/src/hb-bit-set.hh b/src/hb-bit-set.hh index 1dbcce5cb..a51266f44 100644 --- a/src/hb-bit-set.hh +++ b/src/hb-bit-set.hh @@ -699,19 +699,59 @@ struct hb_bit_set_t } bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const { - hb_codepoint_t i; - - i = *last; - if (!next (&i)) + *first = *last; + if (!next (first)) { *last = *first = INVALID; return false; } - /* TODO Speed up. */ - *last = *first = i; - while (next (&i) && i == *last + 1) - (*last)++; + const auto* page_map_array = page_map.arrayZ; + unsigned int major = get_major (*first); + unsigned int i = last_page_lookup; + if (unlikely (i >= page_map.length || page_map_array[i].major != major)) + { + page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST); + assert (i < page_map.length); + } + + *last = *first; + if (pages.arrayZ[page_map_array[i].index].next (last, 0)) + { + *last += major * page_t::PAGE_BITS - 1; + return true; + } + else + *last = (major + 1) * page_t::PAGE_BITS - 1; + + for (i++, major++; i < page_map.length; i++, major++) + { + const page_map_t ¤t = page_map_array[i]; + if (current.major != major) + break; + + auto &page = pages.arrayZ[current.index]; + + if (page.is_full ()) + { + *last += page_t::PAGE_BITS; + continue; + } + + if (page.get (0)) + { + hb_codepoint_t x = 0; + if (page.next (&x, 0)) + { + *last += x; + break; + } + else + *last += page_t::PAGE_BITS; + } + else + break; + } return true; }