hb-bit-vector.hh (5355B)
1 /* 2 * This is part of HarfBuzz, a text shaping library. 3 * 4 * Permission is hereby granted, without written agreement and without 5 * license or royalty fees, to use, copy, modify, and distribute this 6 * software and its documentation for any purpose, provided that the 7 * above copyright notice and the following two paragraphs appear in 8 * all copies of this software. 9 * 10 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 11 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 12 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 13 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 14 * DAMAGE. 15 * 16 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 17 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 18 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 19 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 20 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 21 * 22 * Author(s): Behdad Esfahbod 23 */ 24 25 #ifndef HB_BIT_VECTOR_HH 26 #define HB_BIT_VECTOR_HH 27 28 #include "hb.hh" 29 30 #include "hb-atomic.hh" 31 32 struct hb_min_max_t 33 { 34 void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); } 35 void add_range (hb_codepoint_t a, hb_codepoint_t b) 36 { 37 min_v = hb_min (min_v, a); 38 max_v = hb_max (max_v, b); 39 } 40 41 template <typename set_t> 42 void union_ (const set_t &set) 43 { 44 hb_codepoint_t set_min = set.get_min (); 45 if (unlikely (set_min == HB_CODEPOINT_INVALID)) 46 return; 47 hb_codepoint_t set_max = set.get_max (); 48 min_v = hb_min (min_v, set_min); 49 max_v = hb_max (max_v, set_max); 50 } 51 52 hb_codepoint_t get_min () const { return min_v; } 53 hb_codepoint_t get_max () const { return max_v; } 54 55 private: 56 hb_codepoint_t min_v = HB_CODEPOINT_INVALID; 57 hb_codepoint_t max_v = 0; 58 }; 59 60 template <bool atomic = false> 61 struct hb_bit_vector_t 62 { 63 using int_t = uint64_t; 64 using elt_t = typename std::conditional<atomic, hb_atomic_t<int_t>, int_t>::type; 65 66 hb_bit_vector_t () = delete; 67 hb_bit_vector_t (const hb_bit_vector_t &other) = delete; 68 hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete; 69 70 // Move 71 hb_bit_vector_t (hb_bit_vector_t &&other) 72 : min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts) 73 { 74 other.min_v = other.max_v = other.count = 0; 75 other.elts = nullptr; 76 } 77 hb_bit_vector_t &operator= (hb_bit_vector_t &&other) 78 { 79 hb_swap (min_v, other.min_v); 80 hb_swap (max_v, other.max_v); 81 hb_swap (count, other.count); 82 hb_swap (elts, other.elts); 83 return *this; 84 } 85 86 hb_bit_vector_t (unsigned min_v, unsigned max_v) 87 : min_v (min_v), max_v (max_v) 88 { 89 if (unlikely (min_v >= max_v)) 90 { 91 min_v = max_v = count = 0; 92 return; 93 } 94 95 unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8); 96 elts = (elt_t *) hb_calloc (num, sizeof (int_t)); 97 if (unlikely (!elts)) 98 { 99 min_v = max_v = count = 0; 100 return; 101 } 102 103 count = max_v - min_v + 1; 104 } 105 ~hb_bit_vector_t () 106 { 107 hb_free (elts); 108 } 109 110 void add (hb_codepoint_t g) { elt (g) |= mask (g); } 111 void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } 112 void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); } 113 bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } 114 bool has (hb_codepoint_t g) const { return get (g); } 115 bool may_have (hb_codepoint_t g) const { return get (g); } 116 117 bool operator [] (hb_codepoint_t g) const { return get (g); } 118 bool operator () (hb_codepoint_t g) const { return get (g); } 119 120 void add_range (hb_codepoint_t a, hb_codepoint_t b) 121 { 122 if (unlikely (!count || a > b || a < min_v || b > max_v)) 123 return; 124 125 elt_t *la = &elt (a); 126 elt_t *lb = &elt (b); 127 if (la == lb) 128 *la |= (mask (b) << 1) - mask(a); 129 else 130 { 131 *la |= ~(mask (a) - 1llu); 132 la++; 133 134 hb_memset (la, 0xff, (char *) lb - (char *) la); 135 136 *lb |= ((mask (b) << 1) - 1llu); 137 } 138 } 139 void del_range (hb_codepoint_t a, hb_codepoint_t b) 140 { 141 if (unlikely (!count || a > b || a < min_v || b > max_v)) 142 return; 143 144 elt_t *la = &elt (a); 145 elt_t *lb = &elt (b); 146 if (la == lb) 147 *la &= ~((mask (b) << 1llu) - mask(a)); 148 else 149 { 150 *la &= mask (a) - 1; 151 la++; 152 153 hb_memset (la, 0, (char *) lb - (char *) la); 154 155 *lb &= ~((mask (b) << 1) - 1llu); 156 } 157 } 158 void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v) 159 { if (v) add_range (a, b); else del_range (a, b); } 160 161 template <typename set_t> 162 void union_ (const set_t &set) 163 { 164 for (hb_codepoint_t g : set) 165 add (g); 166 } 167 168 static const unsigned int ELT_BITS = sizeof (elt_t) * 8; 169 static constexpr unsigned ELT_MASK = ELT_BITS - 1; 170 171 static constexpr elt_t zero = 0; 172 173 elt_t &elt (hb_codepoint_t g) 174 { 175 g -= min_v; 176 if (unlikely (g >= count)) 177 return Crap(elt_t); 178 return elts[g / ELT_BITS]; 179 } 180 const elt_t& elt (hb_codepoint_t g) const 181 { 182 g -= min_v; 183 if (unlikely (g >= count)) 184 return Null(elt_t); 185 return elts[g / ELT_BITS]; 186 } 187 188 static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); } 189 190 hb_codepoint_t min_v = 0, max_v = 0, count = 0; 191 elt_t *elts = nullptr; 192 }; 193 194 195 #endif /* HB_BIT_VECTOR_HH */