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