hb-private.hh 23.4 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009  Red Hat, Inc.
3
 * Copyright © 2011,2012  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

/* Essentials */

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

B
Behdad Esfahbod 已提交
64

B
Minor  
Behdad Esfahbod 已提交
65
/* Void! */
B
Behdad Esfahbod 已提交
66
struct _hb_void_t {};
67 68
typedef const _hb_void_t &hb_void_t;
#define HB_VOID (* (const _hb_void_t *) NULL)
B
Minor  
Behdad Esfahbod 已提交
69 70


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

73

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

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

82

B
Behdad Esfahbod 已提交
83
#undef  ARRAY_LENGTH
84
template <typename Type, unsigned int n>
B
Behdad Esfahbod 已提交
85
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
86 87
/* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
88

89 90
#define HB_STMT_START do
#define HB_STMT_END   while (0)
B
Behdad Esfahbod 已提交
91

B
Minor  
Behdad Esfahbod 已提交
92 93 94
#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 已提交
95

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

99 100
#define _PASTE1(a,b) a##b
#define PASTE(a,b) _PASTE1(a,b)
B
Behdad Esfahbod 已提交
101

B
Behdad Esfahbod 已提交
102 103 104 105 106 107 108 109 110 111 112
/* 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 已提交
113 114 115
ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
ASSERT_STATIC (sizeof (hb_position_t) == 4);
ASSERT_STATIC (sizeof (hb_mask_t) == 4);
116
ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
B
Behdad Esfahbod 已提交
117

118 119 120

/* We like our types POD */

B
Minor  
Behdad Esfahbod 已提交
121 122 123
#define _ASSERT_TYPE_POD1(_line, _type)	union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; }
#define _ASSERT_TYPE_POD0(_line, _type)	_ASSERT_TYPE_POD1 (_line, _type)
#define ASSERT_TYPE_POD(_type)		_ASSERT_TYPE_POD0 (__LINE__, _type)
124 125

