tor-browser

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

hb-bit-set-invertible.hh (10657B)


      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_INVERTIBLE_HH
     29 #define HB_BIT_SET_INVERTIBLE_HH
     30 
     31 #include "hb.hh"
     32 #include "hb-bit-set.hh"
     33 
     34 
     35 struct hb_bit_set_invertible_t
     36 {
     37  hb_bit_set_t s;
     38  bool inverted = false;
     39 
     40  hb_bit_set_invertible_t () = default;
     41  hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default;
     42  hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other)  noexcept : hb_bit_set_invertible_t () { hb_swap (*this, other); }
     43  hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default;
     44  hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other)  noexcept { hb_swap (*this, other); return *this; }
     45  friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) noexcept
     46  {
     47    if (likely (!a.s.successful || !b.s.successful))
     48      return;
     49    hb_swap (a.inverted, b.inverted);
     50    hb_swap (a.s, b.s);
     51  }
     52 
     53  void init () { s.init (); inverted = false; }
     54  void fini () { s.fini (); }
     55  void err () { s.err (); }
     56  bool in_error () const { return s.in_error (); }
     57  explicit operator bool () const { return !is_empty (); }
     58 
     59  void alloc (unsigned sz) { s.alloc (sz); }
     60  void reset ()
     61  {
     62    s.reset ();
     63    inverted = false;
     64  }
     65  void clear ()
     66  {
     67    s.clear ();
     68    if (likely (s.successful))
     69      inverted = false;
     70  }
     71  void invert ()
     72  {
     73    if (likely (s.successful))
     74      inverted = !inverted;
     75  }
     76 
     77  bool is_inverted () const
     78  {
     79    return inverted;
     80  }
     81 
     82  bool is_empty () const
     83  {
     84    hb_codepoint_t v = INVALID;
     85    next (&v);
     86    return v == INVALID;
     87  }
     88  uint32_t hash () const { return s.hash () ^ (uint32_t) inverted; }
     89 
     90  hb_codepoint_t get_min () const
     91  {
     92    hb_codepoint_t v = INVALID;
     93    next (&v);
     94    return v;
     95  }
     96  hb_codepoint_t get_max () const
     97  {
     98    hb_codepoint_t v = INVALID;
     99    previous (&v);
    100    return v;
    101  }
    102  unsigned int get_population () const
    103  { return inverted ? INVALID - s.get_population () : s.get_population (); }
    104 
    105 
    106  void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); }
    107  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
    108  { return unlikely (inverted) ? ((void) s.del_range (a, b), true) : s.add_range (a, b); }
    109 
    110  template <typename T>
    111  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
    112  { inverted ? s.del_array (array, count, stride) : s.add_array (array, count, stride); }
    113  template <typename T>
    114  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
    115 
    116  /* Might return false if array looks unsorted.
    117   * Used for faster rejection of corrupt data. */
    118  template <typename T>
    119  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
    120  { return inverted ? s.del_sorted_array (array, count, stride) : s.add_sorted_array (array, count, stride); }
    121  template <typename T>
    122  bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
    123 
    124  void del (hb_codepoint_t g) { unlikely (inverted) ? s.add (g) : s.del (g); }
    125  void del_range (hb_codepoint_t a, hb_codepoint_t b)
    126  { unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
    127 
    128  bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
    129  bool may_have (hb_codepoint_t g) const { return get (g); }
    130 
    131  /* Has interface. */
    132  bool operator [] (hb_codepoint_t k) const { return get (k); }
    133  bool has (hb_codepoint_t k) const { return (*this)[k]; }
    134  /* Predicate. */
    135  bool operator () (hb_codepoint_t k) const { return has (k); }
    136 
    137  /* Sink interface. */
    138  hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
    139  { add (v); return *this; }
    140  hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
    141  { add_range (range.first, range.second); return *this; }
    142 
    143  bool may_intersect (const hb_bit_set_invertible_t &other) const
    144  { return inverted || other.inverted || s.intersects (other.s); }
    145 
    146  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
    147  {
    148    hb_codepoint_t c = first - 1;
    149    return next (&c) && c <= last;
    150  }
    151 
    152  void set (const hb_bit_set_invertible_t &other)
    153  {
    154    s.set (other.s);
    155    if (likely (s.successful))
    156      inverted = other.inverted;
    157  }
    158 
    159  bool is_equal (const hb_bit_set_invertible_t &other) const
    160  {
    161    if (likely (inverted == other.inverted))
    162      return s.is_equal (other.s);
    163    else
    164    {
    165      /* TODO Add iter_ranges() and use here. */
    166      auto it1 = iter ();
    167      auto it2 = other.iter ();
    168      return hb_all (+ hb_zip (it1, it2)
    169 	     | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; }));
    170    }
    171  }
    172 
    173  bool is_subset (const hb_bit_set_invertible_t &larger_set) const
    174  {
    175    if (unlikely (inverted != larger_set.inverted))
    176      return hb_all (hb_iter (s) | hb_map (larger_set.s));
    177    else
    178      return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s);
    179  }
    180 
    181  protected:
    182  template <typename Op>
    183  void process (const Op& op, const hb_bit_set_invertible_t &other)
    184  { s.process (op, other.s); }
    185  public:
    186  void union_ (const hb_bit_set_invertible_t &other)
    187  {
    188    if (likely (inverted == other.inverted))
    189    {
    190      if (unlikely (inverted))
    191 process (hb_bitwise_and, other);
    192      else
    193 process (hb_bitwise_or, other); /* Main branch. */
    194    }
    195    else
    196    {
    197      if (unlikely (inverted))
    198 process (hb_bitwise_gt, other);
    199      else
    200 process (hb_bitwise_lt, other);
    201    }
    202    if (likely (s.successful))
    203      inverted = inverted || other.inverted;
    204  }
    205  void intersect (const hb_bit_set_invertible_t &other)
    206  {
    207    if (likely (inverted == other.inverted))
    208    {
    209      if (unlikely (inverted))
    210 process (hb_bitwise_or, other);
    211      else
    212 process (hb_bitwise_and, other); /* Main branch. */
    213    }
    214    else
    215    {
    216      if (unlikely (inverted))
    217 process (hb_bitwise_lt, other);
    218      else
    219 process (hb_bitwise_gt, other);
    220    }
    221    if (likely (s.successful))
    222      inverted = inverted && other.inverted;
    223  }
    224  void subtract (const hb_bit_set_invertible_t &other)
    225  {
    226    if (likely (inverted == other.inverted))
    227    {
    228      if (unlikely (inverted))
    229 process (hb_bitwise_lt, other);
    230      else
    231 process (hb_bitwise_gt, other); /* Main branch. */
    232    }
    233    else
    234    {
    235      if (unlikely (inverted))
    236 process (hb_bitwise_or, other);
    237      else
    238 process (hb_bitwise_and, other);
    239    }
    240    if (likely (s.successful))
    241      inverted = inverted && !other.inverted;
    242  }
    243  void symmetric_difference (const hb_bit_set_invertible_t &other)
    244  {
    245    process (hb_bitwise_xor, other);
    246    if (likely (s.successful))
    247      inverted = inverted ^ other.inverted;
    248  }
    249 
    250  bool next (hb_codepoint_t *codepoint) const
    251  {
    252    if (likely (!inverted))
    253      return s.next (codepoint);
    254 
    255    auto old = *codepoint;
    256    if (unlikely (old + 1 == INVALID))
    257    {
    258      *codepoint = INVALID;
    259      return false;
    260    }
    261 
    262    auto v = old;
    263    s.next (&v);
    264    if (old + 1 < v)
    265    {
    266      *codepoint = old + 1;
    267      return true;
    268    }
    269 
    270    v = old;
    271    s.next_range (&old, &v);
    272 
    273    *codepoint = v + 1;
    274    return *codepoint != INVALID;
    275  }
    276  bool previous (hb_codepoint_t *codepoint) const
    277  {
    278    if (likely (!inverted))
    279      return s.previous (codepoint);
    280 
    281    auto old = *codepoint;
    282    if (unlikely (old - 1 == INVALID))
    283    {
    284      *codepoint = INVALID;
    285      return false;
    286    }
    287 
    288    auto v = old;
    289    s.previous (&v);
    290 
    291    if (old - 1 > v || v == INVALID)
    292    {
    293      *codepoint = old - 1;
    294      return true;
    295    }
    296 
    297    v = old;
    298    s.previous_range (&v, &old);
    299 
    300    *codepoint = v - 1;
    301    return *codepoint != INVALID;
    302  }
    303  bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
    304  {
    305    if (likely (!inverted))
    306      return s.next_range (first, last);
    307 
    308    if (!next (last))
    309    {
    310      *last = *first = INVALID;
    311      return false;
    312    }
    313 
    314    *first = *last;
    315    s.next (last);
    316    --*last;
    317    return true;
    318  }
    319  bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
    320  {
    321    if (likely (!inverted))
    322      return s.previous_range (first, last);
    323 
    324    if (!previous (first))
    325    {
    326      *last = *first = INVALID;
    327      return false;
    328    }
    329 
    330    *last = *first;
    331    s.previous (first);
    332    ++*first;
    333    return true;
    334  }
    335 
    336  unsigned int next_many (hb_codepoint_t  codepoint,
    337 		  hb_codepoint_t *out,
    338 		  unsigned int    size) const
    339  {
    340    return inverted ? s.next_many_inverted (codepoint, out, size)
    341 	    : s.next_many (codepoint, out, size);
    342  }
    343 
    344  static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
    345 
    346  /*
    347   * Iterator implementation.
    348   */
    349  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
    350  {
    351    static constexpr bool is_sorted_iterator = true;
    352    static constexpr bool has_fast_len = true;
    353    iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
    354     bool init = true) : s (&s_), v (INVALID), l(0)
    355    {
    356      if (init)
    357      {
    358 l = s->get_population () + 1;
    359 __next__ ();
    360      }
    361    }
    362 
    363    typedef hb_codepoint_t __item_t__;
    364    hb_codepoint_t __item__ () const { return v; }
    365    bool __more__ () const { return v != INVALID; }
    366    void __next__ () { s->next (&v); if (likely (l)) l--; }
    367    void __prev__ () { s->previous (&v); l++; }
    368    unsigned __len__ () const { return l; }
    369    iter_t end () const { return iter_t (*s, false); }
    370    bool operator != (const iter_t& o) const
    371    { return v != o.v; }
    372 
    373    protected:
    374    const hb_bit_set_invertible_t *s;
    375    hb_codepoint_t v;
    376    unsigned l;
    377  };
    378  iter_t iter () const { return iter_t (*this); }
    379  operator iter_t () const { return iter (); }
    380 };
    381 
    382 
    383 #endif /* HB_BIT_SET_INVERTIBLE_HH */