hb-private.hh 15.0 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
Behdad Esfahbod 已提交
32 33 34
#if HAVE_CONFIG_H
#include "config.h"
#endif
B
Behdad Esfahbod 已提交
35

B
Behdad Esfahbod 已提交
36
#include "hb-common.h"
37

B
Behdad Esfahbod 已提交
38
#include <stdlib.h>
39
#include <stddef.h>
B
Behdad Esfahbod 已提交
40 41
#include <string.h>
#include <assert.h>
B
Minor  
Behdad Esfahbod 已提交
42 43 44 45 46

/* 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. */
47 48
#include <stdio.h>
#include <errno.h>
49
#include <stdarg.h>
B
Behdad Esfahbod 已提交
50

B
Behdad Esfahbod 已提交
51 52
HB_BEGIN_DECLS

B
Behdad Esfahbod 已提交
53 54 55 56 57 58 59 60 61 62 63 64

/* Essentials */

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

#undef FALSE
#define FALSE 0

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

B
Behdad Esfahbod 已提交
66

B
Behdad Esfahbod 已提交
67 68
/* Basics */

69 70
HB_END_DECLS

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

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

HB_BEGIN_DECLS
78

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

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

B
Behdad Esfahbod 已提交
85 86 87 88
#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 已提交
89
#define ASSERT_STATIC_EXPR(_cond) ((void) sizeof (char[(_cond) ? 1 : -1]))
90
#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
B
Behdad Esfahbod 已提交
91

B
Behdad Esfahbod 已提交
92

B
Behdad Esfahbod 已提交
93 94 95 96 97 98 99 100 101 102 103
/* 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 已提交
104 105 106
ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
ASSERT_STATIC (sizeof (hb_position_t) == 4);
ASSERT_STATIC (sizeof (hb_mask_t) == 4);
107
ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
B
Behdad Esfahbod 已提交
108

B
Behdad Esfahbod 已提交
109 110
/* Misc */

B
Behdad Esfahbod 已提交
111

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

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

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

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

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

#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


165 166 167 168 169 170 171 172 173
#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 已提交
174
/* Return the number of 1 bits in mask. */
B
Behdad Esfahbod 已提交
175
static inline HB_CONST_FUNC unsigned int
B
Behdad Esfahbod 已提交
176 177 178
_hb_popcount32 (uint32_t mask)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
B
Behdad Esfahbod 已提交
179
  return __builtin_popcount (mask);
B
Behdad Esfahbod 已提交
180
#else
B
Behdad Esfahbod 已提交
181 182 183 184 185
  /* "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 已提交
186 187 188
#endif
}

B
Behdad Esfahbod 已提交
189 190 191 192 193
/* 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 已提交
194
  return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
B
Behdad Esfahbod 已提交
195 196 197 198 199 200 201 202 203
#else
  register unsigned int n_bits = 0;
  while (number) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}
B
Behdad Esfahbod 已提交
204

B
Behdad Esfahbod 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
/* 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
}

222 223 224 225 226 227 228
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 已提交
229 230 231 232
/* Type of bsearch() / qsort() compare function */
typedef int (*hb_compare_func_t) (const void *, const void *);


B
Behdad Esfahbod 已提交
233 234 235 236 237 238 239
HB_END_DECLS


/* arrays and maps */


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

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

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

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

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

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

    if (unlikely (!new_array))
B
Behdad Esfahbod 已提交
275
      return NULL;
276 277 278 279

    array = new_array;
    allocated = new_allocated;
    return &array[len++];
B
Behdad Esfahbod 已提交
280 281 282 283 284 285 286
  }

  inline void pop (void)
  {
    len--;
    /* TODO: shrink array if needed */
  }
287 288 289 290 291 292 293 294

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

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
  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;
  }

310 311 312 313
  inline void sort (void)
  {
    qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
  }
314

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

320 321 322 323 324 325 326 327 328 329
  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 已提交
330 331 332 333 334 335 336 337

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

template <typename Type>
B
Minor  
Behdad Esfahbod 已提交
341
struct hb_array_t : hb_prealloced_array_t<Type, 2> {};
342 343