#ifdef __GNUC__
B
Behdad Esfahbod 已提交
126 127 128 129 130
# define _ASSERT_INSTANCE_POD1(_line, _instance) \
	HB_STMT_START { \
		typedef __typeof__(_instance) _type_##_line; \
		_ASSERT_TYPE_POD1 (_line, _type_##_line); \
	} HB_STMT_END
131
#else
B
Minor  
Behdad Esfahbod 已提交
132
# define _ASSERT_INSTANCE_POD1(_line, _instance)	typedef int _assertion_on_line_##_line##_not_tested
133
#endif
B
Minor  
Behdad Esfahbod 已提交
134 135
# define _ASSERT_INSTANCE_POD0(_line, _instance)	_ASSERT_INSTANCE_POD1 (_line, _instance)
# define ASSERT_INSTANCE_POD(_instance)			_ASSERT_INSTANCE_POD0 (__LINE__, _instance)
136 137 138

/* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \
B
Minor  
Behdad Esfahbod 已提交
139 140 141 142
	inline void _static_assertion_on_line_##_line (void) const \
	{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line)	_ASSERT_POD1 (_line)
# define ASSERT_POD()		_ASSERT_POD0 (__LINE__)
143 144 145



B
Behdad Esfahbod 已提交
146 147
/* Misc */

B
Behdad Esfahbod 已提交
148

B
Behdad Esfahbod 已提交
149
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
150
#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
151 152
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
B
Behdad Esfahbod 已提交
153
#else
154 155
#define likely(expr) (expr)
#define unlikely(expr) (expr)
B
Behdad Esfahbod 已提交
156 157 158 159 160 161 162 163
#endif

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

#if __GNUC__ >= 3
164 165
#define HB_PURE_FUNC	__attribute__((pure))
#define HB_CONST_FUNC	__attribute__((const))
166
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
B
Behdad Esfahbod 已提交
167
#else
168 169
#define HB_PURE_FUNC
#define HB_CONST_FUNC
B
Behdad Esfahbod 已提交
170
#define HB_PRINTF_FUNC(format_idx, arg_idx)
B
Behdad Esfahbod 已提交
171
#endif
172
#if __GNUC__ >= 4
173
#define HB_UNUSED	__attribute__((unused))
174
#else
175
#define HB_UNUSED
176
#endif
B
Behdad Esfahbod 已提交
177

B
Behdad Esfahbod 已提交
178
#ifndef HB_INTERNAL
B
Behdad Esfahbod 已提交
179 180 181 182 183
# ifndef __MINGW32__
#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
#  define HB_INTERNAL
# endif
B
Behdad Esfahbod 已提交
184 185
#endif

B
Behdad Esfahbod 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

#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


202 203 204 205 206 207 208 209 210
#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 已提交
211
/* Return the number of 1 bits in mask. */
B
Behdad Esfahbod 已提交
212
static inline HB_CONST_FUNC unsigned int
B
Behdad Esfahbod 已提交
213 214 215
_hb_popcount32 (uint32_t mask)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
B
Behdad Esfahbod 已提交
216
  return __builtin_popcount (mask);
B
Behdad Esfahbod 已提交
217
#else
B
Behdad Esfahbod 已提交
218 219 220 221 222
  /* "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 已提交
223 224 225
#endif
}

B
Behdad Esfahbod 已提交
226 227 228 229 230
/* 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 已提交
231
  return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
B
Behdad Esfahbod 已提交
232 233 234 235 236 237 238 239 240
#else
  register unsigned int n_bits = 0;
  while (number) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}
B
Behdad Esfahbod 已提交
241

B
Behdad Esfahbod 已提交
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
/* 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
}

259 260 261 262 263 264 265
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 已提交
266 267 268 269
/* Type of bsearch() / qsort() compare function */
typedef int (*hb_compare_func_t) (const void *, const void *);


B
Behdad Esfahbod 已提交
270 271 272 273 274


/* arrays and maps */


B
Behdad Esfahbod 已提交
275
#define HB_PREALLOCED_ARRAY_INIT {0}
B
Behdad Esfahbod 已提交
276
template <typename Type, unsigned int StaticSize>
B
Behdad Esfahbod 已提交
277 278
struct hb_prealloced_array_t
{
B
Behdad Esfahbod 已提交
279 280 281 282 283
  unsigned int len;
  unsigned int allocated;
  Type *array;
  Type static_array[StaticSize];

284
  void init (void) { memset (this, 0, sizeof (*this)); }
285

286 287
  inline Type& operator [] (unsigned int i) { return array[i]; }
  inline const Type& operator [] (unsigned int i) const { return array[i]; }
B
Behdad Esfahbod 已提交
288 289 290 291 292 293 294 295 296

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

B
Behdad Esfahbod 已提交
298 299
    /* Need to reallocate */
    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
300 301
    Type *new_array = NULL;

B
Behdad Esfahbod 已提交
302 303
    if (array == static_array) {
      new_array = (Type *) calloc (new_allocated, sizeof (Type));
304
      if (new_array)
B
Behdad Esfahbod 已提交
305 306
        memcpy (new_array, array, len * sizeof (Type));
    } else {
307
      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
308
      if (likely (!overflows)) {
B
Behdad Esfahbod 已提交
309 310 311
	new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
      }
    }
312 313

    if (unlikely (!new_array))
B
Behdad Esfahbod 已提交
314
      return NULL;
315 316 317 318

    array = new_array;
    allocated = new_allocated;
    return &array[len++];
B
Behdad Esfahbod 已提交
319 320 321 322 323
  }

  inline void pop (void)
  {
    len--;
B
Minor  
Behdad Esfahbod 已提交
324 325 326 327 328 329 330 331 332 333
  }

  inline void remove (unsigned int i)
  {
     if (unlikely (i >= len))
       return;
     memmove (static_cast<void *> (&array[i]),
	      static_cast<void *> (&array[i + 1]),
	      (len - i - 1) * sizeof (Type));
     len--;
B
Behdad Esfahbod 已提交
334
  }
335 336 337 338 339 340 341

  inline void shrink (unsigned int l)
  {
     if (l < len)
       len = l;
  }

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
  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;
  }

357 358 359 360
  inline void sort (void)
  {
    qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
  }
361

362 363 364 365 366
  inline void sort (unsigned int start, unsigned int end)
  {
    qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
  }

