Merge pull request #3914 from harfbuzz/multimap
[multimap] Add a multimap datastructure & use for gid-to-unicodes subset accelerator
This commit is contained in:
commit
3fb4ea29cd
|
@ -368,6 +368,7 @@ COMPILED_TESTS = \
|
|||
test-iter \
|
||||
test-machinery \
|
||||
test-map \
|
||||
test-multimap \
|
||||
test-number \
|
||||
test-ot-tag \
|
||||
test-priority-queue \
|
||||
|
@ -407,6 +408,10 @@ test_map_SOURCES = test-map.cc hb-static.cc
|
|||
test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_map_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_multimap_SOURCES = test-multimap.cc hb-static.cc
|
||||
test_multimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_multimap_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_number_SOURCES = test-number.cc hb-number.cc
|
||||
test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_number_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
|
|
@ -52,6 +52,7 @@ HB_BASE_sources = \
|
|||
hb-map.hh \
|
||||
hb-meta.hh \
|
||||
hb-ms-feature-ranges.hh \
|
||||
hb-multimap.hh \
|
||||
hb-mutex.hh \
|
||||
hb-null.hh \
|
||||
hb-number.cc \
|
||||
|
|
|
@ -524,6 +524,18 @@ struct hb_pair_t
|
|||
bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
|
||||
bool operator <= (const pair_t& o) const { return !(*this > o); }
|
||||
|
||||
static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
pair_t *a = (pair_t *) pa;
|
||||
pair_t *b = (pair_t *) pb;
|
||||
|
||||
if (a->first < b->first) return -1;
|
||||
if (a->first > b->first) return +1;
|
||||
if (a->second < b->second) return -1;
|
||||
if (a->second > b->second) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
friend void swap (hb_pair_t& a, hb_pair_t& b)
|
||||
{
|
||||
hb_swap (a.first, b.first);
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright © 2022 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_MULTIMAP_HH
|
||||
#define HB_MULTIMAP_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-map.hh"
|
||||
#include "hb-vector.hh"
|
||||
|
||||
|
||||
/*
|
||||
* hb_multimap_t
|
||||
*/
|
||||
|
||||
struct hb_multimap_t
|
||||
{
|
||||
void add (hb_codepoint_t k, hb_codepoint_t v)
|
||||
{
|
||||
hb_codepoint_t *i;
|
||||
if (multiples_indices.has (k, &i))
|
||||
{
|
||||
multiples_values[*i].push (v);
|
||||
return;
|
||||
}
|
||||
|
||||
hb_codepoint_t *old_v;
|
||||
if (singulars.has (k, &old_v))
|
||||
{
|
||||
hb_codepoint_t old = *old_v;
|
||||
singulars.del (k);
|
||||
|
||||
multiples_indices.set (k, multiples_values.length);
|
||||
auto *vec = multiples_values.push ();
|
||||
|
||||
vec->push (old);
|
||||
vec->push (v);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
singulars.set (k, v);
|
||||
}
|
||||
|
||||
hb_array_t<const hb_codepoint_t> get (hb_codepoint_t k) const
|
||||
{
|
||||
hb_codepoint_t *v;
|
||||
if (singulars.has (k, &v))
|
||||
return hb_array (v, 1);
|
||||
|
||||
hb_codepoint_t *i;
|
||||
if (multiples_indices.has (k, &i))
|
||||
return multiples_values[*i].as_array ();
|
||||
|
||||
return hb_array_t<hb_codepoint_t> ();
|
||||
}
|
||||
|
||||
bool in_error () const
|
||||
{
|
||||
return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error ();
|
||||
}
|
||||
|
||||
protected:
|
||||
hb_map_t singulars;
|
||||
hb_map_t multiples_indices;
|
||||
hb_vector_t<hb_vector_t<hb_codepoint_t>> multiples_values;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* HB_MULTIMAP_HH */
|
|
@ -31,6 +31,7 @@
|
|||
#include "hb.hh"
|
||||
|
||||
#include "hb-map.hh"
|
||||
#include "hb-multimap.hh"
|
||||
#include "hb-set.hh"
|
||||
|
||||
extern HB_INTERNAL hb_user_data_key_t _hb_subset_accelerator_user_data_key;
|
||||
|
@ -51,11 +52,12 @@ struct hb_subset_accelerator_t
|
|||
}
|
||||
|
||||
static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
|
||||
const hb_set_t& unicodes_,
|
||||
const hb_multimap_t gid_to_unicodes_,
|
||||
const hb_set_t& unicodes_,
|
||||
bool has_seac_) {
|
||||
hb_subset_accelerator_t* accel =
|
||||
(hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t));
|
||||
new (accel) hb_subset_accelerator_t (unicode_to_gid_, unicodes_);
|
||||
new (accel) hb_subset_accelerator_t (unicode_to_gid_, gid_to_unicodes_, unicodes_);
|
||||
accel->has_seac = has_seac_;
|
||||
return accel;
|
||||
}
|
||||
|
@ -76,8 +78,9 @@ struct hb_subset_accelerator_t
|
|||
}
|
||||
|
||||
hb_subset_accelerator_t (const hb_map_t& unicode_to_gid_,
|
||||
const hb_multimap_t& gid_to_unicodes_,
|
||||
const hb_set_t& unicodes_)
|
||||
: unicode_to_gid(unicode_to_gid_), unicodes(unicodes_),
|
||||
: unicode_to_gid(unicode_to_gid_), gid_to_unicodes (gid_to_unicodes_), unicodes(unicodes_),
|
||||
cmap_cache(nullptr), destroy_cmap_cache(nullptr),
|
||||
has_seac(false), cff_accelerator(nullptr), destroy_cff_accelerator(nullptr)
|
||||
{ sanitized_table_cache_lock.init (); }
|
||||
|
@ -91,6 +94,7 @@ struct hb_subset_accelerator_t
|
|||
mutable hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
|
||||
|
||||
const hb_map_t unicode_to_gid;
|
||||
const hb_multimap_t gid_to_unicodes;
|
||||
const hb_set_t unicodes;
|
||||
|
||||
// cmap
|
||||
|
@ -106,7 +110,10 @@ struct hb_subset_accelerator_t
|
|||
|
||||
bool in_error () const
|
||||
{
|
||||
return unicode_to_gid.in_error() || unicodes.in_error () || sanitized_table_cache.in_error ();
|
||||
return unicode_to_gid.in_error () ||
|
||||
gid_to_unicodes.in_error () ||
|
||||
unicodes.in_error () ||
|
||||
sanitized_table_cache.in_error ();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "hb-subset-plan.hh"
|
||||
#include "hb-subset-accelerator.hh"
|
||||
#include "hb-map.hh"
|
||||
#include "hb-multimap.hh"
|
||||
#include "hb-set.hh"
|
||||
|
||||
#include "hb-ot-cmap-table.hh"
|
||||
|
@ -523,14 +524,44 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
|
|||
cmap_unicodes = &plan->accelerator->unicodes;
|
||||
}
|
||||
|
||||
for (hb_codepoint_t cp : *cmap_unicodes)
|
||||
if (plan->accelerator &&
|
||||
unicodes->get_population () < cmap_unicodes->get_population () &&
|
||||
glyphs->get_population () < cmap_unicodes->get_population ())
|
||||
{
|
||||
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
|
||||
if (!unicodes->has (cp) && !glyphs->has (gid))
|
||||
continue;
|
||||
auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
|
||||
for (hb_codepoint_t gid : *glyphs)
|
||||
{
|
||||
auto unicodes = gid_to_unicodes.get (gid);
|
||||
|
||||
plan->codepoint_to_glyph->set (cp, gid);
|
||||
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
|
||||
for (hb_codepoint_t cp : unicodes)
|
||||
{
|
||||
plan->codepoint_to_glyph->set (cp, gid);
|
||||
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
|
||||
}
|
||||
}
|
||||
for (hb_codepoint_t cp : *unicodes)
|
||||
{
|
||||
/* Don't double-add entry. */
|
||||
if (plan->codepoint_to_glyph->has (cp))
|
||||
continue;
|
||||
|
||||
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
|
||||
plan->codepoint_to_glyph->set (cp, gid);
|
||||
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
|
||||
}
|
||||
plan->unicode_to_new_gid_list.qsort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (hb_codepoint_t cp : *cmap_unicodes)
|
||||
{
|
||||
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
|
||||
if (!unicodes->has (cp) && !glyphs->has (gid))
|
||||
continue;
|
||||
|
||||
plan->codepoint_to_glyph->set (cp, gid);
|
||||
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
|
||||
}
|
||||
}
|
||||
|
||||
/* Add gids which where requested, but not mapped in cmap */
|
||||
|
@ -930,8 +961,19 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
|||
|
||||
if (plan->attach_accelerator_data)
|
||||
{
|
||||
hb_multimap_t gid_to_unicodes;
|
||||
|
||||
hb_map_t &unicode_to_gid = *plan->codepoint_to_glyph;
|
||||
|
||||
for (auto unicode : *plan->unicodes)
|
||||
{
|
||||
auto gid = unicode_to_gid[unicode];
|
||||
gid_to_unicodes.add (gid, unicode);
|
||||
}
|
||||
|
||||
plan->inprogress_accelerator =
|
||||
hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
|
||||
gid_to_unicodes,
|
||||
*plan->unicodes,
|
||||
plan->has_seac);
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ struct hb_subset_plan_t
|
|||
|
||||
// For each cp that we'd like to retain maps to the corresponding gid.
|
||||
hb_set_t *unicodes;
|
||||
hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list;
|
||||
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list;
|
||||
|
||||
// name_ids we would like to retain
|
||||
hb_set_t *name_ids;
|
||||
|
|
|
@ -56,6 +56,7 @@ hb_base_sources = files(
|
|||
'hb-map.hh',
|
||||
'hb-meta.hh',
|
||||
'hb-ms-feature-ranges.hh',
|
||||
'hb-multimap.hh',
|
||||
'hb-mutex.hh',
|
||||
'hb-null.hh',
|
||||
'hb-number.cc',
|
||||
|
@ -580,6 +581,7 @@ if get_option('tests').enabled()
|
|||
'test-iter': ['test-iter.cc', 'hb-static.cc'],
|
||||
'test-machinery': ['test-machinery.cc', 'hb-static.cc'],
|
||||
'test-map': ['test-map.cc', 'hb-static.cc'],
|
||||
'test-multimap': ['test-multimap.cc', 'hb-static.cc'],
|
||||
'test-number': ['test-number.cc', 'hb-number.cc'],
|
||||
'test-ot-tag': ['hb-ot-tag.cc'],
|
||||
'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright © 2022 Behdad Esfahbod
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-multimap.hh"
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
hb_multimap_t m;
|
||||
|
||||
assert (m.get (10).length == 0);
|
||||
|
||||
m.add (10, 11);
|
||||
assert (m.get (10).length == 1);
|
||||
|
||||
m.add (10, 12);
|
||||
assert (m.get (10).length == 2);
|
||||
|
||||
m.add (10, 13);
|
||||
assert (m.get (10).length == 3);
|
||||
assert (m.get (10)[0] == 11);
|
||||
assert (m.get (10)[1] == 12);
|
||||
assert (m.get (10)[2] == 13);
|
||||
|
||||
assert (m.get (11).length == 0);
|
||||
m.add (11, 14);
|
||||
assert (m.get (10).length == 3);
|
||||
assert (m.get (11).length == 1);
|
||||
assert (m.get (12).length == 0);
|
||||
assert (m.get (10)[0] == 11);
|
||||
assert (m.get (10)[1] == 12);
|
||||
assert (m.get (10)[2] == 13);
|
||||
assert (m.get (11)[0] == 14);
|
||||
assert (m.get (12)[0] == 0); // Array fallback value
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue