2 * Copyright © 2012,2017 Google, Inc.
3 * Copyright © 2021 Behdad Esfahbod
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Google Author(s): Behdad Esfahbod
28 #ifndef HB_BIT_SET_INVERTIBLE_HH
29 #define HB_BIT_SET_INVERTIBLE_HH
32 #include "hb-bit-set.hh"
35 struct hb_bit_set_invertible_t
38 bool inverted = false;
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) : 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) { hb_swap (*this, other); return *this; }
45 friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b)
47 if (likely (!a.s.successful || !b.s.successful))
49 hb_swap (a.inverted, b.inverted);
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 (); }
59 void alloc (unsigned sz) { s.alloc (sz); }
68 if (likely (s.successful))
73 if (likely (s.successful))
77 bool is_inverted () const
82 bool is_empty () const
84 hb_codepoint_t v = INVALID;
88 uint32_t hash () const { return s.hash () ^ (uint32_t) inverted; }
90 hb_codepoint_t get_min () const
92 hb_codepoint_t v = INVALID;
96 hb_codepoint_t get_max () const
98 hb_codepoint_t v = INVALID;
102 unsigned int get_population () const
103 { return inverted ? INVALID - s.get_population () : s.get_population (); }
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); }
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 ()); }
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 ()); }
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); }
128 bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
131 bool operator [] (hb_codepoint_t k) const { return get (k); }
132 bool has (hb_codepoint_t k) const { return (*this)[k]; }
134 bool operator () (hb_codepoint_t k) const { return has (k); }
136 /* Sink interface. */
137 hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
138 { add (v); return *this; }
139 hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
140 { add_range (range.first, range.second); return *this; }
142 bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
144 hb_codepoint_t c = first - 1;
145 return next (&c) && c <= last;
148 void set (const hb_bit_set_invertible_t &other)
151 if (likely (s.successful))
152 inverted = other.inverted;
155 bool is_equal (const hb_bit_set_invertible_t &other) const
157 if (likely (inverted == other.inverted))
158 return s.is_equal (other.s);
161 /* TODO Add iter_ranges() and use here. */
163 auto it2 = other.iter ();
164 return hb_all (+ hb_zip (it1, it2)
165 | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; }));
169 bool is_subset (const hb_bit_set_invertible_t &larger_set) const
171 if (unlikely (inverted != larger_set.inverted))
172 return hb_all (hb_iter (s) | hb_map (larger_set.s));
174 return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s);
178 template <typename Op>
179 void process (const Op& op, const hb_bit_set_invertible_t &other)
180 { s.process (op, other.s); }
182 void union_ (const hb_bit_set_invertible_t &other)
184 if (likely (inverted == other.inverted))
186 if (unlikely (inverted))
187 process (hb_bitwise_and, other);
189 process (hb_bitwise_or, other); /* Main branch. */
193 if (unlikely (inverted))
194 process (hb_bitwise_gt, other);
196 process (hb_bitwise_lt, other);
198 if (likely (s.successful))
199 inverted = inverted || other.inverted;
201 void intersect (const hb_bit_set_invertible_t &other)
203 if (likely (inverted == other.inverted))
205 if (unlikely (inverted))
206 process (hb_bitwise_or, other);
208 process (hb_bitwise_and, other); /* Main branch. */
212 if (unlikely (inverted))
213 process (hb_bitwise_lt, other);
215 process (hb_bitwise_gt, other);
217 if (likely (s.successful))
218 inverted = inverted && other.inverted;
220 void subtract (const hb_bit_set_invertible_t &other)
222 if (likely (inverted == other.inverted))
224 if (unlikely (inverted))
225 process (hb_bitwise_lt, other);
227 process (hb_bitwise_gt, other); /* Main branch. */
231 if (unlikely (inverted))
232 process (hb_bitwise_or, other);
234 process (hb_bitwise_and, other);
236 if (likely (s.successful))
237 inverted = inverted && !other.inverted;
239 void symmetric_difference (const hb_bit_set_invertible_t &other)
241 process (hb_bitwise_xor, other);
242 if (likely (s.successful))
243 inverted = inverted ^ other.inverted;
246 bool next (hb_codepoint_t *codepoint) const
248 if (likely (!inverted))
249 return s.next (codepoint);
251 auto old = *codepoint;
252 if (unlikely (old + 1 == INVALID))
254 *codepoint = INVALID;
262 *codepoint = old + 1;
267 s.next_range (&old, &v);
270 return *codepoint != INVALID;
272 bool previous (hb_codepoint_t *codepoint) const
274 if (likely (!inverted))
275 return s.previous (codepoint);
277 auto old = *codepoint;
278 if (unlikely (old - 1 == INVALID))
280 *codepoint = INVALID;
287 if (old - 1 > v || v == INVALID)
289 *codepoint = old - 1;
294 s.previous_range (&v, &old);
297 return *codepoint != INVALID;
299 bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
301 if (likely (!inverted))
302 return s.next_range (first, last);
306 *last = *first = INVALID;
315 bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
317 if (likely (!inverted))
318 return s.previous_range (first, last);
320 if (!previous (first))
322 *last = *first = INVALID;
332 unsigned int next_many (hb_codepoint_t codepoint,
334 unsigned int size) const
336 return inverted ? s.next_many_inverted (codepoint, out, size)
337 : s.next_many (codepoint, out, size);
340 static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
343 * Iterator implementation.
345 struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
347 static constexpr bool is_sorted_iterator = true;
348 static constexpr bool has_fast_len = true;
349 iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
350 bool init = true) : s (&s_), v (INVALID), l(0)
354 l = s->get_population () + 1;
359 typedef hb_codepoint_t __item_t__;
360 hb_codepoint_t __item__ () const { return v; }
361 bool __more__ () const { return v != INVALID; }
362 void __next__ () { s->next (&v); if (l) l--; }
363 void __prev__ () { s->previous (&v); }
364 unsigned __len__ () const { return l; }
365 iter_t end () const { return iter_t (*s, false); }
366 bool operator != (const iter_t& o) const
367 { return v != o.v || s != o.s; }
370 const hb_bit_set_invertible_t *s;
374 iter_t iter () const { return iter_t (*this); }
375 operator iter_t () const { return iter (); }
379 #endif /* HB_BIT_SET_INVERTIBLE_HH */