hb-private.hh 32.2 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

32 33
#define _GNU_SOURCE 1

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

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

45
#include <math.h>
B
Behdad Esfahbod 已提交
46
#include <stdlib.h>
47
#include <stddef.h>
B
Behdad Esfahbod 已提交
48 49
#include <string.h>
#include <assert.h>
50
#include <errno.h>
51
#include <stdio.h>
52
#include <stdarg.h>
B
Behdad Esfahbod 已提交
53

54
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
55 56
#include <intrin.h>
#endif
B
Behdad Esfahbod 已提交
57

B
Behdad Esfahbod 已提交
58 59 60
#define HB_PASTE1(a,b) a##b
#define HB_PASTE(a,b) HB_PASTE1(a,b)

61 62 63 64 65 66
/* Compile-time custom allocator support. */

#if defined(hb_malloc_impl) \
 && defined(hb_calloc_impl) \
 && defined(hb_realloc_impl) \
 && defined(hb_free_impl)
67 68 69 70
extern "C" void* hb_malloc_impl(size_t size);
extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
extern "C" void* hb_realloc_impl(void *ptr, size_t size);
extern "C" void  hb_free_impl(void *ptr);
71 72 73 74 75 76 77
#define malloc hb_malloc_impl
#define calloc hb_calloc_impl
#define realloc hb_realloc_impl
#define free hb_free_impl
#endif


B
Behdad Esfahbod 已提交
78
/* Compiler attributes */
B
Behdad Esfahbod 已提交
79 80


81 82
#if __cplusplus < 201103L

83 84 85
#ifndef nullptr
#define nullptr NULL
#endif
86 87 88 89

// Static assertions
#ifndef static_assert
#define static_assert(e, msg) \
B
Minor  
Behdad Esfahbod 已提交
90
	HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
91 92
#endif // static_assert

B
Behdad Esfahbod 已提交
93 94 95 96 97 98 99 100
#ifdef __GNUC__
#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
#define thread_local __thread
#endif
#else
#define thread_local
#endif

101 102
#endif // __cplusplus < 201103L

103 104 105
#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
#define likely(expr) (__builtin_expect (!!(expr), 1))
#define unlikely(expr) (__builtin_expect (!!(expr), 0))
B
Behdad Esfahbod 已提交
106 107 108
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
B
Behdad Esfahbod 已提交
109 110
#endif

111
#if !defined(__GNUC__) && !defined(__clang__)
B
Behdad Esfahbod 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
#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))
127 128
#elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */
#define HB_UNUSED __pragma(warning(suppress: 4100 4101))
B
Behdad Esfahbod 已提交
129 130 131 132 133
#else
#define HB_UNUSED
#endif

#ifndef HB_INTERNAL
B
Behdad Esfahbod 已提交
134
# if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC)
B
Behdad Esfahbod 已提交
135 136 137
#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
#  define HB_INTERNAL
138
#  define HB_NO_VISIBILITY 1
B
Behdad Esfahbod 已提交
139 140 141 142 143 144 145 146 147 148
# endif
#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 已提交
149

P
prrace 已提交
150
#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5140)
151 152 153 154
/* https://github.com/harfbuzz/harfbuzz/issues/630 */
#define __restrict
#endif

B
Behdad Esfahbod 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
/*
 * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
 * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
 * cases that fall through without a break or return statement. HB_FALLTHROUGH
 * is only needed on cases that have code:
 *
 * switch (foo) {
 *   case 1: // These cases have no code. No fallthrough annotations are needed.
 *   case 2:
 *   case 3:
 *     foo = 4; // This case has code, so a fallthrough annotation is needed:
 *     HB_FALLTHROUGH;
 *   default:
 *     return foo;
 * }
 */
#if defined(__clang__) && __cplusplus >= 201103L
   /* clang's fallthrough annotations are only available starting in C++11. */
#  define HB_FALLTHROUGH [[clang::fallthrough]]
174 175 176
#elif __GNUC__ >= 7
   /* GNU fallthrough attribute is available from GCC7 */
#  define HB_FALLTHROUGH __attribute__((fallthrough))
B
Behdad Esfahbod 已提交
177 178 179 180 181 182 183 184 185 186 187
#elif defined(_MSC_VER)
   /*
    * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
    * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
    */
#  include <sal.h>
#  define HB_FALLTHROUGH __fallthrough
#else
#  define HB_FALLTHROUGH /* FALLTHROUGH */
#endif

B
Behdad Esfahbod 已提交
188
#if defined(_WIN32) || defined(__CYGWIN__)
189 190 191 192 193 194 195 196 197
   /* 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
198 199 200 201 202 203
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN 1
#  endif
#  ifndef STRICT
#    define STRICT 1
#  endif
B
Minor  
Behdad Esfahbod 已提交
204

K
Konstantin Ritt 已提交
205 206
#  if defined(_WIN32_WCE)
     /* Some things not defined on Windows CE. */
K
Konstantin Ritt 已提交
207
#    define vsnprintf _vsnprintf
B
Behdad Esfahbod 已提交
208
#    define getenv(Name) nullptr
K
Konstantin Ritt 已提交
209 210
#    if _WIN32_WCE < 0x800
#      define setlocale(Category, Locale) "C"
211
static int errno = 0; /* Use something better? */
K
Konstantin Ritt 已提交
212
#    endif
K
Konstantin Ritt 已提交
213
#  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
B
Behdad Esfahbod 已提交
214
#    define getenv(Name) nullptr
K
Konstantin Ritt 已提交
215
#  endif
216
#  if defined(_MSC_VER) && _MSC_VER < 1900
K
Konstantin Ritt 已提交
217 218
#    define snprintf _snprintf
#  endif
219 220
#endif

