hb-private.hh 15.6 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2 3
 * Copyright © 2007,2008,2009  Red Hat, Inc.
 * Copyright © 2011  Google, Inc.
B
Behdad Esfahbod 已提交
4
 *
B
Behdad Esfahbod 已提交
5
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
26
 * Google Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
27 28
 */

29 30
#ifndef HB_PRIVATE_HH
#define HB_PRIVATE_HH
B
Behdad Esfahbod 已提交
31

B
Minor  
Behdad Esfahbod 已提交
32
#ifdef HAVE_CONFIG_H
B
Behdad Esfahbod 已提交
33 34
#include "config.h"
#endif
B
Behdad Esfahbod 已提交
35

36 37
#include "hb.h"
#define HB_H_IN
B
Minor  
Behdad Esfahbod 已提交
38 39
#ifdef HAVE_OT
#include "hb-ot.h"
40
#define HB_OT_H_IN
B
Minor  
Behdad Esfahbod 已提交
41
#endif
42

B
Behdad Esfahbod 已提交
43
#include <stdlib.h>
44
#include <stddef.h>
B
Behdad Esfahbod 已提交
45 46
#include <string.h>
#include <assert.h>
B
Minor  
Behdad Esfahbod 已提交
47 48 49 50 51

/* We only use these two for debug output.  However, the debug code is
 * always seen by the compiler (and optimized out in non-debug builds.
 * If including these becomes a problem, we can start thinking about
 * someway around that. */
52 53
#include <stdio.h>
#include <errno.h>
54
#include <stdarg.h>
B
Behdad Esfahbod 已提交
55

B
Behdad Esfahbod 已提交
56

B
Behdad Esfahbod 已提交
57 58 59 60 61 62 63 64 65 66 67 68

/* Essentials */

#ifndef NULL
# define NULL ((void *) 0)
#endif

#undef FALSE
#define FALSE 0

#undef TRUE
#define TRUE 1
B
Behdad Esfahbod 已提交
69

B
Behdad Esfahbod 已提交
70

B
Behdad Esfahbod 已提交
71 72
/* Basics */

73

B
Behdad Esfahbod 已提交
74
#undef MIN
75
template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
B
Minor  
Behdad Esfahbod 已提交
76

77
#undef MAX
78 79
template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }

80

B
Behdad Esfahbod 已提交
81 82
#undef  ARRAY_LENGTH
#define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
83

84 85
#define HB_STMT_START do
#define HB_STMT_END   while (0)
B
Behdad Esfahbod 已提交
86

B
Behdad Esfahbod 已提交
87 88 89 90
#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))

B
Behdad Esfahbod 已提交
91
#define ASSERT_STATIC_EXPR(_cond) ((void) sizeof (char[(_cond) ? 1 : -1]))
92
#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
B
Behdad Esfahbod 已提交
93

B
Behdad Esfahbod 已提交
94

B
Behdad Esfahbod 已提交
95 96 97 98 99 100 101 102 103 104 105
/* Lets assert int types.  Saves trouble down the road. */

ASSERT_STATIC (sizeof (int8_t) == 1);
ASSERT_STATIC (sizeof (uint8_t) == 1);
ASSERT_STATIC (sizeof (int16_t) == 2);
ASSERT_STATIC (sizeof (uint16_t) == 2);
ASSERT_STATIC (sizeof (int32_t) == 4);
ASSERT_STATIC (sizeof (uint32_t) == 4);
ASSERT_STATIC (sizeof (int64_t) == 8);
ASSERT_STATIC (sizeof (uint64_t) == 8);

B
Behdad Esfahbod 已提交
106 107 108
ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
ASSERT_STATIC (sizeof (hb_position_t) == 4);
ASSERT_STATIC (sizeof (hb_mask_t) == 4);
109
ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
B
Behdad Esfahbod 已提交
110

B
Behdad Esfahbod 已提交
111 112
/* Misc */

B
Behdad Esfahbod 已提交
113

B
Behdad Esfahbod 已提交
114
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
115
#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
116 117
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
B
Behdad Esfahbod 已提交
118
#else
119 120
#define likely(expr) (expr)
#define unlikely(expr) (expr)
B
Behdad Esfahbod 已提交
121 122 123 124 125 126 127 128
#endif

