hb-private.hh 25.7 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
/* Compiler attributes */
B
Behdad Esfahbod 已提交
58 59


B
Behdad Esfahbod 已提交
60 61 62 63 64 65 66
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
B
Behdad Esfahbod 已提交
67 68
#endif

B
Behdad Esfahbod 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif

#if __GNUC__ >= 3
#define HB_PURE_FUNC	__attribute__((pure))
#define HB_CONST_FUNC	__attribute__((const))
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
#define HB_PURE_FUNC
#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if __GNUC__ >= 4
#define HB_UNUSED	__attribute__((unused))
#else
#define HB_UNUSED
#endif

#ifndef HB_INTERNAL
90
# if !defined(__MINGW32__) && !defined(__CYGWIN__)
B
Behdad Esfahbod 已提交
91 92 93 94 95 96 97 98
#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
#  define HB_INTERNAL
# endif
#endif

#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
99 100
/* Windows CE only has _strdup, while rest of Windows has both. */
#define strdup _strdup
B
Behdad Esfahbod 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
#endif

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

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

#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 已提交
120

B
Behdad Esfahbod 已提交
121
#if defined(_WIN32) || defined(__CYGWIN__)
122 123 124 125 126 127 128 129 130 131
   /* We need Windows Vista for both Uniscribe backend and for
    * MemoryBarrier.  We don't support compiling on Windows XP,
    * though we run on it fine. */
#  if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
#    undef _WIN32_WINNT
#  endif
#  ifndef _WIN32_WINNT
#    define _WIN32_WINNT 0x0600
#  endif
#  define WIN32_LEAN_AND_MEAN
132
#  define STRICT
133
#endif
B
Minor  
Behdad Esfahbod 已提交
134

135 136 137 138 139 140 141 142
#ifdef _WIN32_WCE
/* Some things not defined on Windows CE. */
#define MemoryBarrier()
#define getenv(Name) NULL
#define setlocale(Category, Locale) "C"
static int errno = 0; /* Use something better? */
#endif

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
#if HAVE_ATEXIT
/* atexit() is only safe to be called from shared libraries on certain
 * platforms.  Whitelist.
 * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
#  if defined(__linux) && defined(__GLIBC_PREREQ)
#    if __GLIBC_PREREQ(2,3)
/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
#      define HB_USE_ATEXIT 1
#    endif
#  elif defined(_MSC_VER) || defined(__MINGW32__)
/* For MSVC:
 * http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
 * http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
 * mingw32 headers say atexit is safe to use in shared libraries.
 */
#    define HB_USE_ATEXIT 1
#  elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
/* This was fixed in Android NKD r8 or r8b:
 * https://code.google.com/p/android/issues/detail?id=6455
 * which introduced GCC 4.6:
 * https://developer.android.com/tools/sdk/ndk/index.html
 */
#    define HB_USE_ATEXIT 1
#  endif
#endif
B
Minor  
Behdad Esfahbod 已提交
168

B
Behdad Esfahbod 已提交
169 170
/* Basics */

171

B
Behdad Esfahbod 已提交
172 173 174 175
#ifndef NULL
# define NULL ((void *) 0)
#endif

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

180
#undef MAX
181 182
template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
183

184 185 186
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }

187

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

194 195
#define HB_STMT_START do
#define HB_STMT_END   while (0)
B
Behdad Esfahbod 已提交
196

197
#define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
B
Minor  
Behdad Esfahbod 已提交
198 199
#define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
#define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
B
Behdad Esfahbod 已提交
200

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

204 205
#define _PASTE1(a,b) a##b
#define PASTE(a,b) _PASTE1(a,b)
B
Behdad Esfahbod 已提交
206

B
Behdad Esfahbod 已提交
207 208 209 210 211 212 213 214 215 216 217
/* 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 已提交
218 219 220
ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
ASSERT_STATIC (sizeof (hb_position_t) == 4);
ASSERT_STATIC (sizeof (hb_mask_t) == 4);
221
ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
B
Behdad Esfahbod 已提交
222

223 224 225

/* We like our types POD */

B
Minor  
Behdad Esfahbod 已提交
226 227 228
#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)
229 230