221 222 223 224 225 226 227 228 229 230 231
#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:
232 233
 * https://msdn.microsoft.com/en-us/library/tze57ck3.aspx
 * https://msdn.microsoft.com/en-us/library/zk17ww08.aspx
234 235 236
 * mingw32 headers say atexit is safe to use in shared libraries.
 */
#    define HB_USE_ATEXIT 1
237 238 239
#  elif defined(__ANDROID__)
/* This is available since Android NKD r8 or r8b:
 * https://issuetracker.google.com/code/p/android/issues/detail?id=6455
240 241
 */
#    define HB_USE_ATEXIT 1
242 243 244 245 246 247
#  elif defined(__APPLE__)
/* For macOS and related platforms, the atexit man page indicates
 * that it will be invoked when the library is unloaded, not only
 * at application exit.
 */
#    define HB_USE_ATEXIT 1
248 249
#  endif
#endif
B
Behdad Esfahbod 已提交
250 251 252
#ifdef HB_NO_ATEXIT
#  undef HB_USE_ATEXIT
#endif
B
Minor  
Behdad Esfahbod 已提交
253

B
Behdad Esfahbod 已提交
254 255 256
/* Basics */

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

260
#undef MAX
261 262
template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
263

264 265 266
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }

267

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

274 275
#define HB_STMT_START do
#define HB_STMT_END   while (0)
B
Behdad Esfahbod 已提交
276

277 278
template <unsigned int cond> class hb_assert_constant_t;
template <> class hb_assert_constant_t<1> {};
279 280

#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
B
Behdad Esfahbod 已提交
281

B
Behdad Esfahbod 已提交
282 283
/* Lets assert int types.  Saves trouble down the road. */

284 285 286 287 288 289 290 291
static_assert ((sizeof (int8_t) == 1), "");
static_assert ((sizeof (uint8_t) == 1), "");
static_assert ((sizeof (int16_t) == 2), "");
static_assert ((sizeof (uint16_t) == 2), "");
static_assert ((sizeof (int32_t) == 4), "");
static_assert ((sizeof (uint32_t) == 4), "");
static_assert ((sizeof (int64_t) == 8), "");
static_assert ((sizeof (uint64_t) == 8), "");
B
Behdad Esfahbod 已提交
292

293 294 295 296
static_assert ((sizeof (hb_codepoint_t) == 4), "");
static_assert ((sizeof (hb_position_t) == 4), "");
static_assert ((sizeof (hb_mask_t) == 4), "");
static_assert ((sizeof (hb_var_int_t) == 4), "");
B
Behdad Esfahbod 已提交
297

298 299 300

/* We like our types POD */

B
Minor  
Behdad Esfahbod 已提交
301 302 303
#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)
304 305

#ifdef __GNUC__
B
Behdad Esfahbod 已提交
306 307 308 309 310
# define _ASSERT_INSTANCE_POD1(_line, _instance) \
	HB_STMT_START { \
		typedef __typeof__(_instance) _type_##_line; \
		_ASSERT_TYPE_POD1 (_line, _type_##_line); \
	} HB_STMT_END
311
#else
B
Minor  
Behdad Esfahbod 已提交
312
# define _ASSERT_INSTANCE_POD1(_line, _instance)	typedef int _assertion_on_line_##_line##_not_tested
313
#endif
B
Minor  
Behdad Esfahbod 已提交
314 315
# define _ASSERT_INSTANCE_POD0(_line, _instance)	_ASSERT_INSTANCE_POD1 (_line, _instance)
# define ASSERT_INSTANCE_POD(_instance)			_ASSERT_INSTANCE_POD0 (__LINE__, _instance)
316 317 318

/* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \
B
Behdad Esfahbod 已提交
319
	HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
B
Minor  
Behdad Esfahbod 已提交
320 321 322
	{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line)	_ASSERT_POD1 (_line)
# define ASSERT_POD()		_ASSERT_POD0 (__LINE__)
323 324 325



B
Behdad Esfahbod 已提交
326
/* Tiny functions */
B
Behdad Esfahbod 已提交
327

328 329 330 331
/*
 * Void!
 */
typedef const struct _hb_void_t *hb_void_t;
B
Behdad Esfahbod 已提交
332
#define HB_VOID ((const _hb_void_t *) nullptr)
333

334
/* Return the number of 1 bits in v. */
B
Behdad Esfahbod 已提交
335
template <typename T>
B
Behdad Esfahbod 已提交
336
static inline HB_CONST_FUNC unsigned int
337
_hb_popcount (T v)
B
Behdad Esfahbod 已提交
338
{
B
Behdad Esfahbod 已提交
339
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
340 341
  if (sizeof (T) <= sizeof (unsigned int))
    return __builtin_popcount (v);
B
Behdad Esfahbod 已提交
342

343 344
  if (sizeof (T) <= sizeof (unsigned long))
    return __builtin_popcountl (v);
B
Behdad Esfahbod 已提交
345

346 347
  if (sizeof (T) <= sizeof (unsigned long long))
    return __builtin_popcountll (v);
B
Behdad Esfahbod 已提交
348
#endif
B
Behdad Esfahbod 已提交
349 350 351 352 353

  if (sizeof (T) <= 4)
  {
    /* "HACKMEM 169" */
    uint32_t y;
354 355
    y = (v >> 1) &033333333333;
    y = v - y - ((y >>1) & 033333333333);
B
Behdad Esfahbod 已提交
356 357 358 359 360 361
    return (((y + (y >> 3)) & 030707070707) % 077);
  }

  if (sizeof (T) == 8)
  {
    unsigned int shift = 32;
362
    return _hb_popcount<uint32_t> ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift));
B
Behdad Esfahbod 已提交
363 364 365 366 367
  }

  if (sizeof (T) == 16)
  {
    unsigned int shift = 64;
368
    return _hb_popcount<uint64_t> ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift));
