From 183b8094b577dcb7f40b7fcd64b60d405845897a Mon Sep 17 00:00:00 2001 From: rsheeter Date: Wed, 8 May 2019 11:40:31 -0700 Subject: [PATCH 01/18] [map] add iteration --- src/hb-map.hh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/hb-map.hh b/src/hb-map.hh index 13099afc4..2b25c2e61 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -62,6 +62,7 @@ struct hb_hashmap_t bool is_unused () const { return key == kINVALID; } bool is_tombstone () const { return key != kINVALID && value == vINVALID; } bool is_real () const { return key != kINVALID && value != vINVALID; } + hb_pair_t get_pair() const { return hb_pair (key, value); } }; hb_object_header_t header; @@ -206,6 +207,16 @@ struct hb_hashmap_t unsigned int get_population () const { return population; } + /* + * Iterator + */ + auto iter() const HB_AUTO_RETURN + ( + + hb_array_t (items, mask + 1) + | hb_filter (&item_t::is_real) + | hb_map (&item_t::get_pair) + ) + protected: unsigned int bucket_for (K key) const From ba60512813caafc2006b26214e95bbfe1c0e460a Mon Sep 17 00:00:00 2001 From: rsheeter Date: Wed, 8 May 2019 12:09:10 -0700 Subject: [PATCH 02/18] [map] add a test for iteration --- src/hb-map.hh | 2 +- src/test-iter.cc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hb-map.hh b/src/hb-map.hh index 2b25c2e61..5a4f5c371 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -62,7 +62,7 @@ struct hb_hashmap_t bool is_unused () const { return key == kINVALID; } bool is_tombstone () const { return key != kINVALID && value == vINVALID; } bool is_real () const { return key != kINVALID && value != vINVALID; } - hb_pair_t get_pair() const { return hb_pair (key, value); } + hb_pair_t get_pair() const { return hb_pair_t (key, value); } }; hb_object_header_t header; diff --git a/src/test-iter.cc b/src/test-iter.cc index ac2c30e09..7e7732018 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -206,6 +206,10 @@ main (int argc, char **argv) | hb_reduce ([&] (int acc, int value) -> int { return acc; }, 2) ; + using map_pair_t = decltype (*hb_iter (m)); + + hb_iter (m) + | hb_map ([] (map_pair_t p) { return p.first * p.second; }); + unsigned int temp1 = 10; unsigned int temp2 = 0; hb_map_t *result = From 492af0f1bf1d7198b474fda2faca451908af267f Mon Sep 17 00:00:00 2001 From: rsheeter Date: Wed, 8 May 2019 12:47:18 -0700 Subject: [PATCH 03/18] [map] add keys() --- src/hb-map.hh | 9 ++++++++- src/test-iter.cc | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/hb-map.hh b/src/hb-map.hh index 5a4f5c371..4a1f75e65 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -212,11 +212,18 @@ struct hb_hashmap_t */ auto iter() const HB_AUTO_RETURN ( - + hb_array_t (items, mask + 1) + + hb_array (items, mask + 1) | hb_filter (&item_t::is_real) | hb_map (&item_t::get_pair) ) + auto keys() const HB_AUTO_RETURN + ( + + iter() + | hb_map (&hb_pair_t::first) + ) + // | hb_map ([&] (item_t i) { return i.key; }) + protected: unsigned int bucket_for (K key) const diff --git a/src/test-iter.cc b/src/test-iter.cc index 7e7732018..63851a34e 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -210,6 +210,10 @@ main (int argc, char **argv) + hb_iter (m) | hb_map ([] (map_pair_t p) { return p.first * p.second; }); + using map_key_t = decltype (*m.keys()); + + hb_iter (m.keys ()) + | hb_filter ([] (map_key_t k) { return k < 42; }); + unsigned int temp1 = 10; unsigned int temp2 = 0; hb_map_t *result = From b827181ba1f539c990e1bd8fdd3559f1589c8d28 Mon Sep 17 00:00:00 2001 From: rsheeter Date: Wed, 8 May 2019 13:51:11 -0700 Subject: [PATCH 04/18] [map] tweak test-iter.cc --- src/hb-map.hh | 1 - src/test-iter.cc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hb-map.hh b/src/hb-map.hh index 4a1f75e65..36dfc3e5c 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -222,7 +222,6 @@ struct hb_hashmap_t + iter() | hb_map (&hb_pair_t::first) ) - // | hb_map ([&] (item_t i) { return i.key; }) protected: diff --git a/src/test-iter.cc b/src/test-iter.cc index 63851a34e..273ba6c4f 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -206,7 +206,7 @@ main (int argc, char **argv) | hb_reduce ([&] (int acc, int value) -> int { return acc; }, 2) ; - using map_pair_t = decltype (*hb_iter (m)); + using map_pair_t = hb_item_type; + hb_iter (m) | hb_map ([] (map_pair_t p) { return p.first * p.second; }); From 7166bd563447a64eda05c66668bd4a178292bd79 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 14:24:57 -0700 Subject: [PATCH 05/18] Minor --- src/hb-open-type.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 1129bd006..9d388ff3f 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -427,7 +427,7 @@ struct UnsizedArrayOf if (unlikely (!serialize (c, count))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ - for (unsigned i = 0; i < count; i++, items++) + for (unsigned i = 0; i < count; i++, ++items) arrayZ[i] = *items; return_trace (true); } @@ -608,7 +608,7 @@ struct ArrayOf if (unlikely (!serialize (c, count))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ - for (unsigned i = 0; i < count; i++, items++) + for (unsigned i = 0; i < count; i++, ++items) arrayZ[i] = *items; return_trace (true); } From a17f0fa3a10a25959561582ae63ef2e5208647e2 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 14:44:11 -0700 Subject: [PATCH 06/18] [meta] Capture rvalue-references in is_reference / remove_reference --- src/hb-meta.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hb-meta.hh b/src/hb-meta.hh index a47c8cabd..421eb0638 100644 --- a/src/hb-meta.hh +++ b/src/hb-meta.hh @@ -93,6 +93,7 @@ template using hb_remove_const = typename hb_match_const::type; #define hb_is_const(T) hb_match_const::value template struct hb_match_reference { typedef T type; enum { value = false }; }; template struct hb_match_reference { typedef T type; enum { value = true }; }; +template struct hb_match_reference { typedef T type; enum { value = true }; }; template using hb_remove_reference = typename hb_match_reference::type; #define hb_is_reference(T) hb_match_reference::value template struct hb_match_pointer { typedef T type; enum { value = false }; }; From f5705d7656817cbfdbc4479b1cb0be3af6f4abdf Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 14:46:55 -0700 Subject: [PATCH 07/18] Whitespace --- src/hb-map.hh | 10 +++++----- src/test-iter.cc | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/hb-map.hh b/src/hb-map.hh index 36dfc3e5c..0e57f9732 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -210,16 +210,16 @@ struct hb_hashmap_t /* * Iterator */ - auto iter() const HB_AUTO_RETURN + auto iter () const HB_AUTO_RETURN ( + hb_array (items, mask + 1) | hb_filter (&item_t::is_real) | hb_map (&item_t::get_pair) ) - auto keys() const HB_AUTO_RETURN + auto keys () const HB_AUTO_RETURN ( - + iter() + + iter() | hb_map (&hb_pair_t::first) ) @@ -233,9 +233,9 @@ struct hb_hashmap_t while (!items[i].is_unused ()) { if (items[i] == key) - return i; + return i; if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) - tombstone = i; + tombstone = i; i = (i + ++step) & mask; } return tombstone == (unsigned) -1 ? i : tombstone; diff --git a/src/test-iter.cc b/src/test-iter.cc index 273ba6c4f..69f2de978 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -208,11 +208,14 @@ main (int argc, char **argv) using map_pair_t = hb_item_type; + hb_iter (m) - | hb_map ([] (map_pair_t p) { return p.first * p.second; }); + | hb_map ([] (map_pair_t p) { return p.first * p.second; }) + ; - using map_key_t = decltype (*m.keys()); - + hb_iter (m.keys ()) - | hb_filter ([] (map_key_t k) { return k < 42; }); + m.keys (); + using map_key_t = decltype (*m.keys()); + + hb_iter (m.keys ()) + | hb_filter ([] (map_key_t k) { return k < 42; }) + ; unsigned int temp1 = 10; unsigned int temp2 = 0; From 5ceaafa5de8dff51fe91f7008a12ec9c304a1376 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 14:59:25 -0700 Subject: [PATCH 08/18] [algs] Fix identity return type --- src/hb-algs.hh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 52d40923e..d377772e0 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -36,15 +36,15 @@ struct { - template T - operator () (const T& v) const { return v; } + template auto + operator () (T&& v) const HB_AUTO_RETURN ( hb_forward (v) ) } HB_FUNCOBJ (hb_identity); struct { template bool - operator () (const T& v) const { return bool (v); } + operator () (T&& v) const { return bool (hb_forward (v)); } } HB_FUNCOBJ (hb_bool); From 3c69505b3a7850b68a931849a2badb84b6b36d51 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 15:05:10 -0700 Subject: [PATCH 09/18] [map] Fix iter --- src/hb-map.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-map.hh b/src/hb-map.hh index 0e57f9732..a5dedac57 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -212,7 +212,7 @@ struct hb_hashmap_t */ auto iter () const HB_AUTO_RETURN ( - + hb_array (items, mask + 1) + + hb_array (items, mask ? mask + 1 : 0) | hb_filter (&item_t::is_real) | hb_map (&item_t::get_pair) ) From a30482718491e3455365167e1c85981c8c0f542b Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 15:08:10 -0700 Subject: [PATCH 10/18] [map] Add .values() iterator --- src/hb-map.hh | 6 +++++- src/test-iter.cc | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hb-map.hh b/src/hb-map.hh index a5dedac57..1c2fe145f 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -216,12 +216,16 @@ struct hb_hashmap_t | hb_filter (&item_t::is_real) | hb_map (&item_t::get_pair) ) - auto keys () const HB_AUTO_RETURN ( + iter() | hb_map (&hb_pair_t::first) ) + auto values () const HB_AUTO_RETURN + ( + + iter() + | hb_map (&hb_pair_t::second) + ) protected: diff --git a/src/test-iter.cc b/src/test-iter.cc index 69f2de978..0a0e4d102 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -215,6 +215,14 @@ main (int argc, char **argv) using map_key_t = decltype (*m.keys()); + hb_iter (m.keys ()) | hb_filter ([] (map_key_t k) { return k < 42; }) + | hb_drain + ; + + m.values (); + using map_value_t = decltype (*m.values()); + + hb_iter (m.values ()) + | hb_filter ([] (map_value_t k) { return k < 42; }) + | hb_drain ; unsigned int temp1 = 10; From 372c5b97bfa3b744de1d017cf662607eb8a2fa6e Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 15:28:39 -0700 Subject: [PATCH 11/18] [map] Fix bots Older compilers don't like calling iter() from return-type decltype() ../src/hb-map.hh:226:12: error: cannot call member function 'decltype ((((+ hb_array(((const hb_hashmap_t*)this)->hb_hashmap_t::items, (((const hb_hashmap_t*)this)->hb_hashmap_t::mask ? (((const hb_hashmap_t*)this)->hb_hashmap_t::mask + 1) : 0))) | hb_filter((& hb_hashmap_t::item_t:: is_real))) | hb_map((& hb_hashmap_t::item_t:: get_pair)))) hb_hashmap_t::iter() const [with K = const hb_serialize_context_t::object_t*; V = unsigned int; K kINVALID = 0u; V vINVALID = 0u; decltype ((((+ hb_array(((const hb_hashmap_t*)this)->hb_hashmap_t::items, (((const hb_hashmap_t*)this)->hb_hashmap_t::mask ? (((const hb_hashmap_t*)this)->hb_hashmap_t::mask + 1) : 0))) | hb_filter((& hb_hashmap_t::item_t:: is_real))) | hb_map((& hb_hashmap_t::item_t:: get_pair)))) = hb_map_iter_t::item_t>, bool (hb_hashmap_t::item_t::*)() const, const&, 0u>, hb_pair_t (hb_hashmap_t::item_t::*)() const, 0u>]' without object + iter() ^ ../src/hb-meta.hh:58:41: note: in definition of macro 'HB_AUTO_RETURN' #define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); } ^ --- src/hb-map.hh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hb-map.hh b/src/hb-map.hh index 1c2fe145f..6eac8c3d3 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -218,13 +218,15 @@ struct hb_hashmap_t ) auto keys () const HB_AUTO_RETURN ( - + iter() - | hb_map (&hb_pair_t::first) + + hb_array (items, mask ? mask + 1 : 0) + | hb_filter (&item_t::is_real) + | hb_map (&item_t::key) ) auto values () const HB_AUTO_RETURN ( - + iter() - | hb_map (&hb_pair_t::second) + + hb_array (items, mask ? mask + 1 : 0) + | hb_filter (&item_t::is_real) + | hb_map (&item_t::value) ) protected: From 27b2093009745b6c30663605f45ac95deb1562cc Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 15:32:57 -0700 Subject: [PATCH 12/18] [map] Return rvalues from keys()/values() --- src/hb-algs.hh | 7 +++++++ src/hb-map.hh | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index d377772e0..0db2184cf 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -41,6 +41,13 @@ struct } HB_FUNCOBJ (hb_identity); +struct +{ + template hb_remove_reference + operator () (T&& v) const { return v; } +} +HB_FUNCOBJ (hb_rvalue); + struct { template bool diff --git a/src/hb-map.hh b/src/hb-map.hh index 6eac8c3d3..2f0659562 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -221,12 +221,14 @@ struct hb_hashmap_t + hb_array (items, mask ? mask + 1 : 0) | hb_filter (&item_t::is_real) | hb_map (&item_t::key) + | hb_map (hb_rvalue) ) auto values () const HB_AUTO_RETURN ( + hb_array (items, mask ? mask + 1 : 0) | hb_filter (&item_t::is_real) | hb_map (&item_t::value) + | hb_map (hb_rvalue) ) protected: From d5decf9bf77db914b67ffc446379df621516e362 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Tue, 7 May 2019 15:47:38 -0700 Subject: [PATCH 13/18] [subset] Move hdmx to subset2. --- src/hb-ot-hdmx-table.hh | 38 +++++++------------------------------- src/hb-subset.cc | 2 +- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index 847b32657..abf4440a6 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -157,40 +157,16 @@ struct hdmx return_trace (true); } - static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan) + + bool subset (hb_subset_context_t *c) const { - return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->num_output_glyphs ()); - } + TRACE_SUBSET (this); - bool subset (hb_subset_plan_t *plan) const - { - size_t dest_size = get_subsetted_size (this, plan); - hdmx *dest = (hdmx *) malloc (dest_size); - if (unlikely (!dest)) - { - DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size); - return false; - } + hdmx *hdmx_prime = c->serializer->start_embed (); + if (unlikely (!hdmx_prime)) return_trace (false); - hb_serialize_context_t c (dest, dest_size); - hdmx *hdmx_prime = c.start_serialize (); - if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) - { - free (dest); - DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx."); - return false; - } - c.end_serialize (); - - hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest, - dest_size, - HB_MEMORY_MODE_READONLY, - dest, - free); - bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob); - hb_blob_destroy (hdmx_prime_blob); - - return result; + hdmx_prime->serialize (c->serializer, this, c->plan); + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 800bd35c8..f4fc77172 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -159,7 +159,7 @@ _subset_table (hb_subset_plan_t *plan, result = _subset (plan); break; case HB_OT_TAG_hdmx: - result = _subset (plan); + result = _subset2 (plan); break; case HB_OT_TAG_name: result = _subset2 (plan); From e8ef0e627c493af700e254bdd2767f8955f2d03f Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Tue, 7 May 2019 17:23:02 -0700 Subject: [PATCH 14/18] [subset] WIP convert hdmx subsetting to use iterators. --- src/hb-ot-hdmx-table.hh | 117 +++++++++++++++--------------------- test/api/test-subset-hdmx.c | 23 ------- 2 files changed, 49 insertions(+), 91 deletions(-) diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index abf4440a6..560fb14d0 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -41,71 +41,30 @@ namespace OT { struct DeviceRecord { - struct SubsetView - { - const DeviceRecord *source_device_record; - unsigned int sizeDeviceRecord; - hb_subset_plan_t *subset_plan; - - void init (const DeviceRecord *source_device_record, - unsigned int sizeDeviceRecord, - hb_subset_plan_t *subset_plan) - { - this->source_device_record = source_device_record; - this->sizeDeviceRecord = sizeDeviceRecord; - this->subset_plan = subset_plan; - } - - unsigned int len () const - { return this->subset_plan->num_output_glyphs (); } - - const HBUINT8* operator [] (unsigned int new_gid) const - { - if (unlikely (new_gid >= len ())) return nullptr; - - hb_codepoint_t old_gid; - if (!this->subset_plan->old_gid_for_new_gid (new_gid, &old_gid)) - return &Null(HBUINT8); - - if (old_gid >= sizeDeviceRecord - DeviceRecord::min_size) - return nullptr; - return &(this->source_device_record->widthsZ[old_gid]); - } - }; - - static unsigned int get_size (unsigned int count) + static unsigned int get_size (unsigned count) { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } - bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view) + template + bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it) { TRACE_SERIALIZE (this); - unsigned int size = get_size (subset_view.len ()); - if (unlikely (!c->allocate_size (size))) - { - DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.", - size); - return_trace (false); - } + unsigned length = it.len (); - this->pixelSize = subset_view.source_device_record->pixelSize; - this->maxWidth = subset_view.source_device_record->maxWidth; + if (unlikely (!c->extend (*this, length))) return_trace (false); - for (unsigned int i = 0; i < subset_view.len (); i++) - { - const HBUINT8 *width = subset_view[i]; - if (!width) - { - DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i); - return_trace (false); - } - widthsZ[i] = *width; - } + this->pixelSize = pixelSize; + this->maxWidth = + + it + | hb_reduce (hb_max, 0u); + + + it + | hb_sink (widthsZ.as_array (length)); return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const + bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && @@ -135,26 +94,25 @@ struct hdmx return StructAtOffset (&this->firstDeviceRecord, i * sizeDeviceRecord); } - bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan) + template + bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min ((*this)))) return_trace (false); - this->version = source_hdmx->version; - this->numRecords = source_hdmx->numRecords; - this->sizeDeviceRecord = DeviceRecord::get_size (plan->num_output_glyphs ()); + this->version = version; + this->numRecords = it.len (); + this->sizeDeviceRecord = + it ? DeviceRecord::get_size ((*it).second.len ()) : DeviceRecord::get_size (0); - for (unsigned int i = 0; i < source_hdmx->numRecords; i++) - { - DeviceRecord::SubsetView subset_view; - subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan); + using pair_t = decltype (*it); + + it + | hb_apply ([&] (const pair_t& _) { + c->start_embed ()->serialize (c, _.first, _.second); + }); - if (!c->start_embed ()->serialize (c, subset_view)) - return_trace (false); - } - - return_trace (true); + return_trace (c->successful); } @@ -165,10 +123,33 @@ struct hdmx hdmx *hdmx_prime = c->serializer->start_embed (); if (unlikely (!hdmx_prime)) return_trace (false); - hdmx_prime->serialize (c->serializer, this, c->plan); + auto it = + + hb_iota ((unsigned) numRecords) + | hb_map ([&] (unsigned _) { + const DeviceRecord *device_record = + &StructAtOffset (&firstDeviceRecord, + _ * sizeDeviceRecord); + auto row = + + hb_iota (c->plan->num_output_glyphs ()) + | hb_map (c->plan->reverse_glyph_map) + | hb_map ([=] (hb_codepoint_t _) { + if (c->plan->is_empty_glyph (_)) + return Null(HBUINT8); + return device_record->widthsZ.as_array (get_num_glyphs ()) [_]; + }) + ; + return hb_pair ((unsigned) device_record->pixelSize, +row); + }); + + hdmx_prime->serialize (c->serializer, version, it); return_trace (true); } + unsigned get_num_glyphs () const + { + return sizeDeviceRecord - DeviceRecord::min_size; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c index 44e579ace..7178833bc 100644 --- a/test/api/test-subset-hdmx.c +++ b/test/api/test-subset-hdmx.c @@ -91,28 +91,6 @@ test_subset_hdmx_invalid (void) hb_face_destroy (face); } -static void -test_subset_hdmx_fails_sanitize (void) -{ - hb_face_t *face = hb_test_open_font_file ("../fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016"); - - hb_subset_input_t *input = hb_subset_input_create_or_fail (); - hb_set_t *codepoints = hb_subset_input_unicode_set (input); - hb_face_t *subset; - - hb_set_add (codepoints, 'a'); - hb_set_add (codepoints, 'b'); - hb_set_add (codepoints, 'c'); - - subset = hb_subset (face, input); - g_assert (subset); - g_assert (subset == hb_face_get_empty ()); - - hb_subset_input_destroy (input); - hb_face_destroy (subset); - hb_face_destroy (face); -} - static void test_subset_hdmx_noop (void) { @@ -140,7 +118,6 @@ main (int argc, char **argv) hb_test_add (test_subset_hdmx_simple_subset); hb_test_add (test_subset_hdmx_multiple_device_records); hb_test_add (test_subset_hdmx_invalid); - hb_test_add (test_subset_hdmx_fails_sanitize); hb_test_add (test_subset_hdmx_noop); return hb_test_run(); From b710176ce28e863a01797987d7ce37d19aaf2fd3 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 15:46:51 -0700 Subject: [PATCH 15/18] [hdmx] Touch up --- src/hb-ot-hdmx-table.hh | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index 560fb14d0..35d27f7fa 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -44,7 +44,8 @@ struct DeviceRecord static unsigned int get_size (unsigned count) { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } - template + template bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it) { TRACE_SERIALIZE (this); @@ -94,7 +95,8 @@ struct hdmx return StructAtOffset (&this->firstDeviceRecord, i * sizeDeviceRecord); } - template + template bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) { TRACE_SERIALIZE (this); @@ -103,14 +105,13 @@ struct hdmx this->version = version; this->numRecords = it.len (); - this->sizeDeviceRecord = - it ? DeviceRecord::get_size ((*it).second.len ()) : DeviceRecord::get_size (0); + this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0); - using pair_t = decltype (*it); + it - | hb_apply ([&] (const pair_t& _) { + | hb_apply ([&] (const hb_item_type& _) { c->start_embed ()->serialize (c, _.first, _.second); - }); + }) + ; return_trace (c->successful); } @@ -125,21 +126,24 @@ struct hdmx auto it = + hb_iota ((unsigned) numRecords) - | hb_map ([&] (unsigned _) { + | hb_map ([&] (unsigned _) + { const DeviceRecord *device_record = &StructAtOffset (&firstDeviceRecord, _ * sizeDeviceRecord); auto row = + hb_iota (c->plan->num_output_glyphs ()) | hb_map (c->plan->reverse_glyph_map) - | hb_map ([=] (hb_codepoint_t _) { + | hb_map ([=] (hb_codepoint_t _) + { if (c->plan->is_empty_glyph (_)) return Null(HBUINT8); return device_record->widthsZ.as_array (get_num_glyphs ()) [_]; }) ; return hb_pair ((unsigned) device_record->pixelSize, +row); - }); + }) + ; hdmx_prime->serialize (c->serializer, version, it); return_trace (true); From 4c94bc63d914fac7e11940eb165b6cf1039ba5a1 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 15:57:33 -0700 Subject: [PATCH 16/18] Move hb_invoke() back to hb-algs.hh --- src/hb-algs.hh | 32 ++++++++++++++++++++++++++++++++ src/hb-meta.hh | 32 -------------------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 0db2184cf..6adbade15 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -76,6 +76,38 @@ struct } HB_FUNCOBJ (hb_hash); + +struct +{ + private: + + /* Pointer-to-member-function. */ + template auto + impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN + ((hb_deref (hb_forward (v)).*hb_forward (a)) (hb_forward (ds)...)) + + /* Pointer-to-member. */ + template auto + impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN + ((hb_deref (hb_forward (v))).*hb_forward (a)) + + /* Operator(). */ + template auto + impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN + (hb_deref (hb_forward (a)) (hb_forward (ds)...)) + + public: + + template auto + operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN + ( + impl (hb_forward (a), + hb_prioritize, + hb_forward (ds)...) + ) +} +HB_FUNCOBJ (hb_invoke); + struct { private: diff --git a/src/hb-meta.hh b/src/hb-meta.hh index 421eb0638..4e5e5d94f 100644 --- a/src/hb-meta.hh +++ b/src/hb-meta.hh @@ -212,36 +212,4 @@ template <> struct hb_is_integer { enum { value = true }; }; #define hb_is_integer(T) hb_is_integer::value -struct -{ - private: - - /* Pointer-to-member-function. */ - template auto - impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN - ((hb_deref (hb_forward (v)).*hb_forward (a)) (hb_forward (ds)...)) - - /* Pointer-to-member. */ - template auto - impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN - ((hb_deref (hb_forward (v))).*hb_forward (a)) - - /* Operator(). */ - template auto - impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN - (hb_deref (hb_forward (a)) (hb_forward (ds)...)) - - public: - - template auto - operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN - ( - impl (hb_forward (a), - hb_prioritize, - hb_forward (ds)...) - ) -} -HB_FUNCOBJ (hb_invoke); - - #endif /* HB_META_HH */ From afb013f350b0022ae6c05f140aeba23d5de34101 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 16:16:43 -0700 Subject: [PATCH 17/18] Fix msan issue hb_identity returns rvalue-reference if input is rvalue. That, can leak the reference and cause in bad access to temporaries after they are destructed. This is unfortunately unfixable given the desired transparency of hb_identity :(. Just don't use it with hb_map(). --- src/test-iter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test-iter.cc b/src/test-iter.cc index 0a0e4d102..944c234f5 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -161,7 +161,7 @@ main (int argc, char **argv) test_iterator_non_default_constructable (hb_enumerate (hb_iter (st))); test_iterator_non_default_constructable (hb_enumerate (hb_iter (st) + 1)); test_iterator_non_default_constructable (hb_iter (st) | hb_filter ()); - test_iterator_non_default_constructable (hb_iter (st) | hb_map (hb_identity)); + test_iterator_non_default_constructable (hb_iter (st) | hb_map (hb_rvalue)); assert (true == hb_all (st)); assert (false == hb_all (st, 42u)); From e8b45c19330d8718cd6d7aef0ca2db0539a53294 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 May 2019 16:37:38 -0700 Subject: [PATCH 18/18] [array] Add .copy() --- src/hb-array.hh | 11 +++++++++++ src/hb-open-type.hh | 10 ++++------ src/hb-serialize.hh | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/hb-array.hh b/src/hb-array.hh index 2da8df0bb..8902e7aaf 100644 --- a/src/hb-array.hh +++ b/src/hb-array.hh @@ -176,6 +176,17 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> void free () { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; } + template + hb_array_t copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + auto* out = c->template start_embed (arrayZ); + if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ()); + for (unsigned i = 0; i < length; i++) + out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */ + return_trace (hb_array_t (out, length)); + } + template bool sanitize (hb_sanitize_context_t *c) const { return c->check_array (arrayZ, length); } diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 9d388ff3f..cacb1a7b8 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -436,9 +436,7 @@ struct UnsizedArrayOf { TRACE_SERIALIZE (this); auto *out = c->start_embed (this); - if (unlikely (!out->serialize (c, count))) return_trace (nullptr); - for (unsigned i = 0; i < count; i++) - out->arrayZ[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */ + if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); return_trace (out); } @@ -618,9 +616,9 @@ struct ArrayOf TRACE_SERIALIZE (this); auto *out = c->start_embed (this); unsigned count = len; - if (unlikely (!out->serialize (c, count))) return_trace (nullptr); - for (unsigned i = 0; i < count; i++) - out->arrayZ[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */ + if (unlikely (!c->extend_min (out))) return_trace (nullptr); + c->check_assign (out->len, len); + if (unlikely (!as_array ().copy (c))) return_trace (nullptr); return_trace (out); } diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index e0f79809f..76f701608 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -323,7 +323,7 @@ struct hb_serialize_context_t allocate_size (alignment - l); } - template + template Type *start_embed (const Type *obj HB_UNUSED = nullptr) const { return reinterpret_cast (this->head); } template