tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 &current = 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 &current = 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 */