2 * Copyright © 2012 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Google Author(s): Behdad Esfahbod
27 #ifndef HB_SET_PRIVATE_HH
28 #define HB_SET_PRIVATE_HH
30 #include "hb-private.hh"
31 #include "hb-object-private.hh"
35 * The set digests here implement various "filters" that support
36 * "approximate member query". Conceptually these are like Bloom
37 * Filter and Quotient Filter, however, much smaller, faster, and
38 * designed to fit the requirements of our uses for glyph coverage
39 * queries. As a result, our filters have much higher.
42 template <typename mask_t
, unsigned int shift
>
43 struct hb_set_digest_lowest_bits_t
47 static const unsigned int mask_bytes
= sizeof (mask_t
);
48 static const unsigned int mask_bits
= sizeof (mask_t
) * 8;
49 static const unsigned int num_bits
= 0
50 + (mask_bytes
>= 1 ? 3 : 0)
51 + (mask_bytes
>= 2 ? 1 : 0)
52 + (mask_bytes
>= 4 ? 1 : 0)
53 + (mask_bytes
>= 8 ? 1 : 0)
54 + (mask_bytes
>= 16? 1 : 0)
57 ASSERT_STATIC (shift
< sizeof (hb_codepoint_t
) * 8);
58 ASSERT_STATIC (shift
+ num_bits
<= sizeof (hb_codepoint_t
) * 8);
60 inline void init (void) {
64 inline void add (hb_codepoint_t g
) {
68 inline void add_range (hb_codepoint_t a
, hb_codepoint_t b
) {
69 if ((b
>> shift
) - (a
>> shift
) >= mask_bits
- 1)
72 mask_t ma
= mask_for (a
);
73 mask_t mb
= mask_for (b
);
74 mask
|= mb
+ (mb
- ma
) - (mb
< ma
);
78 inline bool may_have (hb_codepoint_t g
) const {
79 return !!(mask
& mask_for (g
));
84 static inline mask_t
mask_for (hb_codepoint_t g
) {
85 return ((mask_t
) 1) << ((g
>> shift
) & (mask_bits
- 1));
90 template <typename head_t
, typename tail_t
>
91 struct hb_set_digest_combiner_t
95 inline void init (void) {
100 inline void add (hb_codepoint_t g
) {
105 inline void add_range (hb_codepoint_t a
, hb_codepoint_t b
) {
106 head
.add_range (a
, b
);
107 tail
.add_range (a
, b
);
110 inline bool may_have (hb_codepoint_t g
) const {
111 return head
.may_have (g
) && tail
.may_have (g
);
123 * This is a combination of digests that performs "best".
124 * There is not much science to this: it's a result of intuition
127 typedef hb_set_digest_combiner_t
129 hb_set_digest_lowest_bits_t
<unsigned long, 4>,
130 hb_set_digest_combiner_t
132 hb_set_digest_lowest_bits_t
<unsigned long, 0>,
133 hb_set_digest_lowest_bits_t
<unsigned long, 9>
144 /* TODO Make this faster and memmory efficient. */
148 friend struct hb_frozen_set_t
;
150 hb_object_header_t header
;
154 inline void init (void) {
155 hb_object_init (this);
158 inline void fini (void) {
160 inline void clear (void) {
161 if (unlikely (hb_object_is_inert (this)))
164 memset (elts
, 0, sizeof elts
);
166 inline bool is_empty (void) const {
167 for (unsigned int i
= 0; i
< ARRAY_LENGTH (elts
); i
++)
172 inline void add (hb_codepoint_t g
)
174 if (unlikely (in_error
)) return;
175 if (unlikely (g
== INVALID
)) return;
176 if (unlikely (g
> MAX_G
)) return;
179 inline void add_range (hb_codepoint_t a
, hb_codepoint_t b
)
181 if (unlikely (in_error
)) return;
183 for (unsigned int i
= a
; i
< b
+ 1; i
++)
186 inline void del (hb_codepoint_t g
)
188 if (unlikely (in_error
)) return;
189 if (unlikely (g
> MAX_G
)) return;
190 elt (g
) &= ~mask (g
);
192 inline void del_range (hb_codepoint_t a
, hb_codepoint_t b
)
194 if (unlikely (in_error
)) return;
196 for (unsigned int i
= a
; i
< b
+ 1; i
++)
199 inline bool has (hb_codepoint_t g
) const
201 if (unlikely (g
> MAX_G
)) return false;
202 return !!(elt (g
) & mask (g
));
204 inline bool intersects (hb_codepoint_t first
,
205 hb_codepoint_t last
) const
207 if (unlikely (first
> MAX_G
)) return false;
208 if (unlikely (last
> MAX_G
)) last
= MAX_G
;
209 unsigned int end
= last
+ 1;
210 for (hb_codepoint_t i
= first
; i
< end
; i
++)
215 inline bool is_equal (const hb_set_t
*other
) const
217 for (unsigned int i
= 0; i
< ELTS
; i
++)
218 if (elts
[i
] != other
->elts
[i
])
222 inline void set (const hb_set_t
*other
)
224 if (unlikely (in_error
)) return;
225 for (unsigned int i
= 0; i
< ELTS
; i
++)
226 elts
[i
] = other
->elts
[i
];
228 inline void union_ (const hb_set_t
*other
)
230 if (unlikely (in_error
)) return;
231 for (unsigned int i
= 0; i
< ELTS
; i
++)
232 elts
[i
] |= other
->elts
[i
];
234 inline void intersect (const hb_set_t
*other
)
236 if (unlikely (in_error
)) return;
237 for (unsigned int i
= 0; i
< ELTS
; i
++)
238 elts
[i
] &= other
->elts
[i
];
240 inline void subtract (const hb_set_t
*other
)
242 if (unlikely (in_error
)) return;
243 for (unsigned int i
= 0; i
< ELTS
; i
++)
244 elts
[i
] &= ~other
->elts
[i
];
246 inline void symmetric_difference (const hb_set_t
*other
)
248 if (unlikely (in_error
)) return;
249 for (unsigned int i
= 0; i
< ELTS
; i
++)
250 elts
[i
] ^= other
->elts
[i
];
252 inline void invert (void)
254 if (unlikely (in_error
)) return;
255 for (unsigned int i
= 0; i
< ELTS
; i
++)
258 inline bool next (hb_codepoint_t
*codepoint
) const
260 if (unlikely (*codepoint
== INVALID
)) {
261 hb_codepoint_t i
= get_min ();
266 *codepoint
= INVALID
;
270 for (hb_codepoint_t i
= *codepoint
+ 1; i
< MAX_G
+ 1; i
++)
275 *codepoint
= INVALID
;
278 inline bool next_range (hb_codepoint_t
*first
, hb_codepoint_t
*last
) const
285 *last
= *first
= INVALID
;
290 while (next (&i
) && i
== *last
+ 1)
296 inline unsigned int get_population (void) const
298 unsigned int count
= 0;
299 for (unsigned int i
= 0; i
< ELTS
; i
++)
300 count
+= _hb_popcount32 (elts
[i
]);
303 inline hb_codepoint_t
get_min (void) const
305 for (unsigned int i
= 0; i
< ELTS
; i
++)
307 for (unsigned int j
= 0; j
< BITS
; j
++)
308 if (elts
[i
] & (1 << j
))
312 inline hb_codepoint_t
get_max (void) const
314 for (unsigned int i
= ELTS
; i
; i
--)
316 for (unsigned int j
= BITS
; j
; j
--)
317 if (elts
[i
- 1] & (1 << (j
- 1)))
318 return (i
- 1) * BITS
+ (j
- 1);
322 typedef uint32_t elt_t
;
323 static const unsigned int MAX_G
= 65536 - 1; /* XXX Fix this... */
324 static const unsigned int SHIFT
= 5;
325 static const unsigned int BITS
= (1 << SHIFT
);
326 static const unsigned int MASK
= BITS
- 1;
327 static const unsigned int ELTS
= (MAX_G
+ 1 + (BITS
- 1)) / BITS
;
328 static const hb_codepoint_t INVALID
= HB_SET_VALUE_INVALID
;
330 elt_t
&elt (hb_codepoint_t g
) { return elts
[g
>> SHIFT
]; }
331 elt_t
const &elt (hb_codepoint_t g
) const { return elts
[g
>> SHIFT
]; }
332 elt_t
mask (hb_codepoint_t g
) const { return elt_t (1) << (g
& MASK
); }
334 elt_t elts
[ELTS
]; /* XXX 8kb */
336 ASSERT_STATIC (sizeof (elt_t
) * 8 == BITS
);
337 ASSERT_STATIC (sizeof (elt_t
) * 8 * ELTS
> MAX_G
);
340 struct hb_frozen_set_t
342 static const unsigned int SHIFT
= hb_set_t::SHIFT
;
343 static const unsigned int BITS
= hb_set_t::BITS
;
344 static const unsigned int MASK
= hb_set_t::MASK
;
345 typedef hb_set_t::elt_t elt_t
;
347 inline void init (const hb_set_t
&set
)
352 unsigned int max
= set
.get_max ();
353 if (max
== set
.INVALID
)
355 unsigned int min
= set
.get_min ();
356 const elt_t
&min_elt
= set
.elt (min
);
357 const elt_t
&max_elt
= set
.elt (max
);
360 count
= max
- start
+ 1;
361 unsigned int num_elts
= (count
+ BITS
- 1) / BITS
;
362 unsigned int elts_size
= num_elts
* sizeof (elt_t
);
363 elts
= (elt_t
*) malloc (elts_size
);
364 if (unlikely (!elts
))
369 memcpy (elts
, &min_elt
, elts_size
);
372 inline void fini (void)
378 inline bool has (hb_codepoint_t g
) const
380 /* hb_codepoint_t is unsigned. */
382 if (unlikely (g
> count
)) return false;
383 return !!(elt (g
) & mask (g
));
386 elt_t
const &elt (hb_codepoint_t g
) const { return elts
[g
>> SHIFT
]; }
387 elt_t
mask (hb_codepoint_t g
) const { return elt_t (1) << (g
& MASK
); }
390 hb_codepoint_t start
, count
;
395 #endif /* HB_SET_PRIVATE_HH */