|
1 /* |
|
2 * Copyright © 2007,2008,2009 Red Hat, Inc. |
|
3 * Copyright © 2011,2012 Google, Inc. |
|
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 * Red Hat Author(s): Behdad Esfahbod |
|
26 * Google Author(s): Behdad Esfahbod |
|
27 */ |
|
28 |
|
29 #ifndef HB_PRIVATE_HH |
|
30 #define HB_PRIVATE_HH |
|
31 |
|
32 #ifdef HAVE_CONFIG_H |
|
33 #include "config.h" |
|
34 #endif |
|
35 |
|
36 #include "hb.h" |
|
37 #define HB_H_IN |
|
38 #ifdef HAVE_OT |
|
39 #include "hb-ot.h" |
|
40 #define HB_OT_H_IN |
|
41 #endif |
|
42 |
|
43 #include <stdlib.h> |
|
44 #include <stddef.h> |
|
45 #include <string.h> |
|
46 #include <assert.h> |
|
47 |
|
48 /* We only use these two for debug output. However, the debug code is |
|
49 * always seen by the compiler (and optimized out in non-debug builds. |
|
50 * If including these becomes a problem, we can start thinking about |
|
51 * someway around that. */ |
|
52 #include <stdio.h> |
|
53 #include <errno.h> |
|
54 #include <stdarg.h> |
|
55 |
|
56 |
|
57 |
|
58 /* Essentials */ |
|
59 |
|
60 #ifndef NULL |
|
61 # define NULL ((void *) 0) |
|
62 #endif |
|
63 |
|
64 |
|
65 /* Void! */ |
|
66 struct _hb_void_t {}; |
|
67 typedef const _hb_void_t &hb_void_t; |
|
68 #define HB_VOID (* (const _hb_void_t *) NULL) |
|
69 |
|
70 |
|
71 /* Basics */ |
|
72 |
|
73 |
|
74 #undef MIN |
|
75 template <typename Type> |
|
76 static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; } |
|
77 |
|
78 #undef MAX |
|
79 template <typename Type> |
|
80 static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; } |
|
81 |
|
82 static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b) |
|
83 { return (a + (b - 1)) / b; } |
|
84 |
|
85 |
|
86 #undef ARRAY_LENGTH |
|
87 template <typename Type, unsigned int n> |
|
88 static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; } |
|
89 /* A const version, but does not detect erratically being called on pointers. */ |
|
90 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0]))) |
|
91 |
|
92 #define HB_STMT_START do |
|
93 #define HB_STMT_END while (0) |
|
94 |
|
95 #define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1] |
|
96 #define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond)) |
|
97 #define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond)) |
|
98 |
|
99 #define ASSERT_STATIC_EXPR(_cond)((void) sizeof (char[(_cond) ? 1 : -1])) |
|
100 #define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1])) |
|
101 |
|
102 #define _PASTE1(a,b) a##b |
|
103 #define PASTE(a,b) _PASTE1(a,b) |
|
104 |
|
105 /* Lets assert int types. Saves trouble down the road. */ |
|
106 |
|
107 ASSERT_STATIC (sizeof (int8_t) == 1); |
|
108 ASSERT_STATIC (sizeof (uint8_t) == 1); |
|
109 ASSERT_STATIC (sizeof (int16_t) == 2); |
|
110 ASSERT_STATIC (sizeof (uint16_t) == 2); |
|
111 ASSERT_STATIC (sizeof (int32_t) == 4); |
|
112 ASSERT_STATIC (sizeof (uint32_t) == 4); |
|
113 ASSERT_STATIC (sizeof (int64_t) == 8); |
|
114 ASSERT_STATIC (sizeof (uint64_t) == 8); |
|
115 |
|
116 ASSERT_STATIC (sizeof (hb_codepoint_t) == 4); |
|
117 ASSERT_STATIC (sizeof (hb_position_t) == 4); |
|
118 ASSERT_STATIC (sizeof (hb_mask_t) == 4); |
|
119 ASSERT_STATIC (sizeof (hb_var_int_t) == 4); |
|
120 |
|
121 |
|
122 /* We like our types POD */ |
|
123 |
|
124 #define _ASSERT_TYPE_POD1(_line, _type) union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; } |
|
125 #define _ASSERT_TYPE_POD0(_line, _type) _ASSERT_TYPE_POD1 (_line, _type) |
|
126 #define ASSERT_TYPE_POD(_type) _ASSERT_TYPE_POD0 (__LINE__, _type) |
|
127 |
|
128 #ifdef __GNUC__ |
|
129 # define _ASSERT_INSTANCE_POD1(_line, _instance) \ |
|
130 HB_STMT_START { \ |
|
131 typedef __typeof__(_instance) _type_##_line; \ |
|
132 _ASSERT_TYPE_POD1 (_line, _type_##_line); \ |
|
133 } HB_STMT_END |
|
134 #else |
|
135 # define _ASSERT_INSTANCE_POD1(_line, _instance) typedef int _assertion_on_line_##_line##_not_tested |
|
136 #endif |
|
137 # define _ASSERT_INSTANCE_POD0(_line, _instance) _ASSERT_INSTANCE_POD1 (_line, _instance) |
|
138 # define ASSERT_INSTANCE_POD(_instance) _ASSERT_INSTANCE_POD0 (__LINE__, _instance) |
|
139 |
|
140 /* Check _assertion in a method environment */ |
|
141 #define _ASSERT_POD1(_line) \ |
|
142 inline void _static_assertion_on_line_##_line (void) const \ |
|
143 { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ } |
|
144 # define _ASSERT_POD0(_line) _ASSERT_POD1 (_line) |
|
145 # define ASSERT_POD() _ASSERT_POD0 (__LINE__) |
|
146 |
|
147 |
|
148 |
|
149 /* Misc */ |
|
150 |
|
151 |
|
152 #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) |
|
153 #define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0) |
|
154 #define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1)) |
|
155 #define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0)) |
|
156 #else |
|
157 #define likely(expr) (expr) |
|
158 #define unlikely(expr) (expr) |
|
159 #endif |
|
160 |
|
161 #ifndef __GNUC__ |
|
162 #undef __attribute__ |
|
163 #define __attribute__(x) |
|
164 #endif |
|
165 |
|
166 #if __GNUC__ >= 3 |
|
167 #define HB_PURE_FUNC __attribute__((pure)) |
|
168 #define HB_CONST_FUNC __attribute__((const)) |
|
169 #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) |
|
170 #else |
|
171 #define HB_PURE_FUNC |
|
172 #define HB_CONST_FUNC |
|
173 #define HB_PRINTF_FUNC(format_idx, arg_idx) |
|
174 #endif |
|
175 #if __GNUC__ >= 4 |
|
176 #define HB_UNUSED __attribute__((unused)) |
|
177 #else |
|
178 #define HB_UNUSED |
|
179 #endif |
|
180 |
|
181 #ifndef HB_INTERNAL |
|
182 # ifndef __MINGW32__ |
|
183 # define HB_INTERNAL __attribute__((__visibility__("hidden"))) |
|
184 # else |
|
185 # define HB_INTERNAL |
|
186 # endif |
|
187 #endif |
|
188 |
|
189 |
|
190 #if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER) |
|
191 #define snprintf _snprintf |
|
192 #endif |
|
193 |
|
194 #ifdef _MSC_VER |
|
195 #undef inline |
|
196 #define inline __inline |
|
197 #endif |
|
198 |
|
199 #ifdef __STRICT_ANSI__ |
|
200 #undef inline |
|
201 #define inline __inline__ |
|
202 #endif |
|
203 |
|
204 |
|
205 #if __GNUC__ >= 3 |
|
206 #define HB_FUNC __PRETTY_FUNCTION__ |
|
207 #elif defined(_MSC_VER) |
|
208 #define HB_FUNC __FUNCSIG__ |
|
209 #else |
|
210 #define HB_FUNC __func__ |
|
211 #endif |
|
212 |
|
213 |
|
214 /* Return the number of 1 bits in mask. */ |
|
215 static inline HB_CONST_FUNC unsigned int |
|
216 _hb_popcount32 (uint32_t mask) |
|
217 { |
|
218 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) |
|
219 return __builtin_popcount (mask); |
|
220 #else |
|
221 /* "HACKMEM 169" */ |
|
222 register uint32_t y; |
|
223 y = (mask >> 1) &033333333333; |
|
224 y = mask - y - ((y >>1) & 033333333333); |
|
225 return (((y + (y >> 3)) & 030707070707) % 077); |
|
226 #endif |
|
227 } |
|
228 |
|
229 /* Returns the number of bits needed to store number */ |
|
230 static inline HB_CONST_FUNC unsigned int |
|
231 _hb_bit_storage (unsigned int number) |
|
232 { |
|
233 #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) |
|
234 return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0; |
|
235 #else |
|
236 register unsigned int n_bits = 0; |
|
237 while (number) { |
|
238 n_bits++; |
|
239 number >>= 1; |
|
240 } |
|
241 return n_bits; |
|
242 #endif |
|
243 } |
|
244 |
|
245 /* Returns the number of zero bits in the least significant side of number */ |
|
246 static inline HB_CONST_FUNC unsigned int |
|
247 _hb_ctz (unsigned int number) |
|
248 { |
|
249 #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) |
|
250 return likely (number) ? __builtin_ctz (number) : 0; |
|
251 #else |
|
252 register unsigned int n_bits = 0; |
|
253 if (unlikely (!number)) return 0; |
|
254 while (!(number & 1)) { |
|
255 n_bits++; |
|
256 number >>= 1; |
|
257 } |
|
258 return n_bits; |
|
259 #endif |
|
260 } |
|
261 |
|
262 static inline bool |
|
263 _hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size) |
|
264 { |
|
265 return (size > 0) && (count >= ((unsigned int) -1) / size); |
|
266 } |
|
267 |
|
268 |
|
269 /* Type of bsearch() / qsort() compare function */ |
|
270 typedef int (*hb_compare_func_t) (const void *, const void *); |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 /* arrays and maps */ |
|
276 |
|
277 |
|
278 #define HB_PREALLOCED_ARRAY_INIT {0} |
|
279 template <typename Type, unsigned int StaticSize> |
|
280 struct hb_prealloced_array_t |
|
281 { |
|
282 unsigned int len; |
|
283 unsigned int allocated; |
|
284 Type *array; |
|
285 Type static_array[StaticSize]; |
|
286 |
|
287 void init (void) { memset (this, 0, sizeof (*this)); } |
|
288 |
|
289 inline Type& operator [] (unsigned int i) { return array[i]; } |
|
290 inline const Type& operator [] (unsigned int i) const { return array[i]; } |
|
291 |
|
292 inline Type *push (void) |
|
293 { |
|
294 if (!array) { |
|
295 array = static_array; |
|
296 allocated = ARRAY_LENGTH (static_array); |
|
297 } |
|
298 if (likely (len < allocated)) |
|
299 return &array[len++]; |
|
300 |
|
301 /* Need to reallocate */ |
|
302 unsigned int new_allocated = allocated + (allocated >> 1) + 8; |
|
303 Type *new_array = NULL; |
|
304 |
|
305 if (array == static_array) { |
|
306 new_array = (Type *) calloc (new_allocated, sizeof (Type)); |
|
307 if (new_array) |
|
308 memcpy (new_array, array, len * sizeof (Type)); |
|
309 } else { |
|
310 bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type)); |
|
311 if (likely (!overflows)) { |
|
312 new_array = (Type *) realloc (array, new_allocated * sizeof (Type)); |
|
313 } |
|
314 } |
|
315 |
|
316 if (unlikely (!new_array)) |
|
317 return NULL; |
|
318 |
|
319 array = new_array; |
|
320 allocated = new_allocated; |
|
321 return &array[len++]; |
|
322 } |
|
323 |
|
324 inline void pop (void) |
|
325 { |
|
326 len--; |
|
327 } |
|
328 |
|
329 inline void remove (unsigned int i) |
|
330 { |
|
331 if (unlikely (i >= len)) |
|
332 return; |
|
333 memmove (static_cast<void *> (&array[i]), |
|
334 static_cast<void *> (&array[i + 1]), |
|
335 (len - i - 1) * sizeof (Type)); |
|
336 len--; |
|
337 } |
|
338 |
|
339 inline void shrink (unsigned int l) |
|
340 { |
|
341 if (l < len) |
|
342 len = l; |
|
343 } |
|
344 |
|
345 template <typename T> |
|
346 inline Type *find (T v) { |
|
347 for (unsigned int i = 0; i < len; i++) |
|
348 if (array[i] == v) |
|
349 return &array[i]; |
|
350 return NULL; |
|
351 } |
|
352 template <typename T> |
|
353 inline const Type *find (T v) const { |
|
354 for (unsigned int i = 0; i < len; i++) |
|
355 if (array[i] == v) |
|
356 return &array[i]; |
|
357 return NULL; |
|
358 } |
|
359 |
|
360 inline void sort (void) |
|
361 { |
|
362 qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp); |
|
363 } |
|
364 |
|
365 inline void sort (unsigned int start, unsigned int end) |
|
366 { |
|
367 qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp); |
|
368 } |
|
369 |
|
370 template <typename T> |
|
371 inline Type *bsearch (T *key) |
|
372 { |
|
373 return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp); |
|
374 } |
|
375 template <typename T> |
|
376 inline const Type *bsearch (T *key) const |
|
377 { |
|
378 return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp); |
|
379 } |
|
380 |
|
381 inline void finish (void) |
|
382 { |
|
383 if (array != static_array) |
|
384 free (array); |
|
385 array = NULL; |
|
386 allocated = len = 0; |
|
387 } |
|
388 }; |
|
389 |
|
390 #define HB_AUTO_ARRAY_PREALLOCED 16 |
|
391 template <typename Type> |
|
392 struct hb_auto_array_t : hb_prealloced_array_t <Type, HB_AUTO_ARRAY_PREALLOCED> |
|
393 { |
|
394 hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::init (); } |
|
395 ~hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::finish (); } |
|
396 }; |
|
397 |
|
398 |
|
399 #define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT} |
|
400 template <typename item_t, typename lock_t> |
|
401 struct hb_lockable_set_t |
|
402 { |
|
403 hb_prealloced_array_t <item_t, 2> items; |
|
404 |
|
405 inline void init (void) { items.init (); } |
|
406 |
|
407 template <typename T> |
|
408 inline item_t *replace_or_insert (T v, lock_t &l, bool replace) |
|
409 { |
|
410 l.lock (); |
|
411 item_t *item = items.find (v); |
|
412 if (item) { |
|
413 if (replace) { |
|
414 item_t old = *item; |
|
415 *item = v; |
|
416 l.unlock (); |
|
417 old.finish (); |
|
418 } |
|
419 else { |
|
420 item = NULL; |
|
421 l.unlock (); |
|
422 } |
|
423 } else { |
|
424 item = items.push (); |
|
425 if (likely (item)) |
|
426 *item = v; |
|
427 l.unlock (); |
|
428 } |
|
429 return item; |
|
430 } |
|
431 |
|
432 template <typename T> |
|
433 inline void remove (T v, lock_t &l) |
|
434 { |
|
435 l.lock (); |
|
436 item_t *item = items.find (v); |
|
437 if (item) { |
|
438 item_t old = *item; |
|
439 *item = items[items.len - 1]; |
|
440 items.pop (); |
|
441 l.unlock (); |
|
442 old.finish (); |
|
443 } else { |
|
444 l.unlock (); |
|
445 } |
|
446 } |
|
447 |
|
448 template <typename T> |
|
449 inline bool find (T v, item_t *i, lock_t &l) |
|
450 { |
|
451 l.lock (); |
|
452 item_t *item = items.find (v); |
|
453 if (item) |
|
454 *i = *item; |
|
455 l.unlock (); |
|
456 return !!item; |
|
457 } |
|
458 |
|
459 template <typename T> |
|
460 inline item_t *find_or_insert (T v, lock_t &l) |
|
461 { |
|
462 l.lock (); |
|
463 item_t *item = items.find (v); |
|
464 if (!item) { |
|
465 item = items.push (); |
|
466 if (likely (item)) |
|
467 *item = v; |
|
468 } |
|
469 l.unlock (); |
|
470 return item; |
|
471 } |
|
472 |
|
473 inline void finish (lock_t &l) |
|
474 { |
|
475 if (!items.len) { |
|
476 /* No need for locking. */ |
|
477 items.finish (); |
|
478 return; |
|
479 } |
|
480 l.lock (); |
|
481 while (items.len) { |
|
482 item_t old = items[items.len - 1]; |
|
483 items.pop (); |
|
484 l.unlock (); |
|
485 old.finish (); |
|
486 l.lock (); |
|
487 } |
|
488 items.finish (); |
|
489 l.unlock (); |
|
490 } |
|
491 |
|
492 }; |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 /* Big-endian handling */ |
|
498 |
|
499 static inline uint16_t hb_be_uint16 (const uint16_t v) |
|
500 { |
|
501 const uint8_t *V = (const uint8_t *) &v; |
|
502 return (V[0] << 8) | V[1]; |
|
503 } |
|
504 |
|
505 static inline uint16_t hb_uint16_swap (const uint16_t v) |
|
506 { |
|
507 return (v >> 8) | (v << 8); |
|
508 } |
|
509 |
|
510 static inline uint32_t hb_uint32_swap (const uint32_t v) |
|
511 { |
|
512 return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); |
|
513 } |
|
514 |
|
515 /* Note, of the following macros, uint16_get is the one called many many times. |
|
516 * If there is any optimizations to be done, it's in that macro. However, I |
|
517 * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which |
|
518 * results in a single ror instruction, does NOT speed this up. In fact, it |
|
519 * resulted in a minor slowdown. At any rate, note that v may not be correctly |
|
520 * aligned, so I think the current implementation is optimal. |
|
521 */ |
|
522 |
|
523 #define hb_be_uint16_put(v,V) HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END |
|
524 #define hb_be_uint16_get(v) (uint16_t) ((v[0] << 8) + v[1]) |
|
525 #define hb_be_uint16_eq(a,b) (a[0] == b[0] && a[1] == b[1]) |
|
526 |
|
527 #define hb_be_uint32_put(v,V) HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END |
|
528 #define hb_be_uint32_get(v) (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3]) |
|
529 #define hb_be_uint32_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]) |
|
530 |
|
531 #define hb_be_uint24_put(v,V) HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] = (V); } HB_STMT_END |
|
532 #define hb_be_uint24_get(v) (uint32_t) ((v[0] << 16) + (v[1] << 8) + v[2]) |
|
533 #define hb_be_uint24_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]) |
|
534 |
|
535 |
|
536 /* ASCII tag/character handling */ |
|
537 |
|
538 static inline bool ISALPHA (unsigned char c) |
|
539 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } |
|
540 static inline bool ISALNUM (unsigned char c) |
|
541 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } |
|
542 static inline bool ISSPACE (unsigned char c) |
|
543 { return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } |
|
544 static inline unsigned char TOUPPER (unsigned char c) |
|
545 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } |
|
546 static inline unsigned char TOLOWER (unsigned char c) |
|
547 { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } |
|
548 |
|
549 #define HB_TAG_CHAR4(s) (HB_TAG(((const char *) s)[0], \ |
|
550 ((const char *) s)[1], \ |
|
551 ((const char *) s)[2], \ |
|
552 ((const char *) s)[3])) |
|
553 |
|
554 |
|
555 /* C++ helpers */ |
|
556 |
|
557 /* Makes class uncopyable. Use in private: section. */ |
|
558 #define NO_COPY(T) \ |
|
559 T (const T &o); \ |
|
560 T &operator = (const T &o) |
|
561 |
|
562 |
|
563 /* Debug */ |
|
564 |
|
565 |
|
566 #ifndef HB_DEBUG |
|
567 #define HB_DEBUG 0 |
|
568 #endif |
|
569 |
|
570 static inline bool |
|
571 _hb_debug (unsigned int level, |
|
572 unsigned int max_level) |
|
573 { |
|
574 return level < max_level; |
|
575 } |
|
576 |
|
577 #define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT)) |
|
578 #define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0)) |
|
579 |
|
580 template <int max_level> static inline void |
|
581 _hb_debug_msg_va (const char *what, |
|
582 const void *obj, |
|
583 const char *func, |
|
584 bool indented, |
|
585 unsigned int level, |
|
586 int level_dir, |
|
587 const char *message, |
|
588 va_list ap) |
|
589 { |
|
590 if (!_hb_debug (level, max_level)) |
|
591 return; |
|
592 |
|
593 fprintf (stderr, "%-10s", what ? what : ""); |
|
594 |
|
595 if (obj) |
|
596 fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj); |
|
597 else |
|
598 fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), ""); |
|
599 |
|
600 if (indented) { |
|
601 /* One may want to add ASCII version of these. See: |
|
602 * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */ |
|
603 #define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ |
|
604 #define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ |
|
605 #define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */ |
|
606 #define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */ |
|
607 #define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */ |
|
608 static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR; |
|
609 fprintf (stderr, "%2u %s" VRBAR "%s", |
|
610 level, |
|
611 bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level), |
|
612 level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR); |
|
613 } else |
|
614 fprintf (stderr, " " VRBAR LBAR); |
|
615 |
|
616 if (func) |
|
617 { |
|
618 unsigned int func_len = strlen (func); |
|
619 #ifndef HB_DEBUG_VERBOSE |
|
620 /* Skip "typename" */ |
|
621 if (0 == strncmp (func, "typename ", 9)) |
|
622 func += 9; |
|
623 /* Skip return type */ |
|
624 const char *space = strchr (func, ' '); |
|
625 if (space) |
|
626 func = space + 1; |
|
627 /* Skip parameter list */ |
|
628 const char *paren = strchr (func, '('); |
|
629 if (paren) |
|
630 func_len = paren - func; |
|
631 #endif |
|
632 fprintf (stderr, "%.*s: ", func_len, func); |
|
633 } |
|
634 |
|
635 if (message) |
|
636 vfprintf (stderr, message, ap); |
|
637 |
|
638 fprintf (stderr, "\n"); |
|
639 } |
|
640 template <> inline void |
|
641 _hb_debug_msg_va<0> (const char *what HB_UNUSED, |
|
642 const void *obj HB_UNUSED, |
|
643 const char *func HB_UNUSED, |
|
644 bool indented HB_UNUSED, |
|
645 unsigned int level HB_UNUSED, |
|
646 int level_dir HB_UNUSED, |
|
647 const char *message HB_UNUSED, |
|
648 va_list ap HB_UNUSED) {} |
|
649 |
|
650 template <int max_level> static inline void |
|
651 _hb_debug_msg (const char *what, |
|
652 const void *obj, |
|
653 const char *func, |
|
654 bool indented, |
|
655 unsigned int level, |
|
656 int level_dir, |
|
657 const char *message, |
|
658 ...) HB_PRINTF_FUNC(7, 8); |
|
659 template <int max_level> static inline void |
|
660 _hb_debug_msg (const char *what, |
|
661 const void *obj, |
|
662 const char *func, |
|
663 bool indented, |
|
664 unsigned int level, |
|
665 int level_dir, |
|
666 const char *message, |
|
667 ...) |
|
668 { |
|
669 va_list ap; |
|
670 va_start (ap, message); |
|
671 _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap); |
|
672 va_end (ap); |
|
673 } |
|
674 template <> inline void |
|
675 _hb_debug_msg<0> (const char *what HB_UNUSED, |
|
676 const void *obj HB_UNUSED, |
|
677 const char *func HB_UNUSED, |
|
678 bool indented HB_UNUSED, |
|
679 unsigned int level HB_UNUSED, |
|
680 int level_dir HB_UNUSED, |
|
681 const char *message HB_UNUSED, |
|
682 ...) HB_PRINTF_FUNC(7, 8); |
|
683 template <> inline void |
|
684 _hb_debug_msg<0> (const char *what HB_UNUSED, |
|
685 const void *obj HB_UNUSED, |
|
686 const char *func HB_UNUSED, |
|
687 bool indented HB_UNUSED, |
|
688 unsigned int level HB_UNUSED, |
|
689 int level_dir HB_UNUSED, |
|
690 const char *message HB_UNUSED, |
|
691 ...) {} |
|
692 |
|
693 #define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__) |
|
694 #define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, false, 0, 0, __VA_ARGS__) |
|
695 #define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__) |
|
696 |
|
697 |
|
698 /* |
|
699 * Printer |
|
700 */ |
|
701 |
|
702 template <typename T> |
|
703 struct hb_printer_t {}; |
|
704 |
|
705 template <> |
|
706 struct hb_printer_t<bool> { |
|
707 const char *print (bool v) { return v ? "true" : "false"; } |
|
708 }; |
|
709 |
|
710 template <> |
|
711 struct hb_printer_t<hb_void_t> { |
|
712 const char *print (hb_void_t) { return ""; } |
|
713 }; |
|
714 |
|
715 |
|
716 /* |
|
717 * Trace |
|
718 */ |
|
719 |
|
720 template <typename T> |
|
721 static inline void _hb_warn_no_return (bool returned) |
|
722 { |
|
723 if (unlikely (!returned)) { |
|
724 fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN. This is a bug, please report.\n"); |
|
725 } |
|
726 } |
|
727 template <> |
|
728 inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED) |
|
729 {} |
|
730 |
|
731 template <int max_level, typename ret_t> |
|
732 struct hb_auto_trace_t { |
|
733 explicit inline hb_auto_trace_t (unsigned int *plevel_, |
|
734 const char *what_, |
|
735 const void *obj_, |
|
736 const char *func, |
|
737 const char *message, |
|
738 ...) : plevel (plevel_), what (what_), obj (obj_), returned (false) |
|
739 { |
|
740 if (plevel) ++*plevel; |
|
741 |
|
742 va_list ap; |
|
743 va_start (ap, message); |
|
744 _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap); |
|
745 va_end (ap); |
|
746 } |
|
747 inline ~hb_auto_trace_t (void) |
|
748 { |
|
749 _hb_warn_no_return<ret_t> (returned); |
|
750 if (!returned) { |
|
751 _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " "); |
|
752 } |
|
753 if (plevel) --*plevel; |
|
754 } |
|
755 |
|
756 inline ret_t ret (ret_t v, unsigned int line = 0) |
|
757 { |
|
758 if (unlikely (returned)) { |
|
759 fprintf (stderr, "OUCH, double calls to TRACE_RETURN. This is a bug, please report.\n"); |
|
760 return v; |
|
761 } |
|
762 |
|
763 _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, |
|
764 "return %s (line %d)", |
|
765 hb_printer_t<ret_t>().print (v), line); |
|
766 if (plevel) --*plevel; |
|
767 plevel = NULL; |
|
768 returned = true; |
|
769 return v; |
|
770 } |
|
771 |
|
772 private: |
|
773 unsigned int *plevel; |
|
774 const char *what; |
|
775 const void *obj; |
|
776 bool returned; |
|
777 }; |
|
778 template <typename ret_t> /* Optimize when tracing is disabled */ |
|
779 struct hb_auto_trace_t<0, ret_t> { |
|
780 explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED, |
|
781 const char *what HB_UNUSED, |
|
782 const void *obj HB_UNUSED, |
|
783 const char *func HB_UNUSED, |
|
784 const char *message HB_UNUSED, |
|
785 ...) {} |
|
786 |
|
787 inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; } |
|
788 }; |
|
789 |
|
790 #define TRACE_RETURN(RET) trace.ret (RET, __LINE__) |
|
791 |
|
792 /* Misc */ |
|
793 |
|
794 |
|
795 /* Pre-mature optimization: |
|
796 * Checks for lo <= u <= hi but with an optimization if lo and hi |
|
797 * are only different in a contiguous set of lower-most bits. |
|
798 */ |
|
799 template <typename T> static inline bool |
|
800 hb_in_range (T u, T lo, T hi) |
|
801 { |
|
802 if ( ((lo^hi) & lo) == 0 && |
|
803 ((lo^hi) & hi) == (lo^hi) && |
|
804 ((lo^hi) & ((lo^hi) + 1)) == 0 ) |
|
805 return (u & ~(lo^hi)) == lo; |
|
806 else |
|
807 return lo <= u && u <= hi; |
|
808 } |
|
809 |
|
810 template <typename T> static inline bool |
|
811 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) |
|
812 { |
|
813 return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); |
|
814 } |
|
815 |
|
816 template <typename T> static inline bool |
|
817 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) |
|
818 { |
|
819 return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); |
|
820 } |
|
821 |
|
822 |
|
823 /* Useful for set-operations on small enums. |
|
824 * For example, for testing "x ∈ {x1, x2, x3}" use: |
|
825 * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3))) |
|
826 */ |
|
827 #define FLAG(x) (1<<(x)) |
|
828 #define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x)) |
|
829 |
|
830 |
|
831 template <typename T, typename T2> inline void |
|
832 hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2) |
|
833 { |
|
834 if (unlikely (!len)) |
|
835 return; |
|
836 |
|
837 unsigned int k = len - 1; |
|
838 do { |
|
839 unsigned int new_k = 0; |
|
840 |
|
841 for (unsigned int j = 0; j < k; j++) |
|
842 if (compar (&array[j], &array[j+1]) > 0) |
|
843 { |
|
844 { |
|
845 T t; |
|
846 t = array[j]; |
|
847 array[j] = array[j + 1]; |
|
848 array[j + 1] = t; |
|
849 } |
|
850 if (array2) |
|
851 { |
|
852 T2 t; |
|
853 t = array2[j]; |
|
854 array2[j] = array2[j + 1]; |
|
855 array2[j + 1] = t; |
|
856 } |
|
857 |
|
858 new_k = j; |
|
859 } |
|
860 k = new_k; |
|
861 } while (k); |
|
862 } |
|
863 |
|
864 template <typename T> inline void |
|
865 hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) |
|
866 { |
|
867 hb_bubble_sort (array, len, compar, (int *) NULL); |
|
868 } |
|
869 |
|
870 static inline hb_bool_t |
|
871 hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) |
|
872 { |
|
873 /* Pain because we don't know whether s is nul-terminated. */ |
|
874 char buf[64]; |
|
875 len = MIN (ARRAY_LENGTH (buf) - 1, len); |
|
876 strncpy (buf, s, len); |
|
877 buf[len] = '\0'; |
|
878 |
|
879 char *end; |
|
880 errno = 0; |
|
881 unsigned long v = strtoul (buf, &end, base); |
|
882 if (errno) return false; |
|
883 if (*end) return false; |
|
884 *out = v; |
|
885 return true; |
|
886 } |
|
887 |
|
888 |
|
889 /* Global runtime options. */ |
|
890 |
|
891 struct hb_options_t |
|
892 { |
|
893 int initialized : 1; |
|
894 int uniscribe_bug_compatible : 1; |
|
895 }; |
|
896 |
|
897 union hb_options_union_t { |
|
898 int i; |
|
899 hb_options_t opts; |
|
900 }; |
|
901 ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t)); |
|
902 |
|
903 HB_INTERNAL void |
|
904 _hb_options_init (void); |
|
905 |
|
906 extern HB_INTERNAL hb_options_union_t _hb_options; |
|
907 |
|
908 static inline hb_options_t |
|
909 hb_options (void) |
|
910 { |
|
911 if (unlikely (!_hb_options.i)) |
|
912 _hb_options_init (); |
|
913 |
|
914 return _hb_options.opts; |
|
915 } |
|
916 |
|
917 |
|
918 #endif /* HB_PRIVATE_HH */ |