B
Behdad Esfahbod 已提交
369 370
  }

371
  assert (0);
B
Behdad Esfahbod 已提交
372
  return 0; /* Shut up stupid compiler. */
B
Behdad Esfahbod 已提交
373
}
B
Behdad Esfahbod 已提交
374

B
Behdad Esfahbod 已提交
375
/* Returns the number of bits needed to store number */
376
template <typename T>
B
Behdad Esfahbod 已提交
377
static inline HB_CONST_FUNC unsigned int
378
_hb_bit_storage (T v)
B
Behdad Esfahbod 已提交
379
{
380
  if (unlikely (!v)) return 0;
B
Behdad Esfahbod 已提交
381

B
Behdad Esfahbod 已提交
382
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
383 384 385 386
  if (sizeof (T) <= sizeof (unsigned int))
    return sizeof (unsigned int) * 8 - __builtin_clz (v);

  if (sizeof (T) <= sizeof (unsigned long))
387
    return sizeof (unsigned long) * 8 - __builtin_clzl (v);
388 389

  if (sizeof (T) <= sizeof (unsigned long long))
390
    return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
B
Behdad Esfahbod 已提交
391 392
#endif

393
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
394 395 396 397 398 399 400 401
  if (sizeof (T) <= sizeof (unsigned int))
  {
    unsigned long where;
    _BitScanReverse (&where, v);
    return 1 + where;
  }
# if _WIN64
  if (sizeof (T) <= 8)
B
Behdad Esfahbod 已提交
402 403
  {
    unsigned long where;
404
    _BitScanReverse64 (&where, v);
B
Behdad Esfahbod 已提交
405 406
    return 1 + where;
  }
407
# endif
B
Behdad Esfahbod 已提交
408 409
#endif

410 411 412 413 414
  if (sizeof (T) <= 4)
  {
    /* "bithacks" */
    const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
    const unsigned int S[] = {1, 2, 4, 8, 16};
415
    unsigned int r = 0;
416 417 418 419 420 421
    for (int i = 4; i >= 0; i--)
      if (v & b[i])
      {
	v >>= S[i];
	r |= S[i];
      }
422
    return r + 1;
423 424 425 426
  }
  if (sizeof (T) <= 8)
  {
    /* "bithacks" */
427
    const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
428
    const unsigned int S[] = {1, 2, 4, 8, 16, 32};
429
    unsigned int r = 0;
430 431 432 433 434 435
    for (int i = 5; i >= 0; i--)
      if (v & b[i])
      {
	v >>= S[i];
	r |= S[i];
      }
436
    return r + 1;
437 438 439 440
  }
  if (sizeof (T) == 16)
  {
    unsigned int shift = 64;
B
Behdad Esfahbod 已提交
441
    return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
442
			  _hb_bit_storage<uint64_t> ((uint64_t) v);
B
Behdad Esfahbod 已提交
443
  }
444 445

  assert (0);
B
Behdad Esfahbod 已提交
446
  return 0; /* Shut up stupid compiler. */
B
Behdad Esfahbod 已提交
447
}
B
Behdad Esfahbod 已提交
448

