[ClassDef2] Use a faster algorithm in subset()

Speedup across the board; up to 40% for MPlus1 at small sizes.
This commit is contained in:
Behdad Esfahbod 2022-11-29 20:29:58 -07:00
parent ae5e6d562b
commit 9b7617d433
1 changed files with 55 additions and 11 deletions

View File

@ -1530,6 +1530,11 @@ struct ClassDefFormat1_3
return classValue[(unsigned int) (glyph_id - startGlyph)];
}
unsigned get_population () const
{
return classValue.len;
}
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
@ -1744,6 +1749,14 @@ struct ClassDefFormat2_4
return rangeRecord.bsearch (glyph_id).value;
}
unsigned get_population () const
{
typename Types::large_int ret = 0;
for (const auto &r : rangeRecord)
ret += r.get_population ();
return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
}
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,
@ -1807,28 +1820,46 @@ struct ClassDefFormat2_4
{
TRACE_SUBSET (this);
const hb_map_t &glyph_map = *c->plan->glyph_map_gsub;
const hb_set_t &glyph_set = *c->plan->glyphset_gsub ();
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass;
hb_set_t orig_klasses;
unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
unsigned count = rangeRecord.len;
for (unsigned i = 0; i < count; i++)
if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2
< get_population ())
{
unsigned klass = rangeRecord.arrayZ[i].value;
if (!klass) continue;
hb_codepoint_t start = rangeRecord.arrayZ[i].first;
hb_codepoint_t end = hb_min (rangeRecord.arrayZ[i].last + 1, num_source_glyphs);
for (hb_codepoint_t g = start; g < end; g++)
for (hb_codepoint_t g : glyph_set)
{
hb_codepoint_t new_gid = glyph_map[g];
unsigned klass = get_class (g);
if (!klass) continue;
hb_codepoint_t new_gid = glyph_map[g];
if (new_gid == HB_MAP_VALUE_INVALID) continue;
if (glyph_filter && !glyph_filter->has (g)) continue;
if (glyph_filter && !glyph_filter->has (g)) continue;
glyph_and_klass.push (hb_pair (new_gid, klass));
orig_klasses.add (klass);
}
}
else
{
unsigned num_source_glyphs = c->plan->source->get_num_glyphs ();
unsigned count = rangeRecord.len;
for (unsigned i = 0; i < count; i++)
{
unsigned klass = rangeRecord.arrayZ[i].value;
if (!klass) continue;
hb_codepoint_t start = rangeRecord.arrayZ[i].first;
hb_codepoint_t end = hb_min (rangeRecord.arrayZ[i].last + 1, num_source_glyphs);
for (hb_codepoint_t g = start; g < end; g++)
{
hb_codepoint_t new_gid = glyph_map[g];
if (new_gid == HB_MAP_VALUE_INVALID) continue;
if (glyph_filter && !glyph_filter->has (g)) continue;
glyph_and_klass.push (hb_pair (new_gid, klass));
orig_klasses.add (klass);
}
}
}
const hb_set_t& glyphset = *c->plan->glyphset_gsub ();
unsigned glyph_count = glyph_filter
@ -2018,6 +2049,19 @@ struct ClassDef
}
}
unsigned get_population () const
{
switch (u.format) {
case 1: return u.format1.get_population ();
case 2: return u.format2.get_population ();
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_population ();
case 4: return u.format4.get_population ();
#endif
default:return NOT_COVERED;
}
}
template<typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)