#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif

#if __GNUC__ >= 3
129 130
#define HB_PURE_FUNC	__attribute__((pure))
#define HB_CONST_FUNC	__attribute__((const))
131
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
B
Behdad Esfahbod 已提交
132
#else
133 134
#define HB_PURE_FUNC
#define HB_CONST_FUNC
B
Behdad Esfahbod 已提交
135
#define HB_PRINTF_FUNC(format_idx, arg_idx)
B
Behdad Esfahbod 已提交
136
#endif
137
#if __GNUC__ >= 4
138
#define HB_UNUSED	__attribute__((unused))
139
#else
140
#define HB_UNUSED
141
#endif
B
Behdad Esfahbod 已提交
142

B
Behdad Esfahbod 已提交
143
#ifndef HB_INTERNAL
B
Behdad Esfahbod 已提交
144 145 146 147 148
# ifndef __MINGW32__
#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
#  define HB_INTERNAL
# endif
B
Behdad Esfahbod 已提交
149 150
#endif

B
Behdad Esfahbod 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#endif

#ifdef _MSC_VER
#undef inline
#define inline __inline
#endif

#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif


167 168 169 170 171 172 173 174 175
#if __GNUC__ >= 3
#define HB_FUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define HB_FUNC __FUNCSIG__
#else
#define HB_FUNC __func__
#endif


B
Behdad Esfahbod 已提交
176
/* Return the number of 1 bits in mask. */
B
Behdad Esfahbod 已提交
177
static inline HB_CONST_FUNC unsigned int
B
Behdad Esfahbod 已提交
178 179 180
_hb_popcount32 (uint32_t mask)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
B
Behdad Esfahbod 已提交
181
  return __builtin_popcount (mask);
B
Behdad Esfahbod 已提交
182
#else
B
Behdad Esfahbod 已提交
183 184 185 186 187
  /* "HACKMEM 169" */
  register uint32_t y;
  y = (mask >> 1) &033333333333;
  y = mask - y - ((y >>1) & 033333333333);
  return (((y + (y >> 3)) & 030707070707) % 077);
B
Behdad Esfahbod 已提交
188 189 190
#endif
}

B
Behdad Esfahbod 已提交
191 192 193 194 195
/* Returns the number of bits needed to store number */
static inline HB_CONST_FUNC unsigned int
_hb_bit_storage (unsigned int number)
{
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
B
Behdad Esfahbod 已提交
196
  return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
B
Behdad Esfahbod 已提交
197 198 199 200 201 202 203 204 205
#else
  register unsigned int n_bits = 0;
  while (number) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}
B
Behdad Esfahbod 已提交
206

B
Behdad Esfahbod 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
/* Returns the number of zero bits in the least significant side of number */
static inline HB_CONST_FUNC unsigned int
_hb_ctz (unsigned int number)
{
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
  return likely (number) ? __builtin_ctz (number) : 0;
#else
  register unsigned int n_bits = 0;
  if (unlikely (!number)) return 0;
  while (!(number & 1)) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}

224 225 226 227 228 229 230
static inline bool
_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
{
  return (size > 0) && (count >= ((unsigned int) -1) / size);
}


B
Behdad Esfahbod 已提交
231 232 233 234
/* Type of bsearch() / qsort() compare function */
typedef int (*hb_compare_func_t) (const void *, const void *);


B
Behdad Esfahbod 已提交
235 236 237 238 239 240


/* arrays and maps */


template <typename Type, unsigned int StaticSize>
B
Minor  
Behdad Esfahbod 已提交
241
struct hb_prealloced_array_t {
B
Behdad Esfahbod 已提交
242 243 244 245 246 247

  unsigned int len;
  unsigned int allocated;
  Type *array;
  Type static_array[StaticSize];

248 249
  hb_prealloced_array_t (void) { memset (this, 0, sizeof (*this)); }

250 251
  inline Type& operator [] (unsigned int i) { return array[i]; }
  inline const Type& operator [] (unsigned int i) const { return array[i]; }
B
Behdad Esfahbod 已提交
252 253 254 255 256 257 258 259 260

