blob: 3615c50e9e2b1817ee288e655e5769a66bc06182 [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
27#ifndef HB_SET_PRIVATE_HH
28#define HB_SET_PRIVATE_HH
29
30#include "hb-private.hh"
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -040031#include "hb-object-private.hh"
32
33
Behdad Esfahbod0edd0fd2013-04-17 17:26:56 -040034/*
Behdad Esfahbod0d5798a2013-04-17 18:19:21 -040035 * hb_set_t
36 */
Behdad Esfahbodb40f2c02013-04-16 23:21:38 -040037
Behdad Esfahbodeeb26d22017-12-02 15:22:04 -080038/* TODO Keep a free-list so we can free pages that are completely zeroed. At that
39 * point maybe also use a sentinel value for "all-1" pages? */
40
Behdad Esfahbod1bc1cb32012-06-16 15:21:55 -040041struct hb_set_t
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -040042{
Behdad Esfahboddeed4a42017-10-15 16:53:09 +020043 struct page_map_t
44 {
45 inline int cmp (const page_map_t *o) const { return (int) o->major - (int) major; }
46
47 uint32_t major;
48 uint32_t index;
49 };
50
51 struct page_t
52 {
Behdad Esfahbod438c3252017-12-01 13:34:14 -080053 inline void init0 (void) { memset (&v, 0, sizeof (v)); }
54 inline void init1 (void) { memset (&v, 0xff, sizeof (v)); }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +020055
56 inline unsigned int len (void) const
57 { return ARRAY_LENGTH_CONST (v); }
58
59 inline bool is_empty (void) const
60 {
61 for (unsigned int i = 0; i < len (); i++)
62 if (v[i])
63 return false;
64 return true;
65 }
66
67 inline void add (hb_codepoint_t g) { elt (g) |= mask (g); }
68 inline void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
69 inline bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }
70
Behdad Esfahbod438c3252017-12-01 13:34:14 -080071 inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
72 {
Behdad Esfahbod81f27df2017-12-16 06:12:06 -080073 elt_t *la = &elt (a);
74 elt_t *lb = &elt (b);
75 if (la == lb)
76 *la |= (mask (b) << 1) - mask(a);
77 else
78 {
79 *la |= ~(mask (a) - 1);
80 la++;
Behdad Esfahbod9d0194b2017-12-01 13:56:06 -080081
Behdad Esfahbod81f27df2017-12-16 06:12:06 -080082 memset (la, 0xff, (char *) lb - (char *) la);
Behdad Esfahbod9d0194b2017-12-01 13:56:06 -080083
Behdad Esfahbod81f27df2017-12-16 06:12:06 -080084 *lb |= ((mask (b) << 1) - 1);
85 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -080086 }
87
Behdad Esfahboddeed4a42017-10-15 16:53:09 +020088 inline bool is_equal (const page_t *other) const
89 {
90 return 0 == memcmp (&v, &other->v, sizeof (v));
91 }
92
93 inline unsigned int get_population (void) const
94 {
95 unsigned int pop = 0;
96 for (unsigned int i = 0; i < len (); i++)
97 pop += _hb_popcount (v[i]);
98 return pop;
99 }
100
101 inline bool next (hb_codepoint_t *codepoint) const
102 {
103 unsigned int m = (*codepoint + 1) & MASK;
104 if (!m)
105 {
106 *codepoint = INVALID;
107 return false;
108 }
109 unsigned int i = m / ELT_BITS;
110 unsigned int j = m & ELT_MASK;
111
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800112 const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
113 for (const elt_t *p = &vv; i < len (); p = &v[++i])
114 if (*p)
115 {
116 *codepoint = i * ELT_BITS + elt_get_min (*p);
117 return true;
118 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200119
120 *codepoint = INVALID;
121 return false;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200122 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800123 inline bool previous (hb_codepoint_t *codepoint) const
124 {
125 unsigned int m = (*codepoint - 1) & MASK;
126 if (m == MASK)
127 {
128 *codepoint = INVALID;
129 return false;
130 }
131 unsigned int i = m / ELT_BITS;
132 unsigned int j = m & ELT_MASK;
133
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800134 const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1);
135 for (const elt_t *p = &vv; (int) i >= 0; p = &v[--i])
136 if (*p)
137 {
138 *codepoint = i * ELT_BITS + elt_get_max (*p);
139 return true;
140 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800141
142 *codepoint = INVALID;
143 return false;
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800144 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200145 inline hb_codepoint_t get_min (void) const
146 {
147 for (unsigned int i = 0; i < len (); i++)
148 if (v[i])
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800149 return i * ELT_BITS + elt_get_min (v[i]);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200150 return INVALID;
151 }
152 inline hb_codepoint_t get_max (void) const
153 {
154 for (int i = len () - 1; i >= 0; i--)
155 if (v[i])
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800156 return i * ELT_BITS + elt_get_max (v[i]);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200157 return 0;
158 }
159
Behdad Esfahbodd25c3e62018-02-16 17:45:09 -0800160 typedef unsigned long long elt_t;
161 static const unsigned int PAGE_BITS = 1024;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200162 static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
163
Behdad Esfahbodf18b9fb2018-02-16 18:14:41 -0800164 static inline unsigned int elt_get_min (const elt_t &elt) { return _hb_ctz (elt); }
165 static inline unsigned int elt_get_max (const elt_t &elt) { return _hb_bit_storage (elt) - 1; }
166
Behdad Esfahbodbb991792017-10-15 18:20:25 -0400167#if 0 && HAVE_VECTOR_SIZE
168 /* The vectorized version does not work with clang as non-const
Behdad Esfahbodab8f3272017-10-15 18:21:35 -0400169 * elt() errs "non-const reference cannot bind to vector element". */
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200170 typedef elt_t vector_t __attribute__((vector_size (PAGE_BITS / 8)));
171#else
Behdad Esfahbod7737e872017-10-15 16:21:03 -0400172 typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200173#endif
174
175 vector_t v;
176
Behdad Esfahbodd25c3e62018-02-16 17:45:09 -0800177 static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200178 static const unsigned int ELT_MASK = ELT_BITS - 1;
Behdad Esfahbodba8b5692017-10-17 11:16:36 -0700179 static const unsigned int BITS = sizeof (vector_t) * 8;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200180 static const unsigned int MASK = BITS - 1;
181 static_assert (PAGE_BITS == BITS, "");
182
183 elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
184 elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
185 elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & ELT_MASK); }
186 };
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400187 static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200188
Behdad Esfahbod6220e5f2012-06-06 03:30:09 -0400189 hb_object_header_t header;
190 ASSERT_POD ();
Behdad Esfahbod8165f272013-01-02 22:50:36 -0600191 bool in_error;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200192 hb_prealloced_array_t<page_map_t, 8> page_map;
Behdad Esfahbod9d6511a2017-12-14 19:04:55 -0800193 hb_prealloced_array_t<page_t, 1> pages;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200194
Behdad Esfahbod9daa88c2017-12-14 13:37:48 -0800195 inline void init (void)
196 {
Behdad Esfahbodc9e12a22018-01-13 17:05:12 +0000197 in_error = false;
Behdad Esfahbod9daa88c2017-12-14 13:37:48 -0800198 page_map.init ();
199 pages.init ();
200 }
201 inline void finish (void)
202 {
203 page_map.finish ();
204 pages.finish ();
205 }
206
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200207 inline bool resize (unsigned int count)
208 {
209 if (unlikely (in_error)) return false;
210 if (!pages.resize (count) || !page_map.resize (count))
211 {
212 pages.resize (page_map.len);
213 in_error = true;
214 return false;
215 }
216 return true;
217 }
Behdad Esfahbod6220e5f2012-06-06 03:30:09 -0400218
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400219 inline void clear (void) {
Behdad Esfahbod7b1b7202013-01-02 23:02:59 -0600220 if (unlikely (hb_object_is_inert (this)))
221 return;
222 in_error = false;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200223 page_map.resize (0);
224 pages.resize (0);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400225 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800226 inline bool is_empty (void) const {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200227 unsigned int count = pages.len;
228 for (unsigned int i = 0; i < count; i++)
229 if (!pages[i].is_empty ())
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400230 return false;
231 return true;
232 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200233
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400234 inline void add (hb_codepoint_t g)
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400235 {
Behdad Esfahbod7b1b7202013-01-02 23:02:59 -0600236 if (unlikely (in_error)) return;
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400237 if (unlikely (g == INVALID)) return;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500238 page_t *page = page_for_insert (g); if (unlikely (!page)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200239 page->add (g);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400240 }
Behdad Esfahbod81f27df2017-12-16 06:12:06 -0800241 inline bool add_range (hb_codepoint_t a, hb_codepoint_t b)
Behdad Esfahbod67bb9e82012-06-09 02:02:46 -0400242 {
Behdad Esfahbod2fe5f882017-12-19 14:48:26 -0500243 if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
244 if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800245 unsigned int ma = get_major (a);
246 unsigned int mb = get_major (b);
247 if (ma == mb)
248 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500249 page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800250 page->add_range (a, b);
251 }
252 else
253 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500254 page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800255 page->add_range (a, major_start (ma + 1) - 1);
256
257 for (unsigned int m = ma + 1; m < mb; m++)
258 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500259 page = page_for_insert (major_start (m)); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800260 page->init1 ();
261 }
262
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500263 page = page_for_insert (b); if (unlikely (!page)) return false;
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800264 page->add_range (major_start (mb), b);
265 }
Behdad Esfahbod81f27df2017-12-16 06:12:06 -0800266 return true;
Behdad Esfahbod67bb9e82012-06-09 02:02:46 -0400267 }
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800268
Behdad Esfahbod0fe62c12017-12-13 13:12:20 -0800269 template <typename T>
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800270 inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
Behdad Esfahbod0fe62c12017-12-13 13:12:20 -0800271 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500272 if (unlikely (in_error)) return;
273 if (!count) return;
274 hb_codepoint_t g = *array;
275 while (count)
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800276 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500277 unsigned int m = get_major (g);
278 page_t *page = page_for_insert (g); if (unlikely (!page)) return;
279 unsigned int start = major_start (m);
280 unsigned int end = major_start (m + 1);
281 do
282 {
283 page->add (g);
284
Behdad Esfahbod34ac3542018-02-07 18:07:45 -0600285 array = (const T *) ((const char *) array + stride);
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500286 count--;
287 }
288 while (count && (g = *array, start <= g && g < end));
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800289 }
Behdad Esfahbod0fe62c12017-12-13 13:12:20 -0800290 }
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500291
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800292 /* Might return false if array looks unsorted.
293 * Used for faster rejection of corrupt data. */
294 template <typename T>
295 inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
296 {
Behdad Esfahbod2fe5f882017-12-19 14:48:26 -0500297 if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500298 if (!count) return true;
299 hb_codepoint_t g = *array;
Behdad Esfahbod493a0052017-12-16 11:49:39 -0500300 hb_codepoint_t last_g = g;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500301 while (count)
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800302 {
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500303 unsigned int m = get_major (g);
304 page_t *page = page_for_insert (g); if (unlikely (!page)) return false;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500305 unsigned int end = major_start (m + 1);
306 do
307 {
Behdad Esfahbod493a0052017-12-16 11:49:39 -0500308 /* If we try harder we can change the following comparison to <=;
309 * Not sure if it's worth it. */
310 if (g < last_g) return false;
311 last_g = g;
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500312 page->add (g);
313
Behdad Esfahbod34ac3542018-02-07 18:07:45 -0600314 array = (const T *) ((const char *) array + stride);
Behdad Esfahbod1ce7d6e2017-12-16 11:36:16 -0500315 count--;
316 }
Behdad Esfahbod493a0052017-12-16 11:49:39 -0500317 while (count && (g = *array, g < end));
Behdad Esfahbod5d025722017-12-14 19:33:55 -0800318 }
319 return true;
320 }
321
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400322 inline void del (hb_codepoint_t g)
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400323 {
Behdad Esfahbod7b1b7202013-01-02 23:02:59 -0600324 if (unlikely (in_error)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200325 page_t *p = page_for (g);
326 if (!p)
327 return;
328 p->del (g);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400329 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800330 inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
331 {
Behdad Esfahbodeeb26d22017-12-02 15:22:04 -0800332 /* TODO Optimize, like add_range(). */
Behdad Esfahbod7b1b7202013-01-02 23:02:59 -0600333 if (unlikely (in_error)) return;
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800334 for (unsigned int i = a; i < b + 1; i++)
335 del (i);
336 }
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400337 inline bool has (hb_codepoint_t g) const
338 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200339 const page_t *p = page_for (g);
340 if (!p)
341 return false;
342 return p->has (g);
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400343 }
344 inline bool intersects (hb_codepoint_t first,
345 hb_codepoint_t last) const
346 {
Behdad Esfahbod10d43652017-10-15 16:56:05 -0400347 hb_codepoint_t c = first - 1;
348 return next (&c) && c <= last;
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400349 }
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400350 inline void set (const hb_set_t *other)
351 {
Behdad Esfahbod7b1b7202013-01-02 23:02:59 -0600352 if (unlikely (in_error)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200353 unsigned int count = other->pages.len;
354 if (!resize (count))
355 return;
356
357 memcpy (pages.array, other->pages.array, count * sizeof (pages.array[0]));
358 memcpy (page_map.array, other->page_map.array, count * sizeof (page_map.array[0]));
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400359 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200360
361 inline bool is_equal (const hb_set_t *other) const
362 {
363 unsigned int na = pages.len;
364 unsigned int nb = other->pages.len;
365
366 unsigned int a = 0, b = 0;
367 for (; a < na && b < nb; )
368 {
369 if (page_at (a).is_empty ()) { a++; continue; }
370 if (other->page_at (b).is_empty ()) { b++; continue; }
371 if (page_map[a].major != other->page_map[b].major ||
372 !page_at (a).is_equal (&other->page_at (b)))
373 return false;
374 a++;
375 b++;
376 }
377 for (; a < na; a++)
378 if (!page_at (a).is_empty ()) { return false; }
379 for (; b < nb; b++)
380 if (!other->page_at (b).is_empty ()) { return false; }
381
382 return true;
383 }
384
385 template <class Op>
386 inline void process (const hb_set_t *other)
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400387 {
Behdad Esfahbod7b1b7202013-01-02 23:02:59 -0600388 if (unlikely (in_error)) return;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200389
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400390 unsigned int na = pages.len;
391 unsigned int nb = other->pages.len;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100392 unsigned int next_page = na;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200393
394 unsigned int count = 0;
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400395 unsigned int a = 0, b = 0;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200396 for (; a < na && b < nb; )
397 {
398 if (page_map[a].major == other->page_map[b].major)
399 {
400 count++;
401 a++;
402 b++;
403 }
404 else if (page_map[a].major < other->page_map[b].major)
405 {
406 if (Op::passthru_left)
407 count++;
408 a++;
409 }
410 else
411 {
412 if (Op::passthru_right)
413 count++;
414 b++;
415 }
416 }
417 if (Op::passthru_left)
418 count += na - a;
419 if (Op::passthru_right)
420 count += nb - b;
421
422 if (!resize (count))
423 return;
424
425 /* Process in-place backward. */
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400426 a = na;
427 b = nb;
428 for (; a && b; )
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200429 {
Jonathan Kewdfd234a2017-10-26 16:59:50 +0100430 if (page_map[a - 1].major == other->page_map[b - 1].major)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200431 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200432 a--;
433 b--;
Behdad Esfahbod75876832018-03-07 09:55:22 +0100434 count--;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100435 page_map[count] = page_map[a];
Behdad Esfahbod75876832018-03-07 09:55:22 +0100436 Op::process (page_at (count).v, page_at (a).v, other->page_at (b).v);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200437 }
Jonathan Kewdfd234a2017-10-26 16:59:50 +0100438 else if (page_map[a - 1].major > other->page_map[b - 1].major)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200439 {
Behdad Esfahbod75876832018-03-07 09:55:22 +0100440 a--;
441 if (Op::passthru_left)
442 {
443 count--;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100444 page_map[count] = page_map[a];
Behdad Esfahbod75876832018-03-07 09:55:22 +0100445 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200446 }
447 else
448 {
Behdad Esfahbod75876832018-03-07 09:55:22 +0100449 b--;
450 if (Op::passthru_right)
451 {
452 count--;
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100453 page_map[count].major = other->page_map[b].major;
454 page_map[count].index = next_page++;
Behdad Esfahbod75876832018-03-07 09:55:22 +0100455 page_at (count).v = other->page_at (b).v;
456 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200457 }
458 }
Behdad Esfahbod81708012017-10-23 14:26:48 -0400459 if (Op::passthru_left)
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400460 while (a)
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100461 {
462 a--;
463 count--;
464 page_map[count] = page_map [a];
465 }
Behdad Esfahbod81708012017-10-23 14:26:48 -0400466 if (Op::passthru_right)
Behdad Esfahbod30a591e2017-10-23 14:28:35 -0400467 while (b)
Behdad Esfahbodf014a122018-03-07 10:49:26 +0100468 {
469 b--;
470 count--;
471 page_map[count].major = other->page_map[b].major;
472 page_map[count].index = next_page++;
473 page_at (count).v = other->page_at (b).v;
474 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200475 assert (!count);
476 }
477
478 inline void union_ (const hb_set_t *other)
479 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400480 process<HbOpOr> (other);
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400481 }
482 inline void intersect (const hb_set_t *other)
483 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400484 process<HbOpAnd> (other);
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400485 }
486 inline void subtract (const hb_set_t *other)
487 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400488 process<HbOpMinus> (other);
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400489 }
Behdad Esfahbod62c3e112012-05-25 13:48:00 -0400490 inline void symmetric_difference (const hb_set_t *other)
491 {
Behdad Esfahbodf8a0ec52017-10-15 16:10:35 -0400492 process<HbOpXor> (other);
Behdad Esfahbod8165f272013-01-02 22:50:36 -0600493 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800494 inline bool next (hb_codepoint_t *codepoint) const
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400495 {
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400496 if (unlikely (*codepoint == INVALID)) {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200497 *codepoint = get_min ();
498 return *codepoint != INVALID;
499 }
500
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400501 page_map_t map = {get_major (*codepoint), 0};
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200502 unsigned int i;
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600503 page_map.bfind (map, &i);
Behdad Esfahbodfe3bc522018-02-13 23:51:45 -0800504 if (i < page_map.len && page_map[i].major == map.major)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200505 {
506 if (pages[page_map[i].index].next (codepoint))
507 {
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400508 *codepoint += page_map[i].major * page_t::PAGE_BITS;
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800509 return true;
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200510 }
511 i++;
512 }
513 for (; i < page_map.len; i++)
514 {
515 hb_codepoint_t m = pages[page_map[i].index].get_min ();
516 if (m != INVALID)
517 {
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400518 *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400519 return true;
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400520 }
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400521 }
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400522 *codepoint = INVALID;
Behdad Esfahbod29ce4462012-05-25 14:17:54 -0400523 return false;
524 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800525 inline bool previous (hb_codepoint_t *codepoint) const
526 {
527 if (unlikely (*codepoint == INVALID)) {
528 *codepoint = get_max ();
529 return *codepoint != INVALID;
530 }
531
532 page_map_t map = {get_major (*codepoint), 0};
533 unsigned int i;
534 page_map.bfind (map, &i);
535 if (i < page_map.len && page_map[i].major == map.major)
536 {
537 if (pages[page_map[i].index].previous (codepoint))
538 {
539 *codepoint += page_map[i].major * page_t::PAGE_BITS;
540 return true;
541 }
542 }
543 i--;
544 for (; (int) i >= 0; i--)
545 {
546 hb_codepoint_t m = pages[page_map[i].index].get_max ();
547 if (m != INVALID)
548 {
549 *codepoint = page_map[i].major * page_t::PAGE_BITS + m;
550 return true;
551 }
552 }
553 *codepoint = INVALID;
554 return false;
555 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800556 inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
557 {
558 hb_codepoint_t i;
559
560 i = *last;
561 if (!next (&i))
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400562 {
563 *last = *first = INVALID;
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800564 return false;
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400565 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800566
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800567 /* TODO Speed up. */
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800568 *last = *first = i;
569 while (next (&i) && i == *last + 1)
570 (*last)++;
571
572 return true;
573 }
Behdad Esfahbod694eaf62018-02-14 01:00:10 -0800574 inline bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
575 {
576 hb_codepoint_t i;
577
578 i = *first;
579 if (!previous (&i))
580 {
581 *last = *first = INVALID;
582 return false;
583 }
584
585 /* TODO Speed up. */
586 *last = *first = i;
587 while (previous (&i) && i == *first - 1)
588 (*first)--;
589
590 return true;
591 }
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800592
593 inline unsigned int get_population (void) const
594 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200595 unsigned int pop = 0;
596 unsigned int count = pages.len;
597 for (unsigned int i = 0; i < count; i++)
598 pop += pages[i].get_population ();
599 return pop;
Behdad Esfahbodaec89de2012-11-15 16:15:42 -0800600 }
Behdad Esfahbodf039e792012-05-17 20:55:12 -0400601 inline hb_codepoint_t get_min (void) const
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400602 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200603 unsigned int count = pages.len;
604 for (unsigned int i = 0; i < count; i++)
605 if (!page_at (i).is_empty ())
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400606 return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400607 return INVALID;
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400608 }
Behdad Esfahbodf039e792012-05-17 20:55:12 -0400609 inline hb_codepoint_t get_max (void) const
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400610 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200611 unsigned int count = pages.len;
612 for (int i = count - 1; i >= 0; i++)
613 if (!page_at (i).is_empty ())
Behdad Esfahbodd0f0ff82017-10-23 08:34:30 -0400614 return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_max ();
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400615 return INVALID;
Behdad Esfahbod6c6ccaf2012-04-24 14:21:15 -0400616 }
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400617
Behdad Esfahbod20cbc1f2013-09-06 15:29:22 -0400618 static const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400619
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800620 inline page_t *page_for_insert (hb_codepoint_t g)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200621 {
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400622 page_map_t map = {get_major (g), pages.len};
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200623 unsigned int i;
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600624 if (!page_map.bfind (map, &i))
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200625 {
626 if (!resize (pages.len + 1))
627 return nullptr;
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400628
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800629 pages[map.index].init0 ();
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200630 memmove (&page_map[i + 1], &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0]));
631 page_map[i] = map;
632 }
633 return &pages[page_map[i].index];
634 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800635 inline page_t *page_for (hb_codepoint_t g)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200636 {
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400637 page_map_t key = {get_major (g)};
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600638 const page_map_t *found = page_map.bsearch (key);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200639 if (found)
640 return &pages[found->index];
641 return nullptr;
642 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800643 inline const page_t *page_for (hb_codepoint_t g) const
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200644 {
Behdad Esfahboddd33e4e2017-10-23 08:36:40 -0400645 page_map_t key = {get_major (g)};
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600646 const page_map_t *found = page_map.bsearch (key);
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200647 if (found)
648 return &pages[found->index];
649 return nullptr;
650 }
Behdad Esfahbod438c3252017-12-01 13:34:14 -0800651 inline page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
652 inline const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
653 inline unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
654 inline hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400655};
656
Behdad Esfahbod0b08adb2012-04-23 22:41:09 -0400657
658#endif /* HB_SET_PRIVATE_HH */