367 368 369 370 371 372 373 374 375 376
  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 已提交
377 378 379 380 381 382 383 384

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

B
Minor  
Behdad Esfahbod 已提交
387
#define HB_AUTO_ARRAY_PREALLOCED 16
B
Behdad Esfahbod 已提交
388 389 390 391 392 393 394
template <typename Type>
struct hb_auto_array_t : hb_prealloced_array_t <Type, HB_AUTO_ARRAY_PREALLOCED>
{
  hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::init (); }
  ~hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::finish (); }
};

395

B
Behdad Esfahbod 已提交
396
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
397 398
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
B
Behdad Esfahbod 已提交
399
{
B
Behdad Esfahbod 已提交
400
  hb_prealloced_array_t <item_t, 2> items;
B
Behdad Esfahbod 已提交
401

402 403
  inline void init (void) { items.init (); }

404
  template <typename T>
405
  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
B
Behdad Esfahbod 已提交
406
  {
407
    l.lock ();
408
    item_t *item = items.find (v);
409
    if (item) {
410 411 412 413 414 415 416 417 418 419
      if (replace) {
	item_t old = *item;
	*item = v;
	l.unlock ();
	old.finish ();
      }
      else {
        item = NULL;
	l.unlock ();
      }
420
    } else {
B
Behdad Esfahbod 已提交
421
      item = items.push ();
422 423 424 425
      if (likely (item))
	*item = v;
      l.unlock ();
    }
426
    return item;
B
Behdad Esfahbod 已提交
427 428
  }

429
  template <typename T>
430
  inline void remove (T v, lock_t &l)
B
Behdad Esfahbod 已提交
431
  {
432
    l.lock ();
433
    item_t *item = items.find (v);
434 435 436 437 438 439 440 441 442
    if (item) {
      item_t old = *item;
      *item = items[items.len - 1];
      items.pop ();
      l.unlock ();
      old.finish ();
    } else {
      l.unlock ();
    }
B
Behdad Esfahbod 已提交
443
  }
444

445
  template <typename T>
446
  inline bool find (T v, item_t *i, lock_t &l)
B
Behdad Esfahbod 已提交
447
  {
448 449 450 451 452 453
    l.lock ();
    item_t *item = items.find (v);
    if (item)
      *i = *item;
    l.unlock ();
    return !!item;
454 455
  }

456
  template <typename T>
457 458 459 460
  inline item_t *find_or_insert (T v, lock_t &l)
  {
    l.lock ();
    item_t *item = items.find (v);
461 462 463 464 465
    if (!item) {
      item = items.push ();
      if (likely (item))
        *item = v;
    }
466
    l.unlock ();
467 468 469
    return item;
  }

470 471
  inline void finish (lock_t &l)
  {
472 473 474 475 476
    if (!items.len) {
      /* No need for locking. */
      items.finish ();
      return;
    }
477 478 479 480 481 482 483 484
    l.lock ();
    while (items.len) {
      item_t old = items[items.len - 1];
	items.pop ();
	l.unlock ();
	old.finish ();
	l.lock ();
    }
B
Behdad Esfahbod 已提交
485
    items.finish ();
486 487 488 489 490
    l.unlock ();
  }

};

B
Behdad Esfahbod 已提交
491

492 493


B
Behdad Esfahbod 已提交
494 495
/* Big-endian handling */

496 497 498
static inline uint16_t hb_be_uint16 (const uint16_t v)
{
  const uint8_t *V = (const uint8_t *) &v;
B
Behdad Esfahbod 已提交
499 500 501 502 503 504 505 506 507 508 509
  return (V[0] << 8) | V[1];
}

static inline uint16_t hb_uint16_swap (const uint16_t v)
{
  return (v >> 8) | (v << 8);
}

static inline uint32_t hb_uint32_swap (const uint32_t v)
{
  return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16);
510
}
B
Behdad Esfahbod 已提交
511

B
Behdad Esfahbod 已提交
512 513 514 515 516 517 518 519
/* 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.
 */

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

524
#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 已提交
525
#define hb_be_uint32_get(v)	(uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
526
#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 已提交
527

