blob: 353403e92978f0adccf13e269c45b821a62f8226 [file] [log] [blame]
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -04001/*
Behdad Esfahboddeed4a42017-10-15 16:53:09 +02002 * Copyright © 2012,2017 Google, Inc.
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -04003 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070027#ifndef HB_SET_HH
28#define HB_SET_HH
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -040029
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070030#include "hb.hh"
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -040031
32
Behdad Esfahbod0edd0fd2013-04-17 17:26:56 -040033/*
Behdad Esfahbod0d5798a2013-04-17 18:19:21 -040034 * hb_set_t
35 */
Behdad Esfahbodb40f2c02013-04-16 23:21:38 -040036
Behdad Esfahbodeeb26d22017-12-02 15:22:04 -080037/* TODO Keep a free-list so we can free pages that are completely zeroed. At that
38 * point maybe also use a sentinel value for "all-1" pages? */
39
Behdad Esfahbod1bc1cb32012-06-16 15:21:55 -040040struct hb_set_t
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -040041{
Behdad Esfahboddeed4a42017-10-15 16:53:09 +020042 struct page_map_t
43 {
44 inline int cmp (const page_map_t *o) const { return (int) o->major - (int) major; }
45
46 uint32_t major;
47 uint32_t index;
48 };
49
50 struct page_t
51 {
Behdad Esfahbod438c3252017-12-01 13:34:14 -080052 inline void init0 (void) { memset (&v, 0, sizeof (v)); }
53 inline void init1 (void) { memset (&v, 0xff, sizeof (v)); }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +020054
55 inline unsigned int len (void) const
56 { return ARRAY_LENGTH_CONST (v); }
57
58 inline bool is_empty (void) const
59 {
60 for (unsigned int i = 0; i < len (); i++)
61 if (v[i])
62 return false;
63 return true;
64 }
65
66 inline void add (hb_codepoint_t g) { elt (g) |= mask (g); }
67 inline void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
68 inline bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }
69
Behdad Esfahbod438c3252017-12-01 13:34:14 -080070 inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
71 {
Behdad Esfahbod81f27df2017-12-16 06:12:06 -080072 elt_t *la = &elt (a);
73 elt_t *lb = &elt (b);
74 if (la == lb)
75 *la |= (mask (b) << 1) - mask(a);
76 else
77 {
78 *la |= ~(mask (a) - 1);
79 la++;
Behdad Esfahbod9d0194b2017-12-01 13:56:06 -080080
Behdad Esfahbod81f27df2017-12-16 06:12:06 -080081 memset (la, 0xff, (char *) lb - (char *) la);
Behdad Esfahbod9d0194b2017-12-01 13:56:06 -080082
Behdad Esfahbod81f27df2017-12-16 06:12:06 -080083 *lb |= ((mask (b) << 1) - 1);
84 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -080085 }
86
Behdad Esfahboddeed4a42017-10-15 16:53:09 +020087 inline bool is_equal (const page_t *other) const
88 {
89 return 0 == memcmp (&v, &other->v, sizeof (v));
90 }
91
92 inline unsigned int get_population (void) const
93 {
94 unsigned int pop = 0;
95 for (unsigned int i = 0; i < len (); i++)
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +020096 pop += hb_popcount (v[i]);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +020097 return pop;
98 }
99
100 inline bool next (hb_codepoint_t *codepoint) const
101 {
102 unsigned int m = (*codepoint + 1) & MASK;
103 if (!m)
104 {
105 *codepoint = INVALID;
106 return false;
107 }
108 unsigned int i = m / ELT_BITS;
109 unsigned int j = m & ELT_MASK;
110
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800111 const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
112 for (const elt_t *p = &vv; i < len (); p = &v[++i])
113 if (*p)
114 {
115 *codepoint = i * ELT_BITS + elt_get_min (*p);
116 return true;
117 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200118
119 *codepoint = INVALID;
120 return false;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200121 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800122 inline bool previous (hb_codepoint_t *codepoint) const
123 {
124 unsigned int m = (*codepoint - 1) & MASK;
125 if (m == MASK)
126 {
127 *codepoint = INVALID;
128 return false;
129 }
130 unsigned int i = m / ELT_BITS;
131 unsigned int j = m & ELT_MASK;
132
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800133 const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1);
134 for (const elt_t *p = &vv; (int) i >= 0; p = &v[--i])
135 if (*p)
136 {
137 *codepoint = i * ELT_BITS + elt_get_max (*p);
138 return true;
139 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800140
141 *codepoint = INVALID;
142 return false;
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800143 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200144 inline hb_codepoint_t get_min (void) const
145 {
146 for (unsigned int i = 0; i < len (); i++)
147 if (v[i])
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800148 return i * ELT_BITS + elt_get_min (v[i]);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200149 return INVALID;
150 }
151 inline hb_codepoint_t get_max (void) const
152 {
153 for (int i = len () - 1; i >= 0; i--)
154 if (v[i])
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800155 return i * ELT_BITS + elt_get_max (v[i]);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200156 return 0;
157 }
158
Behdad Esfahbodd25c3e62018-02-16 17:45:09 -0800159 typedef unsigned long long elt_t;
Behdad Esfahbodfda994e2018-09-07 15:02:57 -0400160 enum { PAGE_BITS = 512 };
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200161 static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
162
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200163 static inline unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
164 static inline unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800165
Behdad Esfahbod7737e872017-10-15 16:21:03 -0400166 typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200167
Behdad Esfahbodfda994e2018-09-07 15:02:57 -0400168 enum { ELT_BITS = sizeof (elt_t) * 8 };
169 enum { ELT_MASK = ELT_BITS - 1 };
170 enum { BITS = sizeof (vector_t) * 8 };
171 enum { MASK = BITS - 1 };
172 static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200173
174 elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
175 elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
176 elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & ELT_MASK); }
Behdad Esfahbod4ca211b2018-06-01 17:18:57 -0700177
178 vector_t v;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200179 };
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400180 static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200181
Behdad Esfahbod6220e5f2012-06-06 03:30:09 -0400182 hb_object_header_t header;
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700183 bool successful; /* Allocations successful */
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400184 mutable unsigned int population;
Behdad Esfahbod33d6f462018-06-01 17:25:35 -0700185 hb_vector_t<page_map_t, 1> page_map;
Behdad Esfahbod5c3112a2018-05-01 19:07:04 -0400186 hb_vector_t<page_t, 1> pages;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200187
Behdad Esfahbodf1f6bc02018-05-02 12:56:21 -0400188 inline void init_shallow (void)
Behdad Esfahbod9daa88c2017-12-14 13:37:48 -0800189 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700190 successful = true;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400191 population = 0;
Behdad Esfahbod9daa88c2017-12-14 13:37:48 -0800192 page_map.init ();
193 pages.init ();
194 }
Behdad Esfahbodf1f6bc02018-05-02 12:56:21 -0400195 inline void init (void)
196 {
197 hb_object_init (this);
198 init_shallow ();
199 }
200 inline void fini_shallow (void)
Behdad Esfahbod9daa88c2017-12-14 13:37:48 -0800201 {
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400202 page_map.fini ();
203 pages.fini ();
Behdad Esfahbod9daa88c2017-12-14 13:37:48 -0800204 }
Behdad Esfahbodf1f6bc02018-05-02 12:56:21 -0400205 inline void fini (void)
206 {
207 hb_object_fini (this);
208 fini_shallow ();
209 }
Behdad Esfahbod9daa88c2017-12-14 13:37:48 -0800210
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200211 inline bool resize (unsigned int count)
212 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700213 if (unlikely (!successful)) return false;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200214 if (!pages.resize (count) || !page_map.resize (count))
215 {
216 pages.resize (page_map.len);
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700217 successful = false;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200218 return false;
219 }
220 return true;
221 }
Behdad Esfahbod6220e5f2012-06-06 03:30:09 -0400222
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400223 inline void clear (void) {
Behdad Esfahbod7b1b7202013-01-02 23:02:59 -0600224 if (unlikely (hb_object_is_inert (this)))
225 return;
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700226 successful = true;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400227 population = 0;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200228 page_map.resize (0);
229 pages.resize (0);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400230 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800231 inline bool is_empty (void) const {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200232 unsigned int count = pages.len;
233 for (unsigned int i = 0; i < count; i++)
234 if (!pages[i].is_empty ())
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400235 return false;
236 return true;
237 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200238
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400239 inline void dirty (void) { population = (unsigned int) -1; }
240
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400241 inline void add (hb_codepoint_t g)
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400242 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700243 if (unlikely (!successful)) return;
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400244 if (unlikely (g == INVALID)) return;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400245 dirty ();
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500246 page_t *page = page_for_insert (g); if (unlikely (!page)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200247 page->add (g);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400248 }
Behdad Esfahbod81f27df2017-12-16 06:12:06 -0800249 inline bool add_range (hb_codepoint_t a, hb_codepoint_t b)
Behdad Esfahbod67bb9e82012-06-09 02:02:46 -0400250 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700251 if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
Behdad Esfahbod2fe5f882017-12-19 14:48:26 -0500252 if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400253 dirty ();
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800254 unsigned int ma = get_major (a);
255 unsigned int mb = get_major (b);
256 if (ma == mb)
257 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500258 page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800259 page->add_range (a, b);
260 }
261 else
262 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500263 page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800264 page->add_range (a, major_start (ma + 1) - 1);
265
266 for (unsigned int m = ma + 1; m < mb; m++)
267 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500268 page = page_for_insert (major_start (m)); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800269 page->init1 ();
270 }
271
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500272 page = page_for_insert (b); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800273 page->add_range (major_start (mb), b);
274 }
Behdad Esfahbod81f27df2017-12-16 06:12:06 -0800275 return true;
Behdad Esfahbod67bb9e82012-06-09 02:02:46 -0400276 }
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800277
Behdad Esfahbod0fe62c12017-12-13 13:12:20 -0800278 template <typename T>
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800279 inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
Behdad Esfahbod0fe62c12017-12-13 13:12:20 -0800280 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700281 if (unlikely (!successful)) return;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500282 if (!count) return;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400283 dirty ();
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500284 hb_codepoint_t g = *array;
285 while (count)
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800286 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500287 unsigned int m = get_major (g);
288 page_t *page = page_for_insert (g); if (unlikely (!page)) return;
289 unsigned int start = major_start (m);
290 unsigned int end = major_start (m + 1);
291 do
292 {
293 page->add (g);
294
Behdad Esfahbod34ac3542018-02-07 18:07:45 -0600295 array = (const T *) ((const char *) array + stride);
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500296 count--;
297 }
298 while (count && (g = *array, start <= g && g < end));
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800299 }
Behdad Esfahbod0fe62c12017-12-13 13:12:20 -0800300 }
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500301
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800302 /* Might return false if array looks unsorted.
303 * Used for faster rejection of corrupt data. */
304 template <typename T>
305 inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
306 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700307 if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500308 if (!count) return true;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400309 dirty ();
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500310 hb_codepoint_t g = *array;
Behdad Esfahbod493a0052017-12-16 11:49:39 -0500311 hb_codepoint_t last_g = g;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500312 while (count)
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800313 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500314 unsigned int m = get_major (g);
315 page_t *page = page_for_insert (g); if (unlikely (!page)) return false;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500316 unsigned int end = major_start (m + 1);
317 do
318 {
Behdad Esfahbod493a0052017-12-16 11:49:39 -0500319 /* If we try harder we can change the following comparison to <=;
320 * Not sure if it's worth it. */
321 if (g < last_g) return false;
322 last_g = g;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500323 page->add (g);
324
Behdad Esfahbod34ac3542018-02-07 18:07:45 -0600325 array = (const T *) ((const char *) array + stride);
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500326 count--;
327 }
Behdad Esfahbod493a0052017-12-16 11:49:39 -0500328 while (count && (g = *array, g < end));
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800329 }
330 return true;
331 }
332
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400333 inline void del (hb_codepoint_t g)
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400334 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700335 /* TODO perform op even if !successful. */
336 if (unlikely (!successful)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200337 page_t *p = page_for (g);
338 if (!p)
339 return;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400340 dirty ();
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200341 p->del (g);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400342 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800343 inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
344 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700345 /* TODO perform op even if !successful. */
Behdad Esfahbodeeb26d22017-12-02 15:22:04 -0800346 /* TODO Optimize, like add_range(). */
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700347 if (unlikely (!successful)) return;
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800348 for (unsigned int i = a; i < b + 1; i++)
349 del (i);
350 }
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400351 inline bool has (hb_codepoint_t g) const
352 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200353 const page_t *p = page_for (g);
354 if (!p)
355 return false;
356 return p->has (g);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400357 }
358 inline bool intersects (hb_codepoint_t first,
359 hb_codepoint_t last) const
360 {
Behdad Esfahbod10d43652017-10-15 16:56:05 -0400361 hb_codepoint_t c = first - 1;
362 return next (&c) && c <= last;
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400363 }
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400364 inline void set (const hb_set_t *other)
365 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700366 if (unlikely (!successful)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200367 unsigned int count = other->pages.len;
368 if (!resize (count))
369 return;
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400370 population = other->population;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700371 memcpy (pages.arrayZ, other->pages.arrayZ, count * sizeof (pages.arrayZ[0]));
372 memcpy (page_map.arrayZ, other->page_map.arrayZ, count * sizeof (page_map.arrayZ[0]));
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400373 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200374
375 inline bool is_equal (const hb_set_t *other) const
376 {
Behdad Esfahboddd22c292018-05-22 20:57:19 -0700377 if (get_population () != other->get_population ())
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400378 return false;
379
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200380 unsigned int na = pages.len;
381 unsigned int nb = other->pages.len;
382
383 unsigned int a = 0, b = 0;
384 for (; a < na && b < nb; )
385 {
386 if (page_at (a).is_empty ()) { a++; continue; }
387 if (other->page_at (b).is_empty ()) { b++; continue; }
388 if (page_map[a].major != other->page_map[b].major ||
389 !page_at (a).is_equal (&other->page_at (b)))
390 return false;
391 a++;
392 b++;
393 }
394 for (; a < na; a++)
395 if (!page_at (a).is_empty ()) { return false; }
396 for (; b < nb; b++)
397 if (!other->page_at (b).is_empty ()) { return false; }
398
399 return true;
400 }
401
Behdad Esfahbod11f1f412018-06-06 16:46:50 -0700402 inline bool is_subset (const hb_set_t *larger_set) const
403 {
404 if (get_population () > larger_set->get_population ())
405 return false;
406
Behdad Esfahbod7cb47d02018-07-10 12:51:29 +0200407 /* TODO Optimize to use pages. */
Behdad Esfahbod11f1f412018-06-06 16:46:50 -0700408 hb_codepoint_t c = INVALID;
409 while (next (&c))
410 if (!larger_set->has (c))
411 return false;
412
413 return true;
414 }
415
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200416 template <class Op>
417 inline void process (const hb_set_t *other)
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400418 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700419 if (unlikely (!successful)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200420
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400421 dirty ();
422
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400423 unsigned int na = pages.len;
424 unsigned int nb = other->pages.len;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100425 unsigned int next_page = na;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200426
Jonathan Kew82484b02018-06-11 20:55:14 -0700427 unsigned int count = 0, newCount = 0;
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400428 unsigned int a = 0, b = 0;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200429 for (; a < na && b < nb; )
430 {
431 if (page_map[a].major == other->page_map[b].major)
432 {
433 count++;
434 a++;
435 b++;
436 }
437 else if (page_map[a].major < other->page_map[b].major)
438 {
439 if (Op::passthru_left)
440 count++;
441 a++;
442 }
443 else
444 {
445 if (Op::passthru_right)
446 count++;
447 b++;
448 }
449 }
450 if (Op::passthru_left)
451 count += na - a;
452 if (Op::passthru_right)
453 count += nb - b;
454
Jonathan Kew82484b02018-06-11 20:55:14 -0700455 if (count > pages.len)
456 if (!resize (count))
457 return;
458 newCount = count;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200459
460 /* Process in-place backward. */
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400461 a = na;
462 b = nb;
463 for (; a && b; )
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200464 {
Jonathan Kewdfd234a2017-10-26 16:59:50 +0100465 if (page_map[a - 1].major == other->page_map[b - 1].major)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200466 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200467 a--;
468 b--;
Behdad Esfahbod75876832018-03-07 09:55:22 +0100469 count--;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100470 page_map[count] = page_map[a];
Behdad Esfahbod75876832018-03-07 09:55:22 +0100471 Op::process (page_at (count).v, page_at (a).v, other->page_at (b).v);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200472 }
Jonathan Kewdfd234a2017-10-26 16:59:50 +0100473 else if (page_map[a - 1].major > other->page_map[b - 1].major)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200474 {
Behdad Esfahbod75876832018-03-07 09:55:22 +0100475 a--;
476 if (Op::passthru_left)
477 {
478 count--;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100479 page_map[count] = page_map[a];
Behdad Esfahbod75876832018-03-07 09:55:22 +0100480 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200481 }
482 else
483 {
Behdad Esfahbod75876832018-03-07 09:55:22 +0100484 b--;
485 if (Op::passthru_right)
486 {
487 count--;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100488 page_map[count].major = other->page_map[b].major;
489 page_map[count].index = next_page++;
Behdad Esfahbod75876832018-03-07 09:55:22 +0100490 page_at (count).v = other->page_at (b).v;
491 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200492 }
493 }
Behdad Esfahbod81708012017-10-23 14:26:48 -0400494 if (Op::passthru_left)
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400495 while (a)
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100496 {
497 a--;
498 count--;
499 page_map[count] = page_map [a];
500 }
Behdad Esfahbod81708012017-10-23 14:26:48 -0400501 if (Op::passthru_right)
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400502 while (b)
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100503 {
504 b--;
505 count--;
506 page_map[count].major = other->page_map[b].major;
507 page_map[count].index = next_page++;
508 page_at (count).v = other->page_at (b).v;
509 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200510 assert (!count);
Jonathan Kew82484b02018-06-11 20:55:14 -0700511 if (pages.len > newCount)
512 resize (newCount);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200513 }
514
515 inline void union_ (const hb_set_t *other)
516 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400517 process<HbOpOr> (other);
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400518 }
519 inline void intersect (const hb_set_t *other)
520 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400521 process<HbOpAnd> (other);
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400522 }
523 inline void subtract (const hb_set_t *other)
524 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400525 process<HbOpMinus> (other);
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400526 }
Behdad Esfahbod62c3e112012-05-25 13:48:00 -0400527 inline void symmetric_difference (const hb_set_t *other)
528 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400529 process<HbOpXor> (other);
Behdad Esfahbod8165f272013-01-02 22:50:36 -0600530 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800531 inline bool next (hb_codepoint_t *codepoint) const
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400532 {
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400533 if (unlikely (*codepoint == INVALID)) {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200534 *codepoint = get_min ();
535 return *codepoint != INVALID;
536 }
537
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400538 page_map_t map = {get_major (*codepoint), 0};
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200539 unsigned int i;
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600540 page_map.bfind (map, &i);
Behdad Esfahbodfe3bc522018-02-13 23:51:45 -0800541 if (i < page_map.len && page_map[i].major == map.major)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200542 {
543 if (pages[page_map[i].index].next (codepoint))
544 {
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400545 *codepoint += page_map[i].major * page_t::PAGE_BITS;
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800546 return true;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200547 }
548 i++;
549 }
550 for (; i < page_map.len; i++)
551 {
552 hb_codepoint_t m = pages[page_map[i].index].get_min ();
553 if (m != INVALID)
554 {
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400555 *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400556 return true;
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400557 }
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400558 }
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400559 *codepoint = INVALID;
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400560 return false;
561 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800562 inline bool previous (hb_codepoint_t *codepoint) const
563 {
564 if (unlikely (*codepoint == INVALID)) {
565 *codepoint = get_max ();
566 return *codepoint != INVALID;
567 }
568
569 page_map_t map = {get_major (*codepoint), 0};
570 unsigned int i;
571 page_map.bfind (map, &i);
572 if (i < page_map.len && page_map[i].major == map.major)
573 {
574 if (pages[page_map[i].index].previous (codepoint))
575 {
576 *codepoint += page_map[i].major * page_t::PAGE_BITS;
577 return true;
578 }
579 }
580 i--;
581 for (; (int) i >= 0; i--)
582 {
583 hb_codepoint_t m = pages[page_map[i].index].get_max ();
584 if (m != INVALID)
585 {
586 *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
587 return true;
588 }
589 }
590 *codepoint = INVALID;
591 return false;
592 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800593 inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
594 {
595 hb_codepoint_t i;
596
597 i = *last;
598 if (!next (&i))
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400599 {
600 *last = *first = INVALID;
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800601 return false;
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400602 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800603
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800604 /* TODO Speed up. */
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800605 *last = *first = i;
606 while (next (&i) && i == *last + 1)
607 (*last)++;
608
609 return true;
610 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800611 inline bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
612 {
613 hb_codepoint_t i;
614
615 i = *first;
616 if (!previous (&i))
617 {
618 *last = *first = INVALID;
619 return false;
620 }
621
622 /* TODO Speed up. */
623 *last = *first = i;
624 while (previous (&i) && i == *first - 1)
625 (*first)--;
626
627 return true;
628 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800629
630 inline unsigned int get_population (void) const
631 {
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400632 if (population != (unsigned int) -1)
633 return population;
634
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200635 unsigned int pop = 0;
636 unsigned int count = pages.len;
637 for (unsigned int i = 0; i < count; i++)
638 pop += pages[i].get_population ();
Behdad Esfahbodbd5f9182018-05-01 18:27:41 -0400639
640 population = pop;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200641 return pop;
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800642 }
Behdad Esfahbodf039e792012-05-17 20:55:12 -0400643 inline hb_codepoint_t get_min (void) const
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400644 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200645 unsigned int count = pages.len;
646 for (unsigned int i = 0; i < count; i++)
647 if (!page_at (i).is_empty ())
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400648 return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400649 return INVALID;
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400650 }
Behdad Esfahbodf039e792012-05-17 20:55:12 -0400651 inline hb_codepoint_t get_max (void) const
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400652 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200653 unsigned int count = pages.len;
654 for (int i = count - 1; i >= 0; i++)
655 if (!page_at (i).is_empty ())
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400656 return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_max ();
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400657 return INVALID;
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400658 }
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400659
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400660 static const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400661
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800662 inline page_t *page_for_insert (hb_codepoint_t g)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200663 {
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400664 page_map_t map = {get_major (g), pages.len};
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200665 unsigned int i;
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600666 if (!page_map.bfind (map, &i))
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200667 {
668 if (!resize (pages.len + 1))
669 return nullptr;
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400670
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800671 pages[map.index].init0 ();
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200672 memmove (&page_map[i + 1], &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0]));
673 page_map[i] = map;
674 }
675 return &pages[page_map[i].index];
676 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800677 inline page_t *page_for (hb_codepoint_t g)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200678 {
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400679 page_map_t key = {get_major (g)};
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600680 const page_map_t *found = page_map.bsearch (key);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200681 if (found)
682 return &pages[found->index];
683 return nullptr;
684 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800685 inline const page_t *page_for (hb_codepoint_t g) const
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200686 {
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400687 page_map_t key = {get_major (g)};
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600688 const page_map_t *found = page_map.bsearch (key);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200689 if (found)
690 return &pages[found->index];
691 return nullptr;
692 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800693 inline page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
694 inline const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
695 inline unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
696 inline hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400697};
698
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400699
Behdad Esfahbodc77ae402018-08-25 22:36:36 -0700700#endif /* HB_SET_HH */