  inline Type *push (void)
  {
    if (!array) {
      array = static_array;
      allocated = ARRAY_LENGTH (static_array);
    }
    if (likely (len < allocated))
      return &array[len++];
261

B
Behdad Esfahbod 已提交
262 263
    /* Need to reallocate */
    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
264 265
    Type *new_array = NULL;

B
Behdad Esfahbod 已提交
266 267
    if (array == static_array) {
      new_array = (Type *) calloc (new_allocated, sizeof (Type));
268
      if (new_array)
B
Behdad Esfahbod 已提交
269 270
        memcpy (new_array, array, len * sizeof (Type));
    } else {
271
      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
272
      if (likely (!overflows)) {
B
Behdad Esfahbod 已提交
273 274 275
	new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
      }
    }
276 277

    if (unlikely (!new_array))
B
Behdad Esfahbod 已提交
278
      return NULL;
279 280 281 282

    array = new_array;
    allocated = new_allocated;
    return &array[len++];
B
Behdad Esfahbod 已提交
283 284 285 286 287 288 289
  }

  inline void pop (void)
  {
    len--;
    /* TODO: shrink array if needed */
  }
290 291 292 293 294 295 296 297

  inline void shrink (unsigned int l)
  {
     if (l < len)
       len = l;
    /* TODO: shrink array if needed */
  }

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
  template <typename T>
  inline Type *find (T v) {
    for (unsigned int i = 0; i < len; i++)
      if (array[i] == v)
	return &array[i];
    return NULL;
  }
  template <typename T>
  inline const Type *find (T v) const {
    for (unsigned int i = 0; i < len; i++)
      if (array[i] == v)
	return &array[i];
    return NULL;
  }

313 314 315 316
  inline void sort (void)
  {
    qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
  }
317

318 319 320 321 322
  inline void sort (unsigned int start, unsigned int end)
  {
    qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
  }

323 324 325 326 327 328 329 330 331 332
  template <typename T>
  inline Type *bsearch (T *key)
  {
    return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
  }
  template <typename T>
  inline const Type *bsearch (T *key) const
  {
    return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
  }
B
Behdad Esfahbod 已提交
333 334 335 336 337 338 339 340

  inline void finish (void)
  {
    if (array != static_array)
      free (array);
    array = NULL;
    allocated = len = 0;
  }
B
Behdad Esfahbod 已提交
341 342 343
};

template <typename Type>
B
Minor  
Behdad Esfahbod 已提交
344
struct hb_array_t : hb_prealloced_array_t<Type, 2> {};
345 346


347 348
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
B
Behdad Esfahbod 已提交
349 350 351
{
  hb_array_t <item_t> items;

352
  template <typename T>
353
  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
B
Behdad Esfahbod 已提交
354
  {
355
    l.lock ();
356
    item_t *item = items.find (v);
357
    if (item) {
358 359 360 361 362 363 364 365 366 367
      if (replace) {
	item_t old = *item;
	*item = v;
	l.unlock ();
	old.finish ();
      }
      else {
        item = NULL;
	l.unlock ();
      }
368
    } else {
B
Behdad Esfahbod 已提交
369
      item = items.push ();
370 371 372 373
      if (likely (item))
	*item = v;
      l.unlock ();
    }
374
    return item;
B
Behdad Esfahbod 已提交
375 376
  }

377
  template <typename T>
378
  inline void remove (T v, lock_t &l)
B
Behdad Esfahbod 已提交
379
  {
380
    l.lock ();
381
    item_t *item = items.find (v);
382 383 384 385 386 387 388 389 390
    if (item) {
      item_t old = *item;
      *item = items[items.len - 1];
      items.pop ();
      l.unlock ();
      old.finish ();
    } else {
      l.unlock ();
    }
B
Behdad Esfahbod 已提交
391
  }
392

393
  template <typename T>
394
  inline bool find (T v, item_t *i, lock_t &l)
B
Behdad Esfahbod 已提交
395
  {
396 397 398 399 400 401
    l.lock ();
    item_t *item = items.find (v);
    if (item)
      *i = *item;
    l.unlock ();
    return !!item;
402 403
  }

404
  template <typename T>
405 406 407 408
  inline item_t *find_or_insert (T v, lock_t &l)
  {
    l.lock ();
    item_t *item = items.find (v);
409 410 411 412 413
    if (!item) {
      item = items.push ();
      if (likely (item))
        *item = v;
    }
414
    l.unlock ();
415 416 417
    return item;
  }

418 419 420 421 422 423 424 425 426 427
  inline void finish (lock_t &l)
  {
    l.lock ();
    while (items.len) {
      item_t old = items[items.len - 1];
	items.pop ();
	l.unlock ();
	old.finish ();
	l.lock ();
    }
B
Behdad Esfahbod 已提交
428
    items.finish ();
429 430 431 432 433
    l.unlock ();
  }

};