449 450
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
B
Behdad Esfahbod 已提交
451
static inline HB_CONST_FUNC unsigned int
452
_hb_ctz (T v)
B
Behdad Esfahbod 已提交
453
{
454
  if (unlikely (!v)) return 0;
B
Behdad Esfahbod 已提交
455

B
Behdad Esfahbod 已提交
456
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
457 458 459 460 461 462 463 464
  if (sizeof (T) <= sizeof (unsigned int))
    return __builtin_ctz (v);

  if (sizeof (T) <= sizeof (unsigned long))
    return __builtin_ctzl (v);

  if (sizeof (T) <= sizeof (unsigned long long))
    return __builtin_ctzll (v);
B
Behdad Esfahbod 已提交
465 466
#endif

467
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
468 469 470 471
  if (sizeof (T) <= sizeof (unsigned int))
  {
    unsigned long where;
    _BitScanForward (&where, v);
B
Behdad Esfahbod 已提交
472
    return where;
473 474 475
  }
# if _WIN64
  if (sizeof (T) <= 8)
B
Behdad Esfahbod 已提交
476 477
  {
    unsigned long where;
478
    _BitScanForward64 (&where, v);
B
Behdad Esfahbod 已提交
479
    return where;
B
Behdad Esfahbod 已提交
480
  }
481
# endif
B
Behdad Esfahbod 已提交
482 483
#endif

484 485 486 487
  if (sizeof (T) <= 4)
  {
    /* "bithacks" */
    unsigned int c = 32;
B
Behdad Esfahbod 已提交
488
    v &= - (int32_t) v;
489 490 491 492 493 494 495
    if (v) c--;
    if (v & 0x0000FFFF) c -= 16;
    if (v & 0x00FF00FF) c -= 8;
    if (v & 0x0F0F0F0F) c -= 4;
    if (v & 0x33333333) c -= 2;
    if (v & 0x55555555) c -= 1;
    return c;
B
Behdad Esfahbod 已提交
496
  }
497 498 499 500
  if (sizeof (T) <= 8)
  {
    /* "bithacks" */
    unsigned int c = 64;
B
Behdad Esfahbod 已提交
501
    v &= - (int64_t) (v);
502
    if (v) c--;
B
Behdad Esfahbod 已提交
503 504 505 506 507 508
    if (v & 0x00000000FFFFFFFFULL) c -= 32;
    if (v & 0x0000FFFF0000FFFFULL) c -= 16;
    if (v & 0x00FF00FF00FF00FFULL) c -= 8;
    if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
    if (v & 0x3333333333333333ULL) c -= 2;
    if (v & 0x5555555555555555ULL) c -= 1;
509 510 511 512 513 514 515 516 517 518
    return c;
  }
  if (sizeof (T) == 16)
  {
    unsigned int shift = 64;
    return (uint64_t) v ? _hb_bit_storage<uint64_t> ((uint64_t) v) :
			  _hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift;
  }

  assert (0);
B
Behdad Esfahbod 已提交
519
  return 0; /* Shut up stupid compiler. */
B
Behdad Esfahbod 已提交
520 521
}

522 523 524 525 526 527
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 已提交
528 529 530
static inline unsigned int
_hb_ceil_to_4 (unsigned int v)
{
B
Behdad Esfahbod 已提交
531
  return ((v - 1) | 3) + 1;
B
Behdad Esfahbod 已提交
532 533
}

534

B
Behdad Esfahbod 已提交
535

B
Behdad Esfahbod 已提交
536 537 538 539 540 541
/*
 *
 * Utility types
 *
 */

542
#define HB_DISALLOW_COPY_AND_ASSIGN(TypeName) \
543 544
  TypeName(const TypeName&); \
  void operator=(const TypeName&)
545

B
Behdad Esfahbod 已提交
546
/*
B
Behdad Esfahbod 已提交
547
 * Static pools
B
Behdad Esfahbod 已提交
548 549 550 551
 */

/* Global nul-content Null pool.  Enlarge as necessary. */

B
Behdad Esfahbod 已提交
552
#define HB_NULL_POOL_SIZE 264
B
Behdad Esfahbod 已提交
553 554 555 556 557 558 559
static_assert (HB_NULL_POOL_SIZE % sizeof (void *) == 0, "Align HB_NULL_POOL_SIZE.");

#ifdef HB_NO_VISIBILITY
static
#else
extern HB_INTERNAL
#endif
B
Behdad Esfahbod 已提交
560
void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)]
B
Behdad Esfahbod 已提交
561 562 563 564 565 566
#ifdef HB_NO_VISIBILITY
= {}
#endif
;
/* Generic nul-content Null objects. */
template <typename Type>
B
Behdad Esfahbod 已提交
567
static inline Type const & Null (void) {
B
Behdad Esfahbod 已提交
568
  static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
B
Behdad Esfahbod 已提交
569
  return *reinterpret_cast<Type const *> (_hb_NullPool);
B
Behdad Esfahbod 已提交
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
}
#define Null(Type) Null<Type>()