#ifdef __GNUC__
B
Behdad Esfahbod 已提交
231 232 233 234 235
# define _ASSERT_INSTANCE_POD1(_line, _instance) \
	HB_STMT_START { \
		typedef __typeof__(_instance) _type_##_line; \
		_ASSERT_TYPE_POD1 (_line, _type_##_line); \
	} HB_STMT_END
236
#else
B
Minor  
Behdad Esfahbod 已提交
237
# define _ASSERT_INSTANCE_POD1(_line, _instance)	typedef int _assertion_on_line_##_line##_not_tested
238
#endif
B
Minor  
Behdad Esfahbod 已提交
239 240
# define _ASSERT_INSTANCE_POD0(_line, _instance)	_ASSERT_INSTANCE_POD1 (_line, _instance)
# define ASSERT_INSTANCE_POD(_instance)			_ASSERT_INSTANCE_POD0 (__LINE__, _instance)
241 242 243

/* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \
B
Behdad Esfahbod 已提交
244
	HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
B
Minor  
Behdad Esfahbod 已提交
245 246 247
	{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line)	_ASSERT_POD1 (_line)
# define ASSERT_POD()		_ASSERT_POD0 (__LINE__)
248 249 250



B
Behdad Esfahbod 已提交
251 252
/* Misc */

B
Behdad Esfahbod 已提交
253 254 255 256
/* Void! */
struct _hb_void_t {};
typedef const _hb_void_t &hb_void_t;
#define HB_VOID (* (const _hb_void_t *) NULL)
257

B
Behdad Esfahbod 已提交
258
/* Return the number of 1 bits in mask. */
B
Behdad Esfahbod 已提交
259
static inline HB_CONST_FUNC unsigned int
B
Behdad Esfahbod 已提交
260 261 262
_hb_popcount32 (uint32_t mask)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
B
Behdad Esfahbod 已提交
263
  return __builtin_popcount (mask);
B
Behdad Esfahbod 已提交
264
#else
B
Behdad Esfahbod 已提交
265
  /* "HACKMEM 169" */
266
  uint32_t y;
B
Behdad Esfahbod 已提交
267 268 269
  y = (mask >> 1) &033333333333;
  y = mask - y - ((y >>1) & 033333333333);
  return (((y + (y >> 3)) & 030707070707) % 077);
B
Behdad Esfahbod 已提交
270 271 272
#endif
}

B
Behdad Esfahbod 已提交
273 274 275 276 277
/* 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 已提交
278
  return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
B
Behdad Esfahbod 已提交
279
#else
280
  unsigned int n_bits = 0;
B
Behdad Esfahbod 已提交
281 282 283 284 285 286 287
  while (number) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}
B
Behdad Esfahbod 已提交
288

B
Behdad Esfahbod 已提交
289 290 291 292 293 294 295
/* 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
296
  unsigned int n_bits = 0;
B
Behdad Esfahbod 已提交
297 298 299 300 301 302 303 304 305
  if (unlikely (!number)) return 0;
  while (!(number & 1)) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}

306 307 308 309 310 311 312
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 已提交
313 314 315 316
/* Type of bsearch() / qsort() compare function */
typedef int (*hb_compare_func_t) (const void *, const void *);


B
Behdad Esfahbod 已提交
317 318 319 320 321


/* arrays and maps */


B
Behdad Esfahbod 已提交
322
#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
323
template <typename Type, unsigned int StaticSize=16>
B
Behdad Esfahbod 已提交
324 325
struct hb_prealloced_array_t
{
B
Behdad Esfahbod 已提交
326 327 328 329 330
  unsigned int len;
  unsigned int allocated;
  Type *array;
  Type static_array[StaticSize];

331
  void init (void) { memset (this, 0, sizeof (*this)); }
332

333 334
  inline Type& operator [] (unsigned int i) { return array[i]; }
  inline const Type& operator [] (unsigned int i) const { return array[i]; }
B
Behdad Esfahbod 已提交
335 336 337 338 339 340 341 342 343

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

B
Behdad Esfahbod 已提交
345 346
    /* Need to reallocate */
    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
347 348
    Type *new_array = NULL;

B
Behdad Esfahbod 已提交
349 350
    if (array == static_array) {
      new_array = (Type *) calloc (new_allocated, sizeof (Type));
351
      if (new_array)
B
Behdad Esfahbod 已提交
352 353
        memcpy (new_array, array, len * sizeof (Type));
    } else {
354
      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
355
      if (likely (!overflows)) {
B
Behdad Esfahbod 已提交
356 357 358
	new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
      }
    }
359 360

    if (unlikely (!new_array))
B
Behdad Esfahbod 已提交
361
      return NULL;
362 363 364 365

    array = new_array;
    allocated = new_allocated;
    return &array[len++];
B
Behdad Esfahbod 已提交
366 367 368 369 370
  }

  inline void pop (void)
  {
    len--;
B
Minor  
Behdad Esfahbod 已提交
371 372 373 374 375 376 377 378 379 380
  }

  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 已提交
