From 10c8fc55535e679a75f6f3012273f256e0416d90 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 2 Dec 2022 15:34:34 -0700 Subject: [PATCH] [multimap] Add a multimap datastructure --- src/Makefile.am | 5 +++ src/Makefile.sources | 1 + src/hb-multimap.hh | 92 ++++++++++++++++++++++++++++++++++++++++++++ src/meson.build | 2 + src/test-multimap.cc | 50 ++++++++++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 src/hb-multimap.hh create mode 100644 src/test-multimap.cc diff --git a/src/Makefile.am b/src/Makefile.am index 225444e32..a4758e792 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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) diff --git a/src/Makefile.sources b/src/Makefile.sources index 6c891eac5..10db3c151 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -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 \ diff --git a/src/hb-multimap.hh b/src/hb-multimap.hh new file mode 100644 index 000000000..4fde00a75 --- /dev/null +++ b/src/hb-multimap.hh @@ -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 get (hb_codepoint_t k) + { + 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 (); + } + + 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> multiples_values; +}; + + + +#endif /* HB_MULTIMAP_HH */ diff --git a/src/meson.build b/src/meson.build index d53e77b5f..07c0eb3fe 100644 --- a/src/meson.build +++ b/src/meson.build @@ -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'], diff --git a/src/test-multimap.cc b/src/test-multimap.cc new file mode 100644 index 000000000..7240c5a50 --- /dev/null +++ b/src/test-multimap.cc @@ -0,0 +1,50 @@ +/* + * 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); + + return 0; +}