B
Behdad Esfahbod 已提交
434

435 436


B
Behdad Esfahbod 已提交
437 438
/* Big-endian handling */

439 440 441 442 443
static inline uint16_t hb_be_uint16 (const uint16_t v)
{
  const uint8_t *V = (const uint8_t *) &v;
  return (uint16_t) (V[0] << 8) + V[1];
}
B
Behdad Esfahbod 已提交
444

B
Behdad Esfahbod 已提交
445 446 447 448 449 450 451 452
/* Note, of the following macros, uint16_get is the one called many many times.
 * If there is any optimizations to be done, it's in that macro.  However, I
 * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
 * results in a single ror instruction, does NOT speed this up.  In fact, it
 * resulted in a minor slowdown.  At any rate, note that v may not be correctly
 * aligned, so I think the current implementation is optimal.
 */

453
#define hb_be_uint16_put(v,V)	HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
B
Behdad Esfahbod 已提交
454
#define hb_be_uint16_get(v)	(uint16_t) ((v[0] << 8) + v[1])
455
#define hb_be_uint16_eq(a,b)	(a[0] == b[0] && a[1] == b[1])
B
Behdad Esfahbod 已提交
456

457
#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
B
Behdad Esfahbod 已提交
458
#define hb_be_uint32_get(v)	(uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
459
#define hb_be_uint32_eq(a,b)	(a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
B
Behdad Esfahbod 已提交
460 461


B
Behdad Esfahbod 已提交
462
/* ASCII tag/character handling */
B
Behdad Esfahbod 已提交
463

