• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012  Google, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Google Author(s): Behdad Esfahbod
25  */
26 
27 #ifndef HB_SET_PRIVATE_HH
28 #define HB_SET_PRIVATE_HH
29 
30 #include "hb-private.hh"
31 #include "hb-set.h"
32 #include "hb-object-private.hh"
33 
34 
35 struct hb_set_digest_common_bits_t
36 {
37   ASSERT_POD ();
38 
39   typedef unsigned int mask_t;
40 
inithb_set_digest_common_bits_t41   inline void init (void) {
42     mask = ~0;
43     value = (mask_t) -1;
44   }
45 
addhb_set_digest_common_bits_t46   inline void add (hb_codepoint_t g) {
47     if (unlikely (value == (mask_t) -1)) {
48       value = g;
49       return;
50     }
51 
52     mask ^= (g & mask) ^ value;
53     value &= mask;
54   }
55 
add_rangehb_set_digest_common_bits_t56   inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
57     /* The negation here stands for ~(x-1). */
58     mask &= -(1 << _hb_bit_storage (a ^ b));
59     value &= mask;
60   }
61 
may_havehb_set_digest_common_bits_t62   inline bool may_have (hb_codepoint_t g) const {
63     return (g & mask) == value;
64   }
65 
66   private:
67   mask_t mask;
68   mask_t value;
69 };
70 
71 struct hb_set_digest_lowest_bits_t
72 {
73   ASSERT_POD ();
74 
75   typedef unsigned long mask_t;
76 
inithb_set_digest_lowest_bits_t77   inline void init (void) {
78     mask = 0;
79   }
80 
addhb_set_digest_lowest_bits_t81   inline void add (hb_codepoint_t g) {
82     mask |= mask_for (g);
83   }
84 
add_rangehb_set_digest_lowest_bits_t85   inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
86     if (b - a >= sizeof (mask_t) * 8 - 1)
87       mask = (mask_t) -1;
88     else {
89       mask_t ma = mask_for (a);
90       mask_t mb = mask_for (b);
91       mask |= mb + (mb - ma) - (mb < ma);
92     }
93   }
94 
may_havehb_set_digest_lowest_bits_t95   inline bool may_have (hb_codepoint_t g) const {
96     return !!(mask & mask_for (g));
97   }
98 
99   private:
100 
mask_forhb_set_digest_lowest_bits_t101   static inline mask_t mask_for (hb_codepoint_t g) { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); }
102   mask_t mask;
103 };
104 
105 struct hb_set_digest_t
106 {
107   ASSERT_POD ();
108 
inithb_set_digest_t109   inline void init (void) {
110     digest1.init ();
111     digest2.init ();
112   }
113 
addhb_set_digest_t114   inline void add (hb_codepoint_t g) {
115     digest1.add (g);
116     digest2.add (g);
117   }
118 
add_rangehb_set_digest_t119   inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
120     digest1.add_range (a, b);
121     digest2.add_range (a, b);
122   }
123 
may_havehb_set_digest_t124   inline bool may_have (hb_codepoint_t g) const {
125     return digest1.may_have (g) && digest2.may_have (g);
126   }
127 
128   private:
129   hb_set_digest_common_bits_t digest1;
130   hb_set_digest_lowest_bits_t digest2;
131 };
132 
133 
134 /* TODO Make this faster and memmory efficient. */
135 
136 struct hb_set_t
137 {
138   hb_object_header_t header;
139   ASSERT_POD ();
140   bool in_error;
141 
inithb_set_t142   inline void init (void) {
143     header.init ();
144     clear ();
145   }
finihb_set_t146   inline void fini (void) {
147   }
clearhb_set_t148   inline void clear (void) {
149     if (unlikely (hb_object_is_inert (this)))
150       return;
151     in_error = false;
152     memset (elts, 0, sizeof elts);
153   }
is_emptyhb_set_t154   inline bool is_empty (void) const {
155     for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
156       if (elts[i])
157         return false;
158     return true;
159   }
addhb_set_t160   inline void add (hb_codepoint_t g)
161   {
162     if (unlikely (in_error)) return;
163     if (unlikely (g == SENTINEL)) return;
164     if (unlikely (g > MAX_G)) return;
165     elt (g) |= mask (g);
166   }
add_rangehb_set_t167   inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
168   {
169     if (unlikely (in_error)) return;
170     /* TODO Speedup */
171     for (unsigned int i = a; i < b + 1; i++)
172       add (i);
173   }
delhb_set_t174   inline void del (hb_codepoint_t g)
175   {
176     if (unlikely (in_error)) return;
177     if (unlikely (g > MAX_G)) return;
178     elt (g) &= ~mask (g);
179   }
del_rangehb_set_t180   inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
181   {
182     if (unlikely (in_error)) return;
183     /* TODO Speedup */
184     for (unsigned int i = a; i < b + 1; i++)
185       del (i);
186   }
hashb_set_t187   inline bool has (hb_codepoint_t g) const
188   {
189     if (unlikely (g > MAX_G)) return false;
190     return !!(elt (g) & mask (g));
191   }
intersectshb_set_t192   inline bool intersects (hb_codepoint_t first,
193 			  hb_codepoint_t last) const
194   {
195     if (unlikely (first > MAX_G)) return false;
196     if (unlikely (last  > MAX_G)) last = MAX_G;
197     unsigned int end = last + 1;
198     for (hb_codepoint_t i = first; i < end; i++)
199       if (has (i))
200         return true;
201     return false;
202   }
is_equalhb_set_t203   inline bool is_equal (const hb_set_t *other) const
204   {
205     for (unsigned int i = 0; i < ELTS; i++)
206       if (elts[i] != other->elts[i])
207         return false;
208     return true;
209   }
sethb_set_t210   inline void set (const hb_set_t *other)
211   {
212     if (unlikely (in_error)) return;
213     for (unsigned int i = 0; i < ELTS; i++)
214       elts[i] = other->elts[i];
215   }
union_hb_set_t216   inline void union_ (const hb_set_t *other)
217   {
218     if (unlikely (in_error)) return;
219     for (unsigned int i = 0; i < ELTS; i++)
220       elts[i] |= other->elts[i];
221   }
intersecthb_set_t222   inline void intersect (const hb_set_t *other)
223   {
224     if (unlikely (in_error)) return;
225     for (unsigned int i = 0; i < ELTS; i++)
226       elts[i] &= other->elts[i];
227   }
subtracthb_set_t228   inline void subtract (const hb_set_t *other)
229   {
230     if (unlikely (in_error)) return;
231     for (unsigned int i = 0; i < ELTS; i++)
232       elts[i] &= ~other->elts[i];
233   }
symmetric_differencehb_set_t234   inline void symmetric_difference (const hb_set_t *other)
235   {
236     if (unlikely (in_error)) return;
237     for (unsigned int i = 0; i < ELTS; i++)
238       elts[i] ^= other->elts[i];
239   }
inverthb_set_t240   inline void invert (void)
241   {
242     if (unlikely (in_error)) return;
243     for (unsigned int i = 0; i < ELTS; i++)
244       elts[i] = ~elts[i];
245   }
nexthb_set_t246   inline bool next (hb_codepoint_t *codepoint) const
247   {
248     if (unlikely (*codepoint == SENTINEL)) {
249       hb_codepoint_t i = get_min ();
250       if (i != SENTINEL) {
251         *codepoint = i;
252 	return true;
253       } else
254         return false;
255     }
256     for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
257       if (has (i)) {
258         *codepoint = i;
259 	return true;
260       }
261     return false;
262   }
next_rangehb_set_t263   inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
264   {
265     hb_codepoint_t i;
266 
267     i = *last;
268     if (!next (&i))
269       return false;
270 
271     *last = *first = i;
272     while (next (&i) && i == *last + 1)
273       (*last)++;
274 
275     return true;
276   }
277 
get_populationhb_set_t278   inline unsigned int get_population (void) const
279   {
280     unsigned int count = 0;
281     for (unsigned int i = 0; i < ELTS; i++)
282       count += _hb_popcount32 (elts[i]);
283     return count;
284   }
get_minhb_set_t285   inline hb_codepoint_t get_min (void) const
286   {
287     for (unsigned int i = 0; i < ELTS; i++)
288       if (elts[i])
289 	for (unsigned int j = 0; i < BITS; j++)
290 	  if (elts[i] & (1 << j))
291 	    return i * BITS + j;
292     return SENTINEL;
293   }
get_maxhb_set_t294   inline hb_codepoint_t get_max (void) const
295   {
296     for (unsigned int i = ELTS; i; i--)
297       if (elts[i - 1])
298 	for (unsigned int j = BITS; j; j--)
299 	  if (elts[i - 1] & (1 << (j - 1)))
300 	    return (i - 1) * BITS + (j - 1);
301     return SENTINEL;
302   }
303 
304   typedef uint32_t elt_t;
305   static const unsigned int MAX_G = 65536 - 1; /* XXX Fix this... */
306   static const unsigned int SHIFT = 5;
307   static const unsigned int BITS = (1 << SHIFT);
308   static const unsigned int MASK = BITS - 1;
309   static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
310   static  const hb_codepoint_t SENTINEL = (hb_codepoint_t) -1;
311 
elthb_set_t312   elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
elthb_set_t313   elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
maskhb_set_t314   elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
315 
316   elt_t elts[ELTS]; /* XXX 8kb */
317 
318   ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
319   ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
320 };
321 
322 
323 
324 #endif /* HB_SET_PRIVATE_HH */
325