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 */