464 465 466 467 468 469 470 471
static inline unsigned char ISALPHA (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
static inline unsigned char ISALNUM (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
static inline unsigned char TOUPPER (unsigned char c)
{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
static inline unsigned char TOLOWER (unsigned char c)
{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
B
Behdad Esfahbod 已提交
472

B
Behdad Esfahbod 已提交
473 474 475 476 477
#define HB_TAG_CHAR4(s)   (HB_TAG(((const char *) s)[0], \
				  ((const char *) s)[1], \
				  ((const char *) s)[2], \
				  ((const char *) s)[3]))

B
Behdad Esfahbod 已提交
478

B
Behdad Esfahbod 已提交
479 480 481 482 483
/* C++ helpers */

/* Makes class uncopyable.  Use in private: section. */
#define NO_COPY(T) \
  T (const T &o); \
B
Behdad Esfahbod 已提交
484
  T &operator = (const T &o)
B
Behdad Esfahbod 已提交
485 486


B
Behdad Esfahbod 已提交
487 488
/* Debug */

489

B
Behdad Esfahbod 已提交
490 491 492 493
#ifndef HB_DEBUG
#define HB_DEBUG 0
#endif

494 495 496 497 498 499 500 501
static inline bool
_hb_debug (unsigned int level,
	   unsigned int max_level)
{
  return level < max_level;
}

#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
502 503
#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))

504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
template <int max_level> inline bool /* always returns TRUE */
_hb_debug_msg (const char *what,
	       const void *obj,
	       const char *func,
	       bool indented,
	       int level,
	       const char *message,
	       ...) HB_PRINTF_FUNC(6, 7);
template <int max_level> inline bool /* always returns TRUE */
_hb_debug_msg (const char *what,
	       const void *obj,
	       const char *func,
	       bool indented,
	       int level,
	       const char *message,
	       ...)
{
  va_list ap;
  va_start (ap, message);

  (void) (_hb_debug (level, max_level) &&
525 526 527
	  fprintf (stderr, "%s", what) &&
	  (obj && fprintf (stderr, "(%p)", obj), TRUE) &&
	  fprintf (stderr, ": ") &&
528 529 530 531 532 533
	  (func && fprintf (stderr, "%s: ", func), TRUE) &&
	  (indented && fprintf (stderr, "%-*d-> ", level + 1, level), TRUE) &&
	  vfprintf (stderr, message, ap) &&
	  fprintf (stderr, "\n"));

  va_end (ap);
534

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
  return TRUE;
}
template <> inline bool /* always returns TRUE */
_hb_debug_msg<0> (const char *what,
		  const void *obj,
		  const char *func,
		  bool indented,
		  int level,
		  const char *message,
		  ...) HB_PRINTF_FUNC(6, 7);
template <> inline bool /* always returns TRUE */
_hb_debug_msg<0> (const char *what,
		  const void *obj,
		  const char *func,
		  bool indented,
		  int level,
		  const char *message,
		  ...)
B
Behdad Esfahbod 已提交
553 554 555 556
{
  return TRUE;
}

557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, FALSE, (LEVEL), __VA_ARGS__)
#define DEBUG_MSG(WHAT, OBJ, ...) DEBUG_MSG_LEVEL (WHAT, OBJ, 0, __VA_ARGS__)
#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, FALSE, 0, __VA_ARGS__)


/*
 * Trace
 */

template <int max_level>
struct hb_auto_trace_t {
  explicit inline hb_auto_trace_t (unsigned int *plevel_,
				   const char *what,
				   const void *obj,
				   const char *func,
				   const char *message) : plevel(plevel_)
  {
    if (max_level) ++*plevel;
    /* TODO support variadic args here */
    _hb_debug_msg<max_level> (what, obj, func, TRUE, *plevel, "%s", message);
  }
  ~hb_auto_trace_t (void) { if (max_level) --*plevel; }

  private:
  unsigned int *plevel;
};
template <> /* Optimize when tracing is disabled */
struct hb_auto_trace_t<0> {
  explicit inline hb_auto_trace_t (unsigned int *plevel_,
				   const char *what,
				   const void *obj,
				   const char *func,
				   const char *message) {}
};


/* Misc */

B
Behdad Esfahbod 已提交
595

B
Minor  
Behdad Esfahbod 已提交
596 597 598 599
/* Pre-mature optimization:
 * Checks for lo <= u <= hi but with an optimization if lo and hi
 * are only different in a contiguous set of lower-most bits.
 */
B
Minor  
Behdad Esfahbod 已提交
600 601
template <typename T> inline bool
hb_in_range (T u, T lo, T hi)
B
Minor  
Behdad Esfahbod 已提交
602 603 604 605 606 607 608 609 610 611
{
  if ( ((lo^hi) & lo) == 0 &&
       ((lo^hi) & hi) == (lo^hi) &&
       ((lo^hi) & ((lo^hi) + 1)) == 0 )
    return (u & ~(lo^hi)) == lo;
  else
    return lo <= u && u <= hi;
}


B
Behdad Esfahbod 已提交
612 613 614 615
/* Useful for set-operations on small enums.
 * For example, for testing "x ∈ {x1, x2, x3}" use:
 * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
 */
B
Minor  
Behdad Esfahbod 已提交
616 617
#define FLAG(x) (1<<(x))

B
Minor  
Behdad Esfahbod 已提交
618

B
Behdad Esfahbod 已提交
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
template <typename T> inline void
hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
{
  if (unlikely (!len))
    return;

  unsigned int k = len - 1;
  do {
    unsigned int new_k = 0;

    for (unsigned int j = 0; j < k; j++)
      if (compar (&array[j], &array[j+1]) > 0) {
        T t;
	t = array[j];
	array[j] = array[j + 1];
	array[j + 1] = t;

	new_k = j;
      }
    k = new_k;
  } while (k);
}



B
Behdad Esfahbod 已提交
644

645
#endif /* HB_PRIVATE_HH */