/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
#define DEFINE_NULL_DATA(Namespace, Type, data) \
} /* Close namespace. */ \
static const char _Null##Type[sizeof (Namespace::Type) + 1] = data; /* +1 is for nul-termination in data */ \
template <> \
/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
  return *reinterpret_cast<const Namespace::Type *> (_Null##Type); \
} \
namespace Namespace { \
/* The following line really exists such that we end in a place needing semicolon */ \
static_assert (Namespace::Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small.  Enlarge.")


B
Behdad Esfahbod 已提交
586 587
/* Global writable pool.  Enlarge as necessary. */

B
Behdad Esfahbod 已提交
588 589 590
/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool
 * for correct operation. It only exist to catch and divert program logic bugs instead of
 * causing bad memory access. So, races there are not actually introducing incorrectness
B
Behdad Esfahbod 已提交
591
 * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
B
Behdad Esfahbod 已提交
592 593 594 595 596
#ifdef HB_NO_VISIBILITY
static
#else
extern HB_INTERNAL
#endif
B
Behdad Esfahbod 已提交
597
/*thread_local*/ void * _hb_CrapPool[HB_NULL_POOL_SIZE / sizeof (void *)]
B
Behdad Esfahbod 已提交
598 599 600 601 602 603 604 605 606 607 608 609 610 611
#ifdef HB_NO_VISIBILITY
= {}
#endif
;
/* CRAP pool: Common Region for Access Protection. */
template <typename Type>
static inline Type& Crap (void) {
  static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
  Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
  *obj = Null(Type);
  return *obj;
}
#define Crap(Type) Crap<Type>()

B
Behdad Esfahbod 已提交
612 613 614 615 616 617 618 619 620 621 622
template <typename Type>
struct CrapOrNull {
  static inline Type & get (void) { return Crap(Type); }
};
template <typename Type>
struct CrapOrNull<const Type> {
  static inline Type const & get (void) { return Null(Type); }
};
#define CrapOrNull(Type) CrapOrNull<Type>::get ()


B
Behdad Esfahbod 已提交
623

B
Behdad Esfahbod 已提交
624 625 626
/* arrays and maps */


B
Behdad Esfahbod 已提交
627
#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
B
Behdad Esfahbod 已提交
628
template <typename Type, unsigned int StaticSize=8>
629
struct hb_vector_t
B
Behdad Esfahbod 已提交
630
{
B
Behdad Esfahbod 已提交
631 632
  unsigned int len;
  unsigned int allocated;
B
Behdad Esfahbod 已提交
633
  bool successful;
634
  Type *arrayZ;
B
Behdad Esfahbod 已提交
635 636
  Type static_array[StaticSize];

637 638 639 640
  void init (void)
  {
    len = 0;
    allocated = ARRAY_LENGTH (static_array);
B
Behdad Esfahbod 已提交
641
    successful = true;
642
    arrayZ = static_array;
643
  }
644

B
Behdad Esfahbod 已提交
645 646 647 648 649 650 651 652 653
  inline Type& operator [] (unsigned int i)
  {
    if (unlikely (i >= len))
      return Crap (Type);
    return arrayZ[i];
  }
  inline const Type& operator [] (unsigned int i) const
  {
    if (unlikely (i >= len))
B
Behdad Esfahbod 已提交
654
      return Null(Type);
B
Behdad Esfahbod 已提交
655 656
    return arrayZ[i];
  }
B
Behdad Esfahbod 已提交
657 658

  inline Type *push (void)
B
Behdad Esfahbod 已提交
659 660
  {
    if (unlikely (!resize (len + 1)))
661
      return &Crap(Type);
662
    return &arrayZ[len - 1];
B
Behdad Esfahbod 已提交
663
  }
664 665
  inline Type *push (const Type& v)
  {
666 667 668
    Type *p = push ();
    *p = v;
    return p;
669
  }
B
Behdad Esfahbod 已提交
670

B
Minor  
Behdad Esfahbod 已提交
671
  /* Allocate for size but don't adjust len. */
672
  inline bool alloc (unsigned int size)
B
Behdad Esfahbod 已提交
673
  {
B
Behdad Esfahbod 已提交
674 675 676
    if (unlikely (!successful))
      return false;

B
Minor  
Behdad Esfahbod 已提交
677
    if (likely (size <= allocated))
678
      return true;
B
Minor  
Behdad Esfahbod 已提交
679 680

    /* Reallocate */
681 682 683 684 685 686 687

    unsigned int new_allocated = allocated;
    while (size >= new_allocated)
      new_allocated += (new_allocated >> 1) + 8;

    Type *new_array = nullptr;

B
Behdad Esfahbod 已提交
688 689
    if (arrayZ == static_array)
    {
690 691
      new_array = (Type *) calloc (new_allocated, sizeof (Type));
      if (new_array)
692
        memcpy (new_array, arrayZ, len * sizeof (Type));
B
Behdad Esfahbod 已提交
693 694 695
    }
    else
    {
696
      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
B
Behdad Esfahbod 已提交
697
      if (likely (!overflows))
698
        new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
699
    }
700

701
    if (unlikely (!new_array))
B
Behdad Esfahbod 已提交
702 703
    {
      successful = false;
704
      return false;
B
Behdad Esfahbod 已提交
705
    }
B
Behdad Esfahbod 已提交
706

707
    arrayZ = new_array;
R
Rod Sheeter 已提交
708
    allocated = new_allocated;
B
Minor  
Behdad Esfahbod 已提交
709

R
Rod Sheeter 已提交
710
    return true;
711
  }
B
Behdad Esfahbod 已提交
712

713
  inline bool resize (int size_)
714
  {
715
    unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
B
Minor  
Behdad Esfahbod 已提交
716
    if (!alloc (size))
717
      return false;
718

B
Behdad Esfahbod 已提交
719 720
    len = size;
    return true;
B
Behdad Esfahbod 已提交
721 722 723 724
  }

  inline void pop (void)
  {
725
    if (!len) return;
B
Behdad Esfahbod 已提交
726
    len--;
B
Minor  
Behdad Esfahbod 已提交
727 728 729 730 731 732
  }

  inline void remove (unsigned int i)
  {
     if (unlikely (i >= len))
       return;
733 734
     memmove (static_cast<void *> (&arrayZ[i]),
	      static_cast<void *> (&arrayZ[i + 1]),
B
Minor  
Behdad Esfahbod 已提交
735 736
	      (len - i - 1) * sizeof (Type));
     len--;
B
Behdad Esfahbod 已提交
737
  }
738

739
  inline void shrink (int size_)
740
  {
741 742 743
    unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
     if (size < len)
       len = size;
744 745
  }

746 747 748
  template <typename T>
  inline Type *find (T v) {
    for (unsigned int i = 0; i < len; i++)
749 750
      if (arrayZ[i] == v)
	return &arrayZ[i];
B
Behdad Esfahbod 已提交
751
    return nullptr;
752 753 754 755
  }
  template <typename T>
  inline const Type *find (T v) const {
    for (unsigned int i = 0; i < len; i++)
756 757
      if (arrayZ[i] == v)
	return &arrayZ[i];
B
Behdad Esfahbod 已提交
758
    return nullptr;
759 760
  }

761 762
  inline void qsort (int (*cmp)(const void*, const void*))
  {
763
    ::qsort (arrayZ, len, sizeof (Type), cmp);
764 765
  }

B
Behdad Esfahbod 已提交
766
  inline void qsort (void)
767
  {
768
    ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
769
  }
770

B
Behdad Esfahbod 已提交
771
  inline void qsort (unsigned int start, unsigned int end)
772
  {
773
    ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
774 775
  }

B
Behdad Esfahbod 已提交
776
  template <typename T>
B
Behdad Esfahbod 已提交
777
  inline Type *lsearch (const T &x)
B
Behdad Esfahbod 已提交
778 779
  {
    for (unsigned int i = 0; i < len; i++)
780 781
      if (0 == this->arrayZ[i].cmp (&x))
	return &arrayZ[i];
B
Behdad Esfahbod 已提交
782 783 784
    return nullptr;
  }

785
  template <typename T>
B
Behdad Esfahbod 已提交
786
  inline Type *bsearch (const T &x)
787
  {
788
    unsigned int i;
789
    return bfind (x, &i) ? &arrayZ[i] : nullptr;
790 791
  }
  template <typename T>
B
Behdad Esfahbod 已提交
792
  inline const Type *bsearch (const T &x) const
793 794
  {
    unsigned int i;
795
    return bfind (x, &i) ? &arrayZ[i] : nullptr;
796 797
  }
  template <typename T>
B
Behdad Esfahbod 已提交
798
  inline bool bfind (const T &x, unsigned int *i) const
799
  {
B
Behdad Esfahbod 已提交
800 801 802 803
    int min = 0, max = (int) this->len - 1;
    while (min <= max)
    {
      int mid = (min + max) / 2;
804
      int c = this->arrayZ[mid].cmp (&x);
B
Behdad Esfahbod 已提交
805 806 807 808 809
      if (c < 0)
        max = mid - 1;
      else if (c > 0)
        min = mid + 1;
      else
810 811 812 813
      {
        *i = mid;
	return true;
      }
B
Behdad Esfahbod 已提交
814
    }
815
    if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
816 817 818
      max++;
    *i = max;
    return false;
819
  }
B
Behdad Esfahbod 已提交
820

B
Behdad Esfahbod 已提交
821
  inline void fini (void)
B
Behdad Esfahbod 已提交
822
  {
823 824 825
    if (arrayZ != static_array)
      free (arrayZ);
    arrayZ = nullptr;
B
Behdad Esfahbod 已提交
826 827
    allocated = len = 0;
  }
B
Behdad Esfahbod 已提交
828 829
};

B
Behdad Esfahbod 已提交
830
template <typename Type>
B
Behdad Esfahbod 已提交
831
struct hb_auto_t : Type
B
Behdad Esfahbod 已提交
832
{
B
Behdad Esfahbod 已提交
833 834 835 836 837
  hb_auto_t (void) { Type::init (); }
  ~hb_auto_t (void) { Type::fini (); }
  private: /* Hide */
  void init (void) {}
  void fini (void) {}
B
Behdad Esfahbod 已提交
838
};
B
Behdad Esfahbod 已提交
839
template <typename Type>
840
struct hb_auto_array_t : hb_auto_t <hb_vector_t <Type> > {};
B
Behdad Esfahbod 已提交
841

842

B
Behdad Esfahbod 已提交
843
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
844 845
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
B
Behdad Esfahbod 已提交
846
{
847
  hb_vector_t <item_t, 1> items;
B
Behdad Esfahbod 已提交
848

849 850
  inline void init (void) { items.init (); }

851
  template <typename T>
852
  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
B
Behdad Esfahbod 已提交
853
  {
854
    l.lock ();
855
    item_t *item = items.find (v);
856
    if (item) {
857 858 859 860
      if (replace) {
	item_t old = *item;
	*item = v;
	l.unlock ();
B
Behdad Esfahbod 已提交
861
	old.fini ();
862 863
      }
      else {
B
Behdad Esfahbod 已提交
864
        item = nullptr;
865 866
	l.unlock ();
      }
867
    } else {
868
      item = items.push (v);
869 870
      l.unlock ();
    }
871
    return item;
B
Behdad Esfahbod 已提交
872 873
  }

874
  template <typename T>
875
  inline void remove (T v, lock_t &l)
B
Behdad Esfahbod 已提交
876
  {
877
    l.lock ();
878
    item_t *item = items.find (v);
879 880 881 882 883
    if (item) {
      item_t old = *item;
      *item = items[items.len - 1];
      items.pop ();
      l.unlock ();
B
Behdad Esfahbod 已提交
884
      old.fini ();
885 886 887
    } else {
      l.unlock ();
    }
B
Behdad Esfahbod 已提交
888
  }
889

890
  template <typename T>
891
  inline bool find (T v, item_t *i, lock_t &l)
B
Behdad Esfahbod 已提交
892
  {
893 894 895 896 897 898
    l.lock ();
    item_t *item = items.find (v);
    if (item)
      *i = *item;
    l.unlock ();
    return !!item;
899 900
  }

901
  template <typename T>
902 903 904 905
  inline item_t *find_or_insert (T v, lock_t &l)
  {
    l.lock ();
    item_t *item = items.find (v);
906
    if (!item) {
907
      item = items.push (v);
908
    }
909
    l.unlock ();
910 911 912
    return item;
  }

B
Behdad Esfahbod 已提交
913
  inline void fini (lock_t &l)
914
  {
915 916
    if (!items.len) {
      /* No need for locking. */
B
Behdad Esfahbod 已提交
917
      items.fini ();
918 919
      return;
    }
920 921 922 923 924
    l.lock ();
    while (items.len) {
      item_t old = items[items.len - 1];
	items.pop ();
	l.unlock ();
B
Behdad Esfahbod 已提交
925
	old.fini ();
926 927
	l.lock ();
    }
B
Behdad Esfahbod 已提交
928
    items.fini ();
929 930 931 932 933
    l.unlock ();
  }

};

B
Behdad Esfahbod 已提交
934

B
Behdad Esfahbod 已提交
935
/* ASCII tag/character handling */
B
Behdad Esfahbod 已提交
936

937
static inline bool ISALPHA (unsigned char c)
938
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
939
static inline bool ISALNUM (unsigned char c)
940
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
941 942
static inline bool ISSPACE (unsigned char c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
943 944 945 946
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 已提交
947 948


B
Behdad Esfahbod 已提交
949 950 951 952 953 954
/* HB_NDEBUG disables some sanity checks that are very safe to disable and
 * should be disabled in production systems.  If NDEBUG is defined, enable
 * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
 * light-weight) to be enabled, then HB_DEBUG can be defined to disable
 * the costlier checks. */
#ifdef NDEBUG
B
Minor  
Behdad Esfahbod 已提交
955
#define HB_NDEBUG 1
B
Behdad Esfahbod 已提交
956 957
#endif

958 959 960

/* Misc */

B
Behdad Esfahbod 已提交
961 962
template <typename T> class hb_assert_unsigned_t;
template <> class hb_assert_unsigned_t<unsigned char> {};
963
template <> class hb_assert_unsigned_t<unsigned short> {};
B
Behdad Esfahbod 已提交
964 965
template <> class hb_assert_unsigned_t<unsigned int> {};
template <> class hb_assert_unsigned_t<unsigned long> {};
B
Behdad Esfahbod 已提交
966

B
Behdad Esfahbod 已提交
967
template <typename T> static inline bool
B
Minor  
Behdad Esfahbod 已提交
968
hb_in_range (T u, T lo, T hi)
B
Minor  
Behdad Esfahbod 已提交
969
{
970 971 972
  /* 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
B
Typo  
Behdad Esfahbod 已提交
973
   * is unusable on some platforms and unused types are less likely
974
   * to generate a warning than unused variables. */
975
  static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
976

977 978 979
  /* 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 已提交
980 981
}

B
Behdad Esfahbod 已提交
982 983 984 985 986 987
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);
}

988
template <typename T> static inline bool
B
Behdad Esfahbod 已提交
989
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
990
{
B
Behdad Esfahbod 已提交
991
  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
992 993
}

B
Minor  
Behdad Esfahbod 已提交
994

B
Behdad Esfahbod 已提交
995
/* Enable bitwise ops on enums marked as flags_t */
996 997
/* To my surprise, looks like the function resolver is happy to silently cast
 * one enum to another...  So this doesn't provide the type-checking that I
B
Behdad Esfahbod 已提交
998 999
 * originally had in mind... :(.
 *
1000
 * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
B
Behdad Esfahbod 已提交
1001 1002 1003 1004
 */
#ifdef _MSC_VER
# pragma warning(disable:4200)
# pragma warning(disable:4800)
C
Chun-wei Fan 已提交
1005
#endif
B
Behdad Esfahbod 已提交
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
#define HB_MARK_AS_FLAG_T(T) \
	extern "C++" { \
	  static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
	  static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
	  static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
	  static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
	  static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
	  static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
	  static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
	}
B
Behdad Esfahbod 已提交
1016 1017


B
Behdad Esfahbod 已提交
1018 1019
/* Useful for set-operations on small enums.
 * For example, for testing "x ∈ {x1, x2, x3}" use:
B
Behdad Esfahbod 已提交
1020
 * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
B
Behdad Esfahbod 已提交
1021
 */
B
Behdad Esfahbod 已提交
1022 1023
#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned int)(x) < 32) + (1U << (unsigned int)(x)))
#define FLAG_UNSAFE(x) ((unsigned int)(x) < 32 ? (1U << (unsigned int)(x)) : 0)
1024
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
B
Minor  
Behdad Esfahbod 已提交
1025

B
Minor  
Behdad Esfahbod 已提交
1026

B
Behdad Esfahbod 已提交
1027
template <typename T, typename T2> static inline void
1028
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
B
Behdad Esfahbod 已提交
1029
{
1030 1031 1032 1033 1034 1035 1036 1037 1038
  for (unsigned int i = 1; i < len; i++)
  {
    unsigned int j = i;
    while (j && compar (&array[j - 1], &array[i]) > 0)
      j--;
    if (i == j)
      continue;
    /* Move item i to occupy place for item j, shift what's in between. */
    {
B
Minor  
Behdad Esfahbod 已提交
1039
      T t = array[i];
1040 1041 1042 1043 1044
      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
      array[j] = t;
    }
    if (array2)
    {
B
Minor  
Behdad Esfahbod 已提交
1045
      T2 t = array2[i];
1046 1047 1048 1049
      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
      array2[j] = t;
    }
  }
B
Behdad Esfahbod 已提交
1050 1051
}

B
Behdad Esfahbod 已提交
1052
template <typename T> static inline void
1053
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
1054
{
B
Behdad Esfahbod 已提交
1055
  hb_stable_sort (array, len, compar, (int *) nullptr);
1056
}
B
Behdad Esfahbod 已提交
1057

1058 1059 1060 1061 1062
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];
1063 1064 1065
  len = MIN (ARRAY_LENGTH (buf) - 1, len);
  strncpy (buf, s, len);
  buf[len] = '\0';
1066 1067 1068 1069 1070 1071 1072 1073 1074

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

B
Behdad Esfahbod 已提交
1076

1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
/* Vectorization */

struct HbOpOr
{
  static const bool passthru_left = true;
  static const bool passthru_right = true;
  template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
};
struct HbOpAnd
{
  static const bool passthru_left = false;
  static const bool passthru_right = false;
  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
};
struct HbOpMinus
{
  static const bool passthru_left = true;
  static const bool passthru_right = false;
  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
};
struct HbOpXor
{
  static const bool passthru_left = true;
  static const bool passthru_right = true;
  template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
};

1104 1105 1106 1107 1108

/* Compiler-assisted vectorization. */

/* The `vector_size' attribute was introduced in gcc 3.1. */
#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
1109 1110 1111
#define HB_VECTOR_SIZE 128
#elif !defined(HB_VECTOR_SIZE)
#define HB_VECTOR_SIZE 0
1112 1113
#endif

1114 1115 1116 1117
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
template <typename elt_t, unsigned int byte_size>
struct hb_vector_size_t
{
1118 1119
  elt_t& operator [] (unsigned int i) { return u.v[i]; }
  const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
1120 1121 1122 1123 1124

  template <class Op>
  inline hb_vector_size_t process (const hb_vector_size_t &o) const
  {
    hb_vector_size_t r;
1125
#if HB_VECTOR_SIZE
1126 1127 1128
    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
	Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
1129
    else
1130 1131 1132
#endif
      for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
	Op::process (r.u.v[i], u.v[i], o.u.v[i]);
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
    return r;
  }
  inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
  { return process<HbOpOr> (o); }
  inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
  { return process<HbOpAnd> (o); }
  inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
  { return process<HbOpXor> (o); }
  inline hb_vector_size_t operator ~ () const
  {
    hb_vector_size_t r;
1144 1145 1146 1147 1148 1149 1150 1151
#if HB_VECTOR_SIZE && 0
    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
	r.u.vec[i] = ~u.vec[i];
    else
#endif
    for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
      r.u.v[i] = ~u.v[i];
1152 1153 1154 1155
    return r;
  }

  private:
B
Behdad Esfahbod 已提交
1156
  static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
1157 1158
  union {
    elt_t v[byte_size / sizeof (elt_t)];
1159
#if HB_VECTOR_SIZE
B
Behdad Esfahbod 已提交
1160
    typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
1161 1162 1163
    vec_t vec[byte_size / sizeof (vec_t)];
#endif
  } u;
1164 1165 1166
};


1167 1168 1169 1170
/* Global runtime options. */

struct hb_options_t
{
B
Behdad Esfahbod 已提交
1171 1172
  unsigned int initialized : 1;
  unsigned int uniscribe_bug_compatible : 1;
1173 1174 1175
};

union hb_options_union_t {
B
Behdad Esfahbod 已提交
1176
  unsigned int i;
1177 1178
  hb_options_t opts;
};
1179
static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194

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;
}

S
Steven R. Loomis 已提交
1195 1196
/* Size signifying variable-sized array */
#define VAR 1
1197

B
Behdad Esfahbod 已提交
1198 1199 1200

/* String type. */

1201
struct hb_bytes_t
B
Behdad Esfahbod 已提交
1202
{
1203 1204
  inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
  inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
B
Behdad Esfahbod 已提交
1205

1206
  inline int cmp (const hb_bytes_t &a) const
B
Behdad Esfahbod 已提交
1207
  {
1208 1209
    if (len != a.len)
      return (int) a.len - (int) len;
B
Behdad Esfahbod 已提交
1210

1211
    return memcmp (a.bytes, bytes, len);
B
Behdad Esfahbod 已提交
1212 1213 1214
  }
  static inline int cmp (const void *pa, const void *pb)
  {
1215 1216
    hb_bytes_t *a = (hb_bytes_t *) pa;
    hb_bytes_t *b = (hb_bytes_t *) pb;
1217
    return b->cmp (*a);
B
Behdad Esfahbod 已提交
1218 1219 1220 1221 1222 1223 1224
  }

  const char *bytes;
  unsigned int len;
};


1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
/* fallback for round() */
#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
static inline double
round (double x)
{
  if (x >= 0)
    return floor (x + 0.5);
  else
    return ceil (x - 0.5);
}
#endif


1238
#endif /* HB_PRIVATE_HH */