B
Behdad Esfahbod 已提交
528
#define hb_be_uint24_put(v,V)	HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] = (V); } HB_STMT_END
B
Behdad Esfahbod 已提交
529 530 531
#define hb_be_uint24_get(v)	(uint32_t) ((v[0] << 16) + (v[1] << 8) + v[2])
#define hb_be_uint24_eq(a,b)	(a[0] == b[0] && a[1] == b[1] && a[2] == b[2])

B
Behdad Esfahbod 已提交
532

B
Behdad Esfahbod 已提交
533
/* ASCII tag/character handling */
B
Behdad Esfahbod 已提交
534

535
static inline bool ISALPHA (unsigned char c)
536
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
537
static inline bool ISALNUM (unsigned char c)
538
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
539 540
static inline bool ISSPACE (unsigned char c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
541 542 543 544
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 已提交
545

B
Behdad Esfahbod 已提交
546 547 548 549 550
#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 已提交
551

B
Behdad Esfahbod 已提交
552 553 554 555 556
/* C++ helpers */

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


B
Behdad Esfahbod 已提交
560 561
/* Debug */

562

B
Behdad Esfahbod 已提交
563 564 565 566
#ifndef HB_DEBUG
#define HB_DEBUG 0
#endif

567 568 569 570 571 572 573
static inline bool
_hb_debug (unsigned int level,
	   unsigned int max_level)
{
  return level < max_level;
}

574 575
#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
576

577
template <int max_level> static inline void
578
_hb_debug_msg_va (const char *what,
B
Behdad Esfahbod 已提交
579 580 581 582 583 584 585
		  const void *obj,
		  const char *func,
		  bool indented,
		  unsigned int level,
		  int level_dir,
		  const char *message,
		  va_list ap)
586
{
B
Behdad Esfahbod 已提交
587
  if (!_hb_debug (level, max_level))
B
Minor  
Behdad Esfahbod 已提交
588
    return;
B
Behdad Esfahbod 已提交
589 590 591 592

  fprintf (stderr, "%-10s", what ? what : "");

  if (obj)
B
/Minor/  
Behdad Esfahbod 已提交
593
    fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
B
Behdad Esfahbod 已提交
594 595 596
  else
    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");

597
  if (indented) {
598 599 600 601 602 603 604 605
/* One may want to add ASCII version of these.  See:
 * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
#define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
#define VRBAR	"\342\224\234"	/* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
#define DLBAR	"\342\225\256"	/* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
#define ULBAR	"\342\225\257"	/* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
#define LBAR	"\342\225\264"	/* U+2574 BOX DRAWINGS LIGHT LEFT */
    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;
606
    fprintf (stderr, "%2u %s" VRBAR "%s",
B
Behdad Esfahbod 已提交
607
	     level,
608 609
	     bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
610
  } else
611
    fprintf (stderr, "   " VRBAR LBAR);
B
Behdad Esfahbod 已提交
612

613 614
  if (func)
  {
B
Behdad Esfahbod 已提交
615 616
    unsigned int func_len = strlen (func);
#ifndef HB_DEBUG_VERBOSE
617 618 619
    /* Skip "typename" */
    if (0 == strncmp (func, "typename ", 9))
      func += 9;
620
    /* Skip return type */
621
    const char *space = strchr (func, ' ');
622
    if (space)
623
      func = space + 1;
624 625
    /* Skip parameter list */
    const char *paren = strchr (func, '(');
B
Behdad Esfahbod 已提交
626 627 628
    if (paren)
      func_len = paren - func;
#endif
629
    fprintf (stderr, "%.*s: ", func_len, func);
630
  }
B
Behdad Esfahbod 已提交
631 632 633 634 635

  if (message)
    vfprintf (stderr, message, ap);

  fprintf (stderr, "\n");
636
}
B
Minor  
Behdad Esfahbod 已提交
637
template <> inline void
B
Behdad Esfahbod 已提交
638 639 640 641 642 643 644 645
_hb_debug_msg_va<0> (const char *what HB_UNUSED,
		     const void *obj HB_UNUSED,
		     const char *func HB_UNUSED,
		     bool indented HB_UNUSED,
		     unsigned int level HB_UNUSED,
		     int level_dir HB_UNUSED,
		     const char *message HB_UNUSED,
		     va_list ap HB_UNUSED) {}
646

647
template <int max_level> static inline void
648 649 650 651
_hb_debug_msg (const char *what,
	       const void *obj,
	       const char *func,
	       bool indented,
B
Behdad Esfahbod 已提交
652 653
	       unsigned int level,
	       int level_dir,
654
	       const char *message,
B
Behdad Esfahbod 已提交
655
	       ...) HB_PRINTF_FUNC(7, 8);
656
template <int max_level> static inline void
657 658 659 660
_hb_debug_msg (const char *what,
	       const void *obj,
	       const char *func,
	       bool indented,
B
Behdad Esfahbod 已提交
661 662
	       unsigned int level,
	       int level_dir,
663 664 665 666 667
	       const char *message,
	       ...)
{
  va_list ap;
  va_start (ap, message);
B
Minor  
Behdad Esfahbod 已提交
668
  _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
669 670
  va_end (ap);
}
B
Minor  
Behdad Esfahbod 已提交
671
template <> inline void
B
Behdad Esfahbod 已提交
672 673 674 675 676 677 678
_hb_debug_msg<0> (const char *what HB_UNUSED,
		  const void *obj HB_UNUSED,
		  const char *func HB_UNUSED,
		  bool indented HB_UNUSED,
		  unsigned int level HB_UNUSED,
		  int level_dir HB_UNUSED,
		  const char *message HB_UNUSED,
B
Behdad Esfahbod 已提交
679
		  ...) HB_PRINTF_FUNC(7, 8);
B
Minor  
Behdad Esfahbod 已提交
680
template <> inline void
B
Behdad Esfahbod 已提交
681 682 683 684 685 686 687
_hb_debug_msg<0> (const char *what HB_UNUSED,
		  const void *obj HB_UNUSED,
		  const char *func HB_UNUSED,
		  bool indented HB_UNUSED,
		  unsigned int level HB_UNUSED,
		  int level_dir HB_UNUSED,
		  const char *message HB_UNUSED,
B
Minor  
Behdad Esfahbod 已提交
688
		  ...) {}
B
Behdad Esfahbod 已提交
689

690 691 692
#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
#define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    false, 0, 0, __VA_ARGS__)
#define DEBUG_MSG_FUNC(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
693 694


B
Minor  
Behdad Esfahbod 已提交
695 696 697 698 699 700 701 702 703 704 705 706 707
/*
 * Printer
 */

template <typename T>
struct hb_printer_t {};

template <>
struct hb_printer_t<bool> {
  const char *print (bool v) { return v ? "true" : "false"; }
};

template <>
708
struct hb_printer_t<hb_void_t> {
B
Behdad Esfahbod 已提交
709
  const char *print (hb_void_t) { return ""; }
B
Minor  
Behdad Esfahbod 已提交
710 711 712
};


713 714 715 716
/*
 * Trace
 */

717 718 719 720 721 722 723 724
template <typename T>
static inline void _hb_warn_no_return (bool returned)
{
  if (unlikely (!returned)) {
    fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.\n");
  }
}
template <>
B
Behdad Esfahbod 已提交
725
inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
726 727 728
{}

template <int max_level, typename ret_t>
729 730
struct hb_auto_trace_t {
  explicit inline hb_auto_trace_t (unsigned int *plevel_,
B
Behdad Esfahbod 已提交
731 732
				   const char *what_,
				   const void *obj_,
733
				   const char *func,
734
				   const char *message,
B
Behdad Esfahbod 已提交
735
				   ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
736
  {
B
Behdad Esfahbod 已提交
737
    if (plevel) ++*plevel;
738 739 740

    va_list ap;
    va_start (ap, message);
741
    _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
742
    va_end (ap);
743
  }
744
  inline ~hb_auto_trace_t (void)
B
Behdad Esfahbod 已提交
745
  {
746 747
    _hb_warn_no_return<ret_t> (returned);
    if (!returned) {
748
      _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
749
    }
B
Behdad Esfahbod 已提交
750 751
    if (plevel) --*plevel;
  }
752

B
Behdad Esfahbod 已提交
753
  inline ret_t ret (ret_t v, unsigned int line = 0)
754 755 756 757 758 759
  {
    if (unlikely (returned)) {
      fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
      return v;
    }

760 761 762
    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
			      "return %s (line %d)",
			      hb_printer_t<ret_t>().print (v), line);
763 764 765 766 767 768
    if (plevel) --*plevel;
    plevel = NULL;
    returned = true;
    return v;
  }

769 770
  private:
  unsigned int *plevel;
B
Behdad Esfahbod 已提交
771 772
  const char *what;
  const void *obj;
B
Behdad Esfahbod 已提交
773
  bool returned;
774
};
775 776
template <typename ret_t> /* Optimize when tracing is disabled */
struct hb_auto_trace_t<0, ret_t> {
B
Behdad Esfahbod 已提交
777 778 779 780 781
  explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
				   const char *what HB_UNUSED,
				   const void *obj HB_UNUSED,
				   const char *func HB_UNUSED,
				   const char *message HB_UNUSED,
782
				   ...) {}
783

B
Behdad Esfahbod 已提交
784
  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
785 786
};

787
#define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
788 789 790

/* Misc */

B
Behdad Esfahbod 已提交
791

B
Minor  
Behdad Esfahbod 已提交
792 793 794 795
/* 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
Behdad Esfahbod 已提交
796
template <typename T> static inline bool
B
Minor  
Behdad Esfahbod 已提交
797
hb_in_range (T u, T lo, T hi)
B
Minor  
Behdad Esfahbod 已提交
798 799 800 801 802 803 804 805 806
{
  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;
}

807
template <typename T> static inline bool
B
Behdad Esfahbod 已提交
808
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
809
{
B
Behdad Esfahbod 已提交
810
  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
811 812
}

B
Minor  
Behdad Esfahbod 已提交
813

B
Behdad Esfahbod 已提交
814 815 816 817
/* 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
Behdad Esfahbod 已提交
818
#define FLAG(x) (1<<(x))
819
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
B
Minor  
Behdad Esfahbod 已提交
820

B
Minor  
Behdad Esfahbod 已提交
821

822 823
template <typename T, typename T2> inline void
hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
B
Behdad Esfahbod 已提交
824 825 826 827 828 829 830 831 832
{
  if (unlikely (!len))
    return;

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

    for (unsigned int j = 0; j < k; j++)
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
      if (compar (&array[j], &array[j+1]) > 0)
      {
        {
	  T t;
	  t = array[j];
	  array[j] = array[j + 1];
	  array[j + 1] = t;
	}
        if (array2)
        {
	  T2 t;
	  t = array2[j];
	  array2[j] = array2[j + 1];
	  array2[j + 1] = t;
	}
B
Behdad Esfahbod 已提交
848 849 850 851 852 853 854

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

855 856 857 858 859
template <typename T> inline void
hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
{
  hb_bubble_sort (array, len, compar, (int *) NULL);
}
B
Behdad Esfahbod 已提交
860

861 862 863 864 865
static inline hb_bool_t
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
{
  /* Pain because we don't know whether s is nul-terminated. */
  char buf[64];
866 867 868
  len = MIN (ARRAY_LENGTH (buf) - 1, len);
  strncpy (buf, s, len);
  buf[len] = '\0';
869 870 871 872 873 874 875 876 877

  char *end;
  errno = 0;
  unsigned long v = strtoul (buf, &end, base);
  if (errno) return false;
  if (*end) return false;
  *out = v;
  return true;
}
B
Behdad Esfahbod 已提交
878

B
Behdad Esfahbod 已提交
879

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
/* Global runtime options. */

struct hb_options_t
{
  int initialized : 1;
  int uniscribe_bug_compatible : 1;
};

union hb_options_union_t {
  int i;
  hb_options_t opts;
};
ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));

HB_INTERNAL void
_hb_options_init (void);

extern HB_INTERNAL hb_options_union_t _hb_options;

static inline hb_options_t
hb_options (void)
{
  if (unlikely (!_hb_options.i))
    _hb_options_init ();

  return _hb_options.opts;
}


909
#endif /* HB_PRIVATE_HH */