381
  }
382 383 384 385 386 387 388

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

389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
  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;
  }

B
Behdad Esfahbod 已提交
404
  inline void qsort (void)
405
  {
B
Behdad Esfahbod 已提交
406
    ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
407
  }
408

B
Behdad Esfahbod 已提交
409
  inline void qsort (unsigned int start, unsigned int end)
410
  {
B
Behdad Esfahbod 已提交
411
    ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
412 413
  }

414 415 416 417 418 419 420 421 422 423
  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 已提交
424 425 426 427 428 429 430 431

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

B
Behdad Esfahbod 已提交
434
template <typename Type>
435
struct hb_auto_array_t : hb_prealloced_array_t <Type>
B
Behdad Esfahbod 已提交
436
{
437 438
  hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
  ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
B
Behdad Esfahbod 已提交
439 440
};

441

B
Behdad Esfahbod 已提交
442
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
443 444
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
B
Behdad Esfahbod 已提交
445
{
B
Behdad Esfahbod 已提交
446
  hb_prealloced_array_t <item_t, 2> items;
B
Behdad Esfahbod 已提交
447

448 449
  inline void init (void) { items.init (); }

450
  template <typename T>
451
  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
B
Behdad Esfahbod 已提交
452
  {
453
    l.lock ();
454
    item_t *item = items.find (v);
455
    if (item) {
456 457 458 459 460 461 462 463 464 465
      if (replace) {
	item_t old = *item;
	*item = v;
	l.unlock ();
	old.finish ();
      }
      else {
        item = NULL;
	l.unlock ();
      }
466
    } else {
B
Behdad Esfahbod 已提交
467
      item = items.push ();
468 469 470 471
      if (likely (item))
	*item = v;
      l.unlock ();
    }
472
    return item;
B
Behdad Esfahbod 已提交
473 474
  }

475
  template <typename T>
476
  inline void remove (T v, lock_t &l)
B
Behdad Esfahbod 已提交
477
  {
478
    l.lock ();
479
    item_t *item = items.find (v);
480 481 482 483 484 485 486 487 488
    if (item) {
      item_t old = *item;
      *item = items[items.len - 1];
      items.pop ();
      l.unlock ();
      old.finish ();
    } else {
      l.unlock ();
    }
B
Behdad Esfahbod 已提交
489
  }
490

491
  template <typename T>
492
  inline bool find (T v, item_t *i, lock_t &l)
B
Behdad Esfahbod 已提交
493
  {
494 495 496 497 498 499
    l.lock ();
    item_t *item = items.find (v);
    if (item)
      *i = *item;
    l.unlock ();
    return !!item;
500 501
  }

502
  template <typename T>
503 504 505 506
  inline item_t *find_or_insert (T v, lock_t &l)
  {
    l.lock ();
    item_t *item = items.find (v);
507 508 509 510 511
    if (!item) {
      item = items.push ();
      if (likely (item))
        *item = v;
    }
512
    l.unlock ();
513 514 515
    return item;
  }

516 517
  inline void finish (lock_t &l)
  {
518 519 520 521 522
    if (!items.len) {
      /* No need for locking. */
      items.finish ();
      return;
    }
523 524 525 526 527 528 529 530
    l.lock ();
    while (items.len) {
      item_t old = items[items.len - 1];
	items.pop ();
	l.unlock ();
	old.finish ();
	l.lock ();
    }
B
Behdad Esfahbod 已提交
531
    items.finish ();
532 533 534 535 536
    l.unlock ();
  }

};

B
Behdad Esfahbod 已提交
537

538 539


B
Behdad Esfahbod 已提交
540 541
/* Big-endian handling */

542 543 544
static inline uint16_t hb_be_uint16 (const uint16_t v)
{
  const uint8_t *V = (const uint8_t *) &v;
B
Behdad Esfahbod 已提交
545 546 547 548 549 550 551 552 553 554 555
  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);
556
}
B
Behdad Esfahbod 已提交
557

B
Behdad Esfahbod 已提交
558 559 560 561 562 563 564 565
/* 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.
 */

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

570
#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 已提交
571
#define hb_be_uint32_get(v)	(uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
572
#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 已提交
573

B
Behdad Esfahbod 已提交
574
#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 已提交
575 576 577
#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 已提交
578

B
Behdad Esfahbod 已提交
579
/* ASCII tag/character handling */
B
Behdad Esfahbod 已提交
580

