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