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