581
static inline bool ISALPHA (unsigned char c)
582
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
583
static inline bool ISALNUM (unsigned char c)
584
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
585 586
static inline bool ISSPACE (unsigned char c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
587 588 589 590
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 已提交
591

B
Behdad Esfahbod 已提交
592 593 594 595 596
#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 已提交
597

B
Behdad Esfahbod 已提交
598 599 600 601 602
/* C++ helpers */

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


B
Behdad Esfahbod 已提交
606 607
/* Debug */

608

B
Behdad Esfahbod 已提交
609 610 611 612
#ifndef HB_DEBUG
#define HB_DEBUG 0
#endif

613 614 615 616 617 618 619
static inline bool
_hb_debug (unsigned int level,
	   unsigned int max_level)
{
  return level < max_level;
}

620 621
#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
622

623
template <int max_level> static inline void
624
_hb_debug_msg_va (const char *what,
B
Behdad Esfahbod 已提交
625 626 627 628 629 630 631
		  const void *obj,
		  const char *func,
		  bool indented,
		  unsigned int level,
		  int level_dir,
		  const char *message,
		  va_list ap)
632
{
B
Behdad Esfahbod 已提交
633
  if (!_hb_debug (level, max_level))
B
Minor  
Behdad Esfahbod 已提交
634
    return;
B
Behdad Esfahbod 已提交
635 636 637 638

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

  if (obj)
B
/Minor/  
Behdad Esfahbod 已提交
639
    fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
B
Behdad Esfahbod 已提交
640 641 642
  else
    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");

643
  if (indented) {
644 645 646 647 648 649 650 651
/* 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;
652
    fprintf (stderr, "%2u %s" VRBAR "%s",
B
Behdad Esfahbod 已提交
653
	     level,
654 655
	     bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
656
  } else
657
    fprintf (stderr, "   " VRBAR LBAR);
B
Behdad Esfahbod 已提交
658

659 660
  if (func)
  {
B
Behdad Esfahbod 已提交
661 662
    unsigned int func_len = strlen (func);
#ifndef HB_DEBUG_VERBOSE
663 664 665
    /* Skip "typename" */
    if (0 == strncmp (func, "typename ", 9))
      func += 9;
666
    /* Skip return type */
667
    const char *space = strchr (func, ' ');
668
    if (space)
669
      func = space + 1;
670 671
    /* Skip parameter list */
    const char *paren = strchr (func, '(');
B
Behdad Esfahbod 已提交
672 673 674
    if (paren)
      func_len = paren - func;
#endif
675
    fprintf (stderr, "%.*s: ", func_len, func);
676
  }
B
Behdad Esfahbod 已提交
677 678 679 680 681

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

  fprintf (stderr, "\n");
682
}
B
Minor  
Behdad Esfahbod 已提交
683
template <> inline void
B
Behdad Esfahbod 已提交
684 685 686 687 688 689 690 691
_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) {}
692

693
template <int max_level> static inline void
694 695 696 697
_hb_debug_msg (const char *what,
	       const void *obj,
	       const char *func,
	       bool indented,
B
Behdad Esfahbod 已提交
698 699
	       unsigned int level,
	       int level_dir,
700
	       const char *message,
B
Behdad Esfahbod 已提交
701
	       ...) HB_PRINTF_FUNC(7, 8);
702
template <int max_level> static inline void
703 704 705 706
_hb_debug_msg (const char *what,
	       const void *obj,
	       const char *func,
	       bool indented,
B
Behdad Esfahbod 已提交
707 708
	       unsigned int level,
	       int level_dir,
709 710 711 712 713
	       const char *message,
	       ...)
{
  va_list ap;
  va_start (ap, message);
B
Minor  
Behdad Esfahbod 已提交
714
  _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
715 716
  va_end (ap);
}
B
Minor  
Behdad Esfahbod 已提交
717
template <> inline void
B
Behdad Esfahbod 已提交
718 719 720 721 722 723 724
_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 已提交
725
		  ...) HB_PRINTF_FUNC(7, 8);
B
Minor  
Behdad Esfahbod 已提交
726
template <> inline void
B
Behdad Esfahbod 已提交
727 728 729 730 731 732 733
_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 已提交
734
		  ...) {}
B
Behdad Esfahbod 已提交
735

736 737 738
#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__)
739 740


B
Minor  
Behdad Esfahbod 已提交
741 742 743 744 745 746 747 748 749 750 751 752 753
/*
 * Printer
 */

template <typename T>
struct hb_printer_t {};

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

template <>
754
struct hb_printer_t<hb_void_t> {
B
Behdad Esfahbod 已提交
755
  const char *print (hb_void_t) { return ""; }
B
Minor  
Behdad Esfahbod 已提交
756 757 758
};