344 345
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
B
Behdad Esfahbod 已提交
346 347 348
{
  hb_array_t <item_t> items;

349
  template <typename T>
350
  inline item_t *replace_or_insert (T v, lock_t &l)
B
Behdad Esfahbod 已提交
351
  {
352
    l.lock ();
353
    item_t *item = items.find (v);
354 355 356 357 358 359
    if (item) {
      item_t old = *item;
      *item = v;
      l.unlock ();
      old.finish ();
    } else {
B
Behdad Esfahbod 已提交
360
      item = items.push ();
361 362 363 364
      if (likely (item))
	*item = v;
      l.unlock ();
    }
365
    return item;
B
Behdad Esfahbod 已提交
366 367
  }

368
  template <typename T>
369
  inline void remove (T v, lock_t &l)
B
Behdad Esfahbod 已提交
370
  {
371
    l.lock ();
372
    item_t *item = items.find (v);
373 374 375 376 377 378 379 380 381
    if (item) {
      item_t old = *item;
      *item = items[items.len - 1];
      items.pop ();
      l.unlock ();
      old.finish ();
    } else {
      l.unlock ();
    }
B
Behdad Esfahbod 已提交
382
  }
383

384
  template <typename T>
385
  inline bool find (T v, item_t *i, lock_t &l)
B
Behdad Esfahbod 已提交
386
  {
387 388 389 390 391 392
    l.lock ();
    item_t *item = items.find (v);
    if (item)
      *i = *item;
    l.unlock ();
    return !!item;
393 394
  }

395
  template <typename T>
396 397 398 399
  inline item_t *find_or_insert (T v, lock_t &l)
  {
    l.lock ();
    item_t *item = items.find (v);
400 401 402 403 404
    if (!item) {
      item = items.push ();
      if (likely (item))
        *item = v;
    }
405
    l.unlock ();
406 407 408
    return item;
  }

409 410 411 412 413 414 415 416 417 418
  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 已提交
419
    items.finish ();
420 421 422 423 424
    l.unlock ();
  }

};

B
Behdad Esfahbod 已提交
425 426

HB_BEGIN_DECLS
427 428


B
Behdad Esfahbod 已提交
429 430
/* Big-endian handling */

431 432 433 434 435
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 已提交
436

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

441
#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 已提交
442
#define hb_be_uint32_get(v)	(uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
443
#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 已提交
444 445


B
Behdad Esfahbod 已提交
446
/* ASCII tag/character handling */
B
Behdad Esfahbod 已提交
447

448 449 450 451 452 453 454 455
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 已提交
456

B
Behdad Esfahbod 已提交
457 458 459 460 461
#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 已提交
462

B
Behdad Esfahbod 已提交
463 464 465 466 467
/* C++ helpers */

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


B
Behdad Esfahbod 已提交
471 472
/* Debug */

473 474
HB_END_DECLS

B
Behdad Esfahbod 已提交
475 476 477 478
#ifndef HB_DEBUG
#define HB_DEBUG 0
#endif

479 480 481 482 483 484 485 486
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))
487 488
#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))

489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
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) &&
	  fprintf (stderr, "%s(%p): ", what, obj) &&
	  (func && fprintf (stderr, "%s: ", func), TRUE) &&
	  (indented && fprintf (stderr, "%-*d-> ", level + 1, level), TRUE) &&
	  vfprintf (stderr, message, ap) &&
	  fprintf (stderr, "\n"));

  va_end (ap);
517

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
  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 已提交
536 537 538 539
{
  return TRUE;
}

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
#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 已提交
578

B
Minor  
Behdad Esfahbod 已提交
579 580 581 582
/* 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 已提交
583 584
template <typename T> inline bool
hb_in_range (T u, T lo, T hi)
B
Minor  
Behdad Esfahbod 已提交
585 586 587 588 589 590 591 592 593 594
{
  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 已提交
595 596 597 598
/* 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 已提交
599 600
#define FLAG(x) (1<<(x))

B
Minor  
Behdad Esfahbod 已提交
601

B
Behdad Esfahbod 已提交
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
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);
}


HB_BEGIN_DECLS

B
Behdad Esfahbod 已提交
628 629
HB_END_DECLS

630
#endif /* HB_PRIVATE_HH */