From ffafcf9633eae1c679b8835a31e9b00dca740dde Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 4 Jan 2023 12:55:59 -0700 Subject: [PATCH] [map] Add hb_map_next() --- docs/harfbuzz-sections.txt | 1 + src/hb-map.cc | 25 ++++++++++++++++++++++++- src/hb-map.h | 6 ++++++ src/hb-map.hh | 24 ++++++++++++++++++++++++ src/test-map.cc | 27 +++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index f697157ae..e30590f59 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -546,6 +546,7 @@ hb_map_get_population hb_map_is_empty hb_map_is_equal hb_map_hash +hb_map_next HB_MAP_VALUE_INVALID hb_map_t diff --git a/src/hb-map.cc b/src/hb-map.cc index 5c5f5de59..fd7f3e371 100644 --- a/src/hb-map.cc +++ b/src/hb-map.cc @@ -335,9 +335,32 @@ hb_map_is_equal (const hb_map_t *map, * * Since: 4.4.0 **/ -HB_EXTERN unsigned int +unsigned int hb_map_hash (const hb_map_t *map) { return map->hash (); } +/** + * hb_map_next: + * @map: A map + * @idx: (inout): Iterator internal state + * @key: (out): Key retrieved + * @value: (out): Value retrieved + * + * Fetches the next key/value paire in @map. + * + * Set @idx to -1 to get started. + * + * Return value: `true` if there was a next value, `false` otherwise + * + * Since: REPLACEME + **/ +hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value) +{ + return map->next (idx, key, value); +} diff --git a/src/hb-map.h b/src/hb-map.h index 3a067c5c7..9387ec2ce 100644 --- a/src/hb-map.h +++ b/src/hb-map.h @@ -118,6 +118,12 @@ HB_EXTERN hb_bool_t hb_map_has (const hb_map_t *map, hb_codepoint_t key); +/* Pass -1 in for idx to get started. */ +HB_EXTERN hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value); HB_END_DECLS diff --git a/src/hb-map.hh b/src/hb-map.hh index bfb1b3f76..9d6fbec8b 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -348,6 +348,30 @@ struct hb_hashmap_t | hb_map (hb_ridentity) ) + /* C iterator. */ + bool next (int *idx, + K *key, + V *value) const + { + unsigned i = (unsigned) (*idx + 1); + + unsigned count = size (); + while (i <= count && !items[i].is_real ()) + i++; + + if (i >= count) + { + *idx = -1; + return false; + } + + *key = items[i].key; + *value = items[i].value; + + *idx = (signed) i; + return true; + } + /* Sink interface. */ hb_hashmap_t& operator << (const hb_pair_t& v) { set (v.first, v.second); return *this; } diff --git a/src/test-map.cc b/src/test-map.cc index da77a2f6c..bda3548e8 100644 --- a/src/test-map.cc +++ b/src/test-map.cc @@ -301,6 +301,33 @@ main (int argc, char **argv) m.set (1, hb_set_t {1, 2, 3}); m.reset (); } + /* Test iteration. */ + { + hb_map_t m; + m.set (1, 1); + m.set (4, 3); + m.set (5, 5); + m.set (2, 1); + m.set (3, 2); + m.set (6, 8); + + hb_codepoint_t k; + hb_codepoint_t v; + unsigned pop = 0; + for (signed i; + m.next (&i, &k, &v);) + { + pop++; + if (k == 1) assert (v == 1); + else if (k == 2) assert (v == 1); + else if (k == 3) assert (v == 2); + else if (k == 4) assert (v == 3); + else if (k == 5) assert (v == 5); + else if (k == 6) assert (v == 8); + else assert (false); + } + assert (pop = m.get_population ()); + } return 0; }