759 760 761 762
/*
 * Trace
 */

763 764 765 766 767 768 769 770
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 <>
771
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
772 773 774
{}

template <int max_level, typename ret_t>
775 776
struct hb_auto_trace_t {
  explicit inline hb_auto_trace_t (unsigned int *plevel_,
B
Behdad Esfahbod 已提交
777 778
				   const char *what_,
				   const void *obj_,
779
				   const char *func,
780
				   const char *message,
B
Behdad Esfahbod 已提交
781
				   ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
782
  {
B
Behdad Esfahbod 已提交
783
    if (plevel) ++*plevel;
784 785 786

    va_list ap;
    va_start (ap, message);
787
    _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
788
    va_end (ap);
789
  }
790
  inline ~hb_auto_trace_t (void)
B
Behdad Esfahbod 已提交
791
  {
792 793
    _hb_warn_no_return<ret_t> (returned);
    if (!returned) {
794
      _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
795
    }
B
Behdad Esfahbod 已提交
796 797
    if (plevel) --*plevel;
  }
798

B
Behdad Esfahbod 已提交
799
  inline ret_t ret (ret_t v, unsigned int line = 0)
800 801 802 803 804 805
  {
    if (unlikely (returned)) {
      fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
      return v;
    }

806 807 808
    _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);
809 810 811 812 813 814
    if (plevel) --*plevel;
    plevel = NULL;
    returned = true;
    return v;
  }

815 816
  private:
  unsigned int *plevel;
B
Behdad Esfahbod 已提交
817 818
  const char *what;
  const void *obj;
B
Behdad Esfahbod 已提交
819
  bool returned;
820
};
821 822
template <typename ret_t> /* Optimize when tracing is disabled */
struct hb_auto_trace_t<0, ret_t> {
B
Behdad Esfahbod 已提交
823 824 825 826 827
  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,
828
				   ...) {}
829

B
Behdad Esfahbod 已提交
830
  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
831 832
};

833
#define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
834 835 836

/* Misc */

B
Behdad Esfahbod 已提交
837 838
template <typename T> class hb_assert_unsigned_t;
template <> class hb_assert_unsigned_t<unsigned char> {};
839
template <> class hb_assert_unsigned_t<unsigned short> {};
B
Behdad Esfahbod 已提交
840 841
template <> class hb_assert_unsigned_t<unsigned int> {};
template <> class hb_assert_unsigned_t<unsigned long> {};
B
Behdad Esfahbod 已提交
842

B
Behdad Esfahbod 已提交
843
template <typename T> static inline bool
B
Minor  
Behdad Esfahbod 已提交
844
hb_in_range (T u, T lo, T hi)
B
Minor  
Behdad Esfahbod 已提交
845
{
846 847 848 849 850 851 852
  /* The sizeof() is here to force template instantiation.
   * I'm sure there are better ways to do this but can't think of
   * one right now.  Declaring a variable won't work as HB_UNUSED
   * is unsable on some platforms and unused types are less likely
   * to generate a warning than unused variables. */
  ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);

853 854 855
  /* The casts below are important as if T is smaller than int,
   * the subtract results will become a signed int! */
  return (T)(u - lo) <= (T)(hi - lo);
B
Minor  
Behdad Esfahbod 已提交
856 857
}

B
Behdad Esfahbod 已提交
858 859 860 861 862 863
template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
{
  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
}

864
template <typename T> static inline bool
B
Behdad Esfahbod 已提交
865
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
866
{
B
Behdad Esfahbod 已提交
867
  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
868 869
}

B
Minor  
Behdad Esfahbod 已提交
870

B
Behdad Esfahbod 已提交
871 872 873 874
/* 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 已提交
875
#define FLAG(x) (1<<(x))
876
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
B
Minor  
Behdad Esfahbod 已提交
877

B
Minor  
Behdad Esfahbod 已提交
878

879 880
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 已提交
881 882 883 884 885 886 887 888 889
{
  if (unlikely (!len))
    return;

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

    for (unsigned int j = 0; j < k; j++)
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
      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 已提交
905 906 907 908 909 910 911

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

912 913 914 915 916
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 已提交
917

918 919 920 921 922
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];
923 924 925
  len = MIN (ARRAY_LENGTH (buf) - 1, len);
  strncpy (buf, s, len);
  buf[len] = '\0';
926 927 928 929 930 931 932 933 934

  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 已提交
935

B
Behdad Esfahbod 已提交
936

937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
/* 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;
}


966
#endif /* HB_PRIVATE_HH */