comparison mupdf-source/thirdparty/harfbuzz/src/hb-bit-set.hh @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*
2 * Copyright © 2012,2017 Google, Inc.
3 * Copyright © 2021 Behdad Esfahbod
4 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Google Author(s): Behdad Esfahbod
26 */
27
28 #ifndef HB_BIT_SET_HH
29 #define HB_BIT_SET_HH
30
31 #include "hb.hh"
32 #include "hb-bit-page.hh"
33 #include "hb-machinery.hh"
34
35
36 struct hb_bit_set_t
37 {
38 hb_bit_set_t () = default;
39 ~hb_bit_set_t () = default;
40
41 hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); }
42 hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
43 hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
44 hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
45 friend void swap (hb_bit_set_t &a, hb_bit_set_t &b)
46 {
47 if (likely (!a.successful || !b.successful))
48 return;
49 hb_swap (a.population, b.population);
50 hb_swap (a.last_page_lookup, b.last_page_lookup);
51 hb_swap (a.page_map, b.page_map);
52 hb_swap (a.pages, b.pages);
53 }
54
55 void init ()
56 {
57 successful = true;
58 population = 0;
59 last_page_lookup = 0;
60 page_map.init ();
61 pages.init ();
62 }
63 void fini ()
64 {
65 page_map.fini ();
66 pages.fini ();
67 }
68
69 using page_t = hb_bit_page_t;
70 struct page_map_t
71 {
72 int cmp (const page_map_t &o) const { return cmp (o.major); }
73 int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
74
75 uint32_t major;
76 uint32_t index;
77 };
78
79 bool successful = true; /* Allocations successful */
80 mutable unsigned int population = 0;
81 mutable hb_atomic_int_t last_page_lookup = 0;
82 hb_sorted_vector_t<page_map_t> page_map;
83 hb_vector_t<page_t> pages;
84
85 void err () { if (successful) successful = false; } /* TODO Remove */
86 bool in_error () const { return !successful; }
87
88 bool resize (unsigned int count, bool clear = true)
89 {
90 if (unlikely (!successful)) return false;
91 if (unlikely (!pages.resize (count, clear) || !page_map.resize (count, clear)))
92 {
93 pages.resize (page_map.length);
94 successful = false;
95 return false;
96 }
97 return true;
98 }
99
100 void alloc (unsigned sz)
101 {
102 sz >>= (page_t::PAGE_BITS_LOG_2 - 1);
103 pages.alloc (sz);
104 page_map.alloc (sz);
105 }
106
107 void reset ()
108 {
109 successful = true;
110 clear ();
111 }
112
113 void clear ()
114 {
115 resize (0);
116 if (likely (successful))
117 population = 0;
118 }
119 bool is_empty () const
120 {
121 unsigned int count = pages.length;
122 for (unsigned int i = 0; i < count; i++)
123 if (!pages[i].is_empty ())
124 return false;
125 return true;
126 }
127 explicit operator bool () const { return !is_empty (); }
128
129 uint32_t hash () const
130 {
131 uint32_t h = 0;
132 for (auto &map : page_map)
133 h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]);
134 return h;
135 }
136
137 private:
138 void dirty () { population = UINT_MAX; }
139 public:
140
141 void add (hb_codepoint_t g)
142 {
143 if (unlikely (!successful)) return;
144 if (unlikely (g == INVALID)) return;
145 dirty ();
146 page_t *page = page_for (g, true); if (unlikely (!page)) return;
147 page->add (g);
148 }
149 bool add_range (hb_codepoint_t a, hb_codepoint_t b)
150 {
151 if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
152 if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
153 dirty ();
154 unsigned int ma = get_major (a);
155 unsigned int mb = get_major (b);
156 if (ma == mb)
157 {
158 page_t *page = page_for (a, true); if (unlikely (!page)) return false;
159 page->add_range (a, b);
160 }
161 else
162 {
163 page_t *page = page_for (a, true); if (unlikely (!page)) return false;
164 page->add_range (a, major_start (ma + 1) - 1);
165
166 for (unsigned int m = ma + 1; m < mb; m++)
167 {
168 page = page_for (major_start (m), true); if (unlikely (!page)) return false;
169 page->init1 ();
170 }
171
172 page = page_for (b, true); if (unlikely (!page)) return false;
173 page->add_range (major_start (mb), b);
174 }
175 return true;
176 }
177
178 template <typename T>
179 void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
180 {
181 if (unlikely (!successful)) return;
182 if (!count) return;
183 dirty ();
184 hb_codepoint_t g = *array;
185 while (count)
186 {
187 unsigned int m = get_major (g);
188 page_t *page = page_for (g, v); if (unlikely (v && !page)) return;
189 unsigned int start = major_start (m);
190 unsigned int end = major_start (m + 1);
191 do
192 {
193 if (v || page) /* The v check is to optimize out the page check if v is true. */
194 page->set (g, v);
195
196 array = &StructAtOffsetUnaligned<T> (array, stride);
197 count--;
198 }
199 while (count && (g = *array, start <= g && g < end));
200 }
201 }
202
203 template <typename T>
204 void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
205 { set_array (true, array, count, stride); }
206 template <typename T>
207 void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
208
209 template <typename T>
210 void del_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
211 { set_array (false, array, count, stride); }
212 template <typename T>
213 void del_array (const hb_array_t<const T>& arr) { del_array (&arr, arr.len ()); }
214
215 /* Might return false if array looks unsorted.
216 * Used for faster rejection of corrupt data. */
217 template <typename T>
218 bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
219 {
220 if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
221 if (unlikely (!count)) return true;
222 dirty ();
223 hb_codepoint_t g = *array;
224 hb_codepoint_t last_g = g;
225 while (count)
226 {
227 unsigned int m = get_major (g);
228 page_t *page = page_for (g, v); if (unlikely (v && !page)) return false;
229 unsigned int end = major_start (m + 1);
230 do
231 {
232 /* If we try harder we can change the following comparison to <=;
233 * Not sure if it's worth it. */
234 if (g < last_g) return false;
235 last_g = g;
236
237 if (v || page) /* The v check is to optimize out the page check if v is true. */
238 page->add (g);
239
240 array = &StructAtOffsetUnaligned<T> (array, stride);
241 count--;
242 }
243 while (count && (g = *array, g < end));
244 }
245 return true;
246 }
247
248 template <typename T>
249 bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
250 { return set_sorted_array (true, array, count, stride); }
251 template <typename T>
252 bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
253
254 template <typename T>
255 bool del_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
256 { return set_sorted_array (false, array, count, stride); }
257 template <typename T>
258 bool del_sorted_array (const hb_sorted_array_t<const T>& arr) { return del_sorted_array (&arr, arr.len ()); }
259
260 void del (hb_codepoint_t g)
261 {
262 if (unlikely (!successful)) return;
263 page_t *page = page_for (g);
264 if (!page)
265 return;
266 dirty ();
267 page->del (g);
268 }
269
270 private:
271 void del_pages (int ds, int de)
272 {
273 if (ds <= de)
274 {
275 // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
276 // before attempting to rewrite the page map.
277 hb_vector_t<unsigned> compact_workspace;
278 if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
279
280 unsigned int write_index = 0;
281 for (unsigned int i = 0; i < page_map.length; i++)
282 {
283 int m = (int) page_map[i].major;
284 if (m < ds || de < m)
285 page_map[write_index++] = page_map[i];
286 }
287 compact (compact_workspace, write_index);
288 resize (write_index);
289 }
290 }
291
292
293 public:
294 void del_range (hb_codepoint_t a, hb_codepoint_t b)
295 {
296 if (unlikely (!successful)) return;
297 if (unlikely (a > b || a == INVALID)) return;
298 dirty ();
299 unsigned int ma = get_major (a);
300 unsigned int mb = get_major (b);
301 /* Delete pages from ds through de if ds <= de. */
302 int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
303 int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
304 if (ds > de || (int) ma < ds)
305 {
306 page_t *page = page_for (a);
307 if (page)
308 {
309 if (ma == mb)
310 page->del_range (a, b);
311 else
312 page->del_range (a, major_start (ma + 1) - 1);
313 }
314 }
315 if (de < (int) mb && ma != mb)
316 {
317 page_t *page = page_for (b);
318 if (page)
319 page->del_range (major_start (mb), b);
320 }
321 del_pages (ds, de);
322 }
323
324 bool get (hb_codepoint_t g) const
325 {
326 const page_t *page = page_for (g);
327 if (!page)
328 return false;
329 return page->get (g);
330 }
331
332 /* Has interface. */
333 bool operator [] (hb_codepoint_t k) const { return get (k); }
334 bool has (hb_codepoint_t k) const { return (*this)[k]; }
335 /* Predicate. */
336 bool operator () (hb_codepoint_t k) const { return has (k); }
337
338 /* Sink interface. */
339 hb_bit_set_t& operator << (hb_codepoint_t v)
340 { add (v); return *this; }
341 hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
342 { add_range (range.first, range.second); return *this; }
343
344 bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
345 {
346 hb_codepoint_t c = first - 1;
347 return next (&c) && c <= last;
348 }
349 void set (const hb_bit_set_t &other)
350 {
351 if (unlikely (!successful)) return;
352 unsigned int count = other.pages.length;
353 if (unlikely (!resize (count, false)))
354 return;
355 population = other.population;
356
357 page_map = other.page_map;
358 pages = other.pages;
359 }
360
361 bool is_equal (const hb_bit_set_t &other) const
362 {
363 if (has_population () && other.has_population () &&
364 population != other.population)
365 return false;
366
367 unsigned int na = pages.length;
368 unsigned int nb = other.pages.length;
369
370 unsigned int a = 0, b = 0;
371 for (; a < na && b < nb; )
372 {
373 if (page_at (a).is_empty ()) { a++; continue; }
374 if (other.page_at (b).is_empty ()) { b++; continue; }
375 if (page_map[a].major != other.page_map[b].major ||
376 !page_at (a).is_equal (other.page_at (b)))
377 return false;
378 a++;
379 b++;
380 }
381 for (; a < na; a++)
382 if (!page_at (a).is_empty ()) { return false; }
383 for (; b < nb; b++)
384 if (!other.page_at (b).is_empty ()) { return false; }
385
386 return true;
387 }
388
389 bool is_subset (const hb_bit_set_t &larger_set) const
390 {
391 if (has_population () && larger_set.has_population () &&
392 population > larger_set.population)
393 return false;
394
395 uint32_t spi = 0;
396 for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
397 {
398 uint32_t spm = page_map[spi].major;
399 uint32_t lpm = larger_set.page_map[lpi].major;
400 auto sp = page_at (spi);
401 auto lp = larger_set.page_at (lpi);
402
403 if (spm < lpm && !sp.is_empty ())
404 return false;
405
406 if (lpm < spm)
407 continue;
408
409 if (!sp.is_subset (lp))
410 return false;
411
412 spi++;
413 }
414
415 while (spi < page_map.length)
416 if (!page_at (spi++).is_empty ())
417 return false;
418
419 return true;
420 }
421
422 private:
423 bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
424 {
425 if (unlikely (!workspace.resize (pages.length)))
426 {
427 successful = false;
428 return false;
429 }
430
431 return true;
432 }
433
434 /*
435 * workspace should be a pre-sized vector allocated to hold at exactly pages.length
436 * elements.
437 */
438 void compact (hb_vector_t<unsigned>& workspace,
439 unsigned int length)
440 {
441 assert(workspace.length == pages.length);
442 hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
443
444 hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
445 for (unsigned i = 0; i < length; i++)
446 old_index_to_page_map_index[page_map[i].index] = i;
447
448 compact_pages (old_index_to_page_map_index);
449 }
450 void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
451 {
452 unsigned int write_index = 0;
453 for (unsigned int i = 0; i < pages.length; i++)
454 {
455 if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
456
457 if (write_index < i)
458 pages[write_index] = pages[i];
459
460 page_map[old_index_to_page_map_index[i]].index = write_index;
461 write_index++;
462 }
463 }
464 public:
465
466 void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &),
467 bool passthru_left, bool passthru_right,
468 const hb_bit_set_t &other)
469 {
470 if (unlikely (!successful)) return;
471
472 dirty ();
473
474 unsigned int na = pages.length;
475 unsigned int nb = other.pages.length;
476 unsigned int next_page = na;
477
478 unsigned int count = 0, newCount = 0;
479 unsigned int a = 0, b = 0;
480 unsigned int write_index = 0;
481
482 // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
483 // before attempting to rewrite the page map.
484 hb_vector_t<unsigned> compact_workspace;
485 if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
486
487 for (; a < na && b < nb; )
488 {
489 if (page_map[a].major == other.page_map[b].major)
490 {
491 if (!passthru_left)
492 {
493 // Move page_map entries that we're keeping from the left side set
494 // to the front of the page_map vector. This isn't necessary if
495 // passthru_left is set since no left side pages will be removed
496 // in that case.
497 if (write_index < a)
498 page_map[write_index] = page_map[a];
499 write_index++;
500 }
501
502 count++;
503 a++;
504 b++;
505 }
506 else if (page_map[a].major < other.page_map[b].major)
507 {
508 if (passthru_left)
509 count++;
510 a++;
511 }
512 else
513 {
514 if (passthru_right)
515 count++;
516 b++;
517 }
518 }
519 if (passthru_left)
520 count += na - a;
521 if (passthru_right)
522 count += nb - b;
523
524 if (!passthru_left)
525 {
526 na = write_index;
527 next_page = write_index;
528 compact (compact_workspace, write_index);
529 }
530
531 if (unlikely (!resize (count)))
532 return;
533
534 newCount = count;
535
536 /* Process in-place backward. */
537 a = na;
538 b = nb;
539 for (; a && b; )
540 {
541 if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major)
542 {
543 a--;
544 b--;
545 count--;
546 page_map.arrayZ[count] = page_map.arrayZ[a];
547 page_at (count).v = op (page_at (a).v, other.page_at (b).v);
548 }
549 else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major)
550 {
551 a--;
552 if (passthru_left)
553 {
554 count--;
555 page_map.arrayZ[count] = page_map.arrayZ[a];
556 }
557 }
558 else
559 {
560 b--;
561 if (passthru_right)
562 {
563 count--;
564 page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
565 page_map.arrayZ[count].index = next_page++;
566 page_at (count).v = other.page_at (b).v;
567 }
568 }
569 }
570 if (passthru_left)
571 while (a)
572 {
573 a--;
574 count--;
575 page_map.arrayZ[count] = page_map.arrayZ[a];
576 }
577 if (passthru_right)
578 while (b)
579 {
580 b--;
581 count--;
582 page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
583 page_map.arrayZ[count].index = next_page++;
584 page_at (count).v = other.page_at (b).v;
585 }
586 assert (!count);
587 resize (newCount);
588 }
589 template <typename Op>
590 static hb_bit_page_t::vector_t
591 op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b)
592 { return Op{} (a, b); }
593 template <typename Op>
594 void process (const Op& op, const hb_bit_set_t &other)
595 {
596 process_ (op_<Op>, op (1, 0), op (0, 1), other);
597 }
598
599 void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
600 void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
601 void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); }
602 void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); }
603
604 bool next (hb_codepoint_t *codepoint) const
605 {
606 if (unlikely (*codepoint == INVALID)) {
607 *codepoint = get_min ();
608 return *codepoint != INVALID;
609 }
610
611 const auto* page_map_array = page_map.arrayZ;
612 unsigned int major = get_major (*codepoint);
613 unsigned int i = last_page_lookup;
614
615 if (unlikely (i >= page_map.length || page_map_array[i].major != major))
616 {
617 page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
618 if (i >= page_map.length) {
619 *codepoint = INVALID;
620 return false;
621 }
622 }
623
624 const auto* pages_array = pages.arrayZ;
625 const page_map_t &current = page_map_array[i];
626 if (likely (current.major == major))
627 {
628 if (pages_array[current.index].next (codepoint))
629 {
630 *codepoint += current.major * page_t::PAGE_BITS;
631 last_page_lookup = i;
632 return true;
633 }
634 i++;
635 }
636
637 for (; i < page_map.length; i++)
638 {
639 const page_map_t &current = page_map_array[i];
640 hb_codepoint_t m = pages_array[current.index].get_min ();
641 if (m != INVALID)
642 {
643 *codepoint = current.major * page_t::PAGE_BITS + m;
644 last_page_lookup = i;
645 return true;
646 }
647 }
648 last_page_lookup = 0;
649 *codepoint = INVALID;
650 return false;
651 }
652 bool previous (hb_codepoint_t *codepoint) const
653 {
654 if (unlikely (*codepoint == INVALID)) {
655 *codepoint = get_max ();
656 return *codepoint != INVALID;
657 }
658
659 page_map_t map = {get_major (*codepoint), 0};
660 unsigned int i;
661 page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
662 if (i < page_map.length && page_map.arrayZ[i].major == map.major)
663 {
664 if (pages[page_map.arrayZ[i].index].previous (codepoint))
665 {
666 *codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS;
667 return true;
668 }
669 }
670 i--;
671 for (; (int) i >= 0; i--)
672 {
673 hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max ();
674 if (m != INVALID)
675 {
676 *codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m;
677 return true;
678 }
679 }
680 *codepoint = INVALID;
681 return false;
682 }
683 bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
684 {
685 hb_codepoint_t i;
686
687 i = *last;
688 if (!next (&i))
689 {
690 *last = *first = INVALID;
691 return false;
692 }
693
694 /* TODO Speed up. */
695 *last = *first = i;
696 while (next (&i) && i == *last + 1)
697 (*last)++;
698
699 return true;
700 }
701 bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
702 {
703 hb_codepoint_t i;
704
705 i = *first;
706 if (!previous (&i))
707 {
708 *last = *first = INVALID;
709 return false;
710 }
711
712 /* TODO Speed up. */
713 *last = *first = i;
714 while (previous (&i) && i == *first - 1)
715 (*first)--;
716
717 return true;
718 }
719
720 unsigned int next_many (hb_codepoint_t codepoint,
721 hb_codepoint_t *out,
722 unsigned int size) const
723 {
724 // By default, start at the first bit of the first page of values.
725 unsigned int start_page = 0;
726 unsigned int start_page_value = 0;
727 if (unlikely (codepoint != INVALID))
728 {
729 const auto* page_map_array = page_map.arrayZ;
730 unsigned int major = get_major (codepoint);
731 unsigned int i = last_page_lookup;
732 if (unlikely (i >= page_map.length || page_map_array[i].major != major))
733 {
734 page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
735 if (i >= page_map.length)
736 return 0; // codepoint is greater than our max element.
737 }
738 start_page = i;
739 start_page_value = page_remainder (codepoint + 1);
740 if (unlikely (start_page_value == 0))
741 {
742 // The export-after value was last in the page. Start on next page.
743 start_page++;
744 start_page_value = 0;
745 }
746 }
747
748 unsigned int initial_size = size;
749 for (unsigned int i = start_page; i < page_map.length && size; i++)
750 {
751 uint32_t base = major_start (page_map[i].major);
752 unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
753 out += n;
754 size -= n;
755 start_page_value = 0;
756 }
757 return initial_size - size;
758 }
759
760 unsigned int next_many_inverted (hb_codepoint_t codepoint,
761 hb_codepoint_t *out,
762 unsigned int size) const
763 {
764 unsigned int initial_size = size;
765 // By default, start at the first bit of the first page of values.
766 unsigned int start_page = 0;
767 unsigned int start_page_value = 0;
768 if (unlikely (codepoint != INVALID))
769 {
770 const auto* page_map_array = page_map.arrayZ;
771 unsigned int major = get_major (codepoint);
772 unsigned int i = last_page_lookup;
773 if (unlikely (i >= page_map.length || page_map_array[i].major != major))
774 {
775 page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
776 if (unlikely (i >= page_map.length))
777 {
778 // codepoint is greater than our max element.
779 while (++codepoint != INVALID && size)
780 {
781 *out++ = codepoint;
782 size--;
783 }
784 return initial_size - size;
785 }
786 }
787 start_page = i;
788 start_page_value = page_remainder (codepoint + 1);
789 if (unlikely (start_page_value == 0))
790 {
791 // The export-after value was last in the page. Start on next page.
792 start_page++;
793 start_page_value = 0;
794 }
795 }
796
797 hb_codepoint_t next_value = codepoint + 1;
798 for (unsigned int i=start_page; i<page_map.length && size; i++)
799 {
800 uint32_t base = major_start (page_map[i].major);
801 unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
802 out += n;
803 size -= n;
804 start_page_value = 0;
805 }
806 while (next_value < HB_SET_VALUE_INVALID && size) {
807 *out++ = next_value++;
808 size--;
809 }
810 return initial_size - size;
811 }
812
813 bool has_population () const { return population != UINT_MAX; }
814 unsigned int get_population () const
815 {
816 if (has_population ())
817 return population;
818
819 unsigned int pop = 0;
820 unsigned int count = pages.length;
821 for (unsigned int i = 0; i < count; i++)
822 pop += pages[i].get_population ();
823
824 population = pop;
825 return pop;
826 }
827 hb_codepoint_t get_min () const
828 {
829 unsigned count = pages.length;
830 for (unsigned i = 0; i < count; i++)
831 {
832 const auto& map = page_map[i];
833 const auto& page = pages[map.index];
834
835 if (!page.is_empty ())
836 return map.major * page_t::PAGE_BITS + page.get_min ();
837 }
838 return INVALID;
839 }
840 hb_codepoint_t get_max () const
841 {
842 unsigned count = pages.length;
843 for (signed i = count - 1; i >= 0; i--)
844 {
845 const auto& map = page_map[(unsigned) i];
846 const auto& page = pages[map.index];
847
848 if (!page.is_empty ())
849 return map.major * page_t::PAGE_BITS + page.get_max ();
850 }
851 return INVALID;
852 }
853
854 static constexpr hb_codepoint_t INVALID = page_t::INVALID;
855
856 /*
857 * Iterator implementation.
858 */
859 struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
860 {
861 static constexpr bool is_sorted_iterator = true;
862 iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
863 bool init = true) : s (&s_), v (INVALID), l(0)
864 {
865 if (init)
866 {
867 l = s->get_population () + 1;
868 __next__ ();
869 }
870 }
871
872 typedef hb_codepoint_t __item_t__;
873 hb_codepoint_t __item__ () const { return v; }
874 bool __more__ () const { return v != INVALID; }
875 void __next__ () { s->next (&v); if (l) l--; }
876 void __prev__ () { s->previous (&v); }
877 unsigned __len__ () const { return l; }
878 iter_t end () const { return iter_t (*s, false); }
879 bool operator != (const iter_t& o) const
880 { return s != o.s || v != o.v; }
881
882 protected:
883 const hb_bit_set_t *s;
884 hb_codepoint_t v;
885 unsigned l;
886 };
887 iter_t iter () const { return iter_t (*this); }
888 operator iter_t () const { return iter (); }
889
890 protected:
891
892 page_t *page_for (hb_codepoint_t g, bool insert = false)
893 {
894 unsigned major = get_major (g);
895
896 /* The extra page_map length is necessary; can't just rely on vector here,
897 * since the next check would be tricked because a null page also has
898 * major==0, which we can't distinguish from an actualy major==0 page... */
899 unsigned i = last_page_lookup;
900 if (likely (i < page_map.length))
901 {
902 auto &cached_page = page_map.arrayZ[i];
903 if (cached_page.major == major)
904 return &pages.arrayZ[cached_page.index];
905 }
906
907 page_map_t map = {major, pages.length};
908 if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
909 {
910 if (!insert)
911 return nullptr;
912
913 if (unlikely (!resize (pages.length + 1)))
914 return nullptr;
915
916 pages.arrayZ[map.index].init0 ();
917 memmove (page_map.arrayZ + i + 1,
918 page_map.arrayZ + i,
919 (page_map.length - 1 - i) * page_map.item_size);
920 page_map[i] = map;
921 }
922
923 last_page_lookup = i;
924 return &pages.arrayZ[page_map.arrayZ[i].index];
925 }
926 const page_t *page_for (hb_codepoint_t g) const
927 {
928 unsigned major = get_major (g);
929
930 /* The extra page_map length is necessary; can't just rely on vector here,
931 * since the next check would be tricked because a null page also has
932 * major==0, which we can't distinguish from an actualy major==0 page... */
933 unsigned i = last_page_lookup;
934 if (likely (i < page_map.length))
935 {
936 auto &cached_page = page_map.arrayZ[i];
937 if (cached_page.major == major)
938 return &pages.arrayZ[cached_page.index];
939 }
940
941 page_map_t key = {major};
942 if (!page_map.bfind (key, &i))
943 return nullptr;
944
945 last_page_lookup = i;
946 return &pages.arrayZ[page_map[i].index];
947 }
948 page_t &page_at (unsigned int i)
949 {
950 assert (i < page_map.length);
951 return pages.arrayZ[page_map.arrayZ[i].index];
952 }
953 const page_t &page_at (unsigned int i) const
954 {
955 assert (i < page_map.length);
956 return pages.arrayZ[page_map.arrayZ[i].index];
957 }
958 unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; }
959 unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; }
960 hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; }
961 };
962
963
964 #endif /* HB_BIT_SET_HH */