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

B
Behdad Esfahbod 已提交
54
#if defined(_MSC_VER) || 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 93 94
#endif // static_assert

#endif // __cplusplus < 201103L

95 96 97
#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
#define likely(expr) (__builtin_expect (!!(expr), 1))
#define unlikely(expr) (__builtin_expect (!!(expr), 0))
B
Behdad Esfahbod 已提交
98 99 100
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
B
Behdad Esfahbod 已提交
101 102
#endif

103
#if !defined(__GNUC__) && !defined(__clang__)
B
Behdad Esfahbod 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#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))
119 120
#elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */
#define HB_UNUSED __pragma(warning(suppress: 4100 4101))
B
Behdad Esfahbod 已提交
121 122 123 124 125
#else
#define HB_UNUSED
#endif

#ifndef HB_INTERNAL
B
Behdad Esfahbod 已提交
126
# if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC)
B
Behdad Esfahbod 已提交
127 128 129
#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
#  define HB_INTERNAL
130
#  define HB_NO_VISIBILITY 1
B
Behdad Esfahbod 已提交
131 132 133 134 135 136 137 138 139 140
# 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 已提交
141

142 143 144 145 146
#ifdef __SUNPRO_CC
/* https://github.com/harfbuzz/harfbuzz/issues/630 */
#define __restrict
#endif

B
Behdad Esfahbod 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
/*
 * 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]]
166 167 168
#elif __GNUC__ >= 7
   /* GNU fallthrough attribute is available from GCC7 */
#  define HB_FALLTHROUGH __attribute__((fallthrough))
B
Behdad Esfahbod 已提交
169 170 171 172 173 174 175 176 177 178 179
#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 已提交
180
#if defined(_WIN32) || defined(__CYGWIN__)
181 182 183 184 185 186 187 188 189
   /* 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
190 191 192 193 194 195
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN 1
#  endif
#  ifndef STRICT
#    define STRICT 1
#  endif
B
Minor  
Behdad Esfahbod 已提交
196

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

213 214 215 216 217 218 219 220 221 222 223
#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:
224 225
 * https://msdn.microsoft.com/en-us/library/tze57ck3.aspx
 * https://msdn.microsoft.com/en-us/library/zk17ww08.aspx
226 227 228 229 230 231 232 233 234 235
 * 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
236 237 238 239 240 241
#  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
242 243
#  endif
#endif
B
Behdad Esfahbod 已提交
244 245 246
#ifdef HB_NO_ATEXIT
#  undef HB_USE_ATEXIT
#endif
B
Minor  
Behdad Esfahbod 已提交
247

B
Behdad Esfahbod 已提交
248 249 250
/* Basics */

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

254
#undef MAX
255 256
template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
257

258 259 260
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }

261

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

268 269
#define HB_STMT_START do
#define HB_STMT_END   while (0)
B
Behdad Esfahbod 已提交
270

271 272
template <unsigned int cond> class hb_assert_constant_t;
template <> class hb_assert_constant_t<1> {};
273 274

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

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

278 279 280 281 282 283 284 285
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 已提交
286

287 288 289 290
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 已提交
291

292 293 294

/* We like our types POD */

B
Minor  
Behdad Esfahbod 已提交
295 296 297
#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)
298 299

#ifdef __GNUC__
B
Behdad Esfahbod 已提交
300 301 302 303 304
# define _ASSERT_INSTANCE_POD1(_line, _instance) \
	HB_STMT_START { \
		typedef __typeof__(_instance) _type_##_line; \
		_ASSERT_TYPE_POD1 (_line, _type_##_line); \
	} HB_STMT_END
305
#else
B
Minor  
Behdad Esfahbod 已提交
306
# define _ASSERT_INSTANCE_POD1(_line, _instance)	typedef int _assertion_on_line_##_line##_not_tested
307
#endif
B
Minor  
Behdad Esfahbod 已提交
308 309
# define _ASSERT_INSTANCE_POD0(_line, _instance)	_ASSERT_INSTANCE_POD1 (_line, _instance)
# define ASSERT_INSTANCE_POD(_instance)			_ASSERT_INSTANCE_POD0 (__LINE__, _instance)
310 311 312

/* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \
B
Behdad Esfahbod 已提交
313
	HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
B
Minor  
Behdad Esfahbod 已提交
314 315 316
	{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line)	_ASSERT_POD1 (_line)
# define ASSERT_POD()		_ASSERT_POD0 (__LINE__)
317 318 319



B
Behdad Esfahbod 已提交
320 321
/* Misc */

322 323 324 325
/*
 * Void!
 */
typedef const struct _hb_void_t *hb_void_t;
B
Behdad Esfahbod 已提交
326
#define HB_VOID ((const _hb_void_t *) nullptr)
327

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

337 338
  if (sizeof (T) <= sizeof (unsigned long))
    return __builtin_popcountl (v);
B
Behdad Esfahbod 已提交
339

340 341
  if (sizeof (T) <= sizeof (unsigned long long))
    return __builtin_popcountll (v);
B
Behdad Esfahbod 已提交
342
#endif
B
Behdad Esfahbod 已提交
343 344 345 346 347

  if (sizeof (T) <= 4)
  {
    /* "HACKMEM 169" */
    uint32_t y;
348 349
    y = (v >> 1) &033333333333;
    y = v - y - ((y >>1) & 033333333333);
B
Behdad Esfahbod 已提交
350 351 352 353 354 355
    return (((y + (y >> 3)) & 030707070707) % 077);
  }

  if (sizeof (T) == 8)
  {
    unsigned int shift = 32;
356
    return _hb_popcount<uint32_t> ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift));
B
Behdad Esfahbod 已提交
357 358 359 360 361
  }

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

365
  assert (0);
B
Behdad Esfahbod 已提交
366
}
B
Behdad Esfahbod 已提交
367

B
Behdad Esfahbod 已提交
368
/* Returns the number of bits needed to store number */
369
template <typename T>
B
Behdad Esfahbod 已提交
370
static inline HB_CONST_FUNC unsigned int
371
_hb_bit_storage (T v)
B
Behdad Esfahbod 已提交
372
{
373
  if (unlikely (!v)) return 0;
B
Behdad Esfahbod 已提交
374

B
Behdad Esfahbod 已提交
375
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
376 377 378 379
  if (sizeof (T) <= sizeof (unsigned int))
    return sizeof (unsigned int) * 8 - __builtin_clz (v);

  if (sizeof (T) <= sizeof (unsigned long))
380
    return sizeof (unsigned long) * 8 - __builtin_clzl (v);
381 382

  if (sizeof (T) <= sizeof (unsigned long long))
383
    return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
B
Behdad Esfahbod 已提交
384 385 386
#endif

#if defined(_MSC_VER) || defined(__MINGW32__)
387 388 389 390 391 392 393 394
  if (sizeof (T) <= sizeof (unsigned int))
  {
    unsigned long where;
    _BitScanReverse (&where, v);
    return 1 + where;
  }
# if _WIN64
  if (sizeof (T) <= 8)
B
Behdad Esfahbod 已提交
395 396
  {
    unsigned long where;
397
    _BitScanReverse64 (&where, v);
B
Behdad Esfahbod 已提交
398 399
    return 1 + where;
  }
400
# endif
B
Behdad Esfahbod 已提交
401 402
#endif

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

  assert (0);
B
Behdad Esfahbod 已提交
439
}
B
Behdad Esfahbod 已提交
440

441 442
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
B
Behdad Esfahbod 已提交
443
static inline HB_CONST_FUNC unsigned int
444
_hb_ctz (T v)
B
Behdad Esfahbod 已提交
445
{
446
  if (unlikely (!v)) return 0;
B
Behdad Esfahbod 已提交
447

B
Behdad Esfahbod 已提交
448
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
449 450 451 452 453 454 455 456
  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 已提交
457 458 459
#endif

#if defined(_MSC_VER) || defined(__MINGW32__)
460 461 462 463
  if (sizeof (T) <= sizeof (unsigned int))
  {
    unsigned long where;
    _BitScanForward (&where, v);
B
Behdad Esfahbod 已提交
464
    return where;
465 466 467
  }
# if _WIN64
  if (sizeof (T) <= 8)
B
Behdad Esfahbod 已提交
468 469
  {
    unsigned long where;
470
    _BitScanForward64 (&where, v);
B
Behdad Esfahbod 已提交
471
    return where;
B
Behdad Esfahbod 已提交
472
  }
473
# endif
B
Behdad Esfahbod 已提交
474 475
#endif

476 477 478 479
  if (sizeof (T) <= 4)
  {
    /* "bithacks" */
    unsigned int c = 32;
B
Behdad Esfahbod 已提交
480
    v &= - (int32_t) v;
481 482 483 484 485 486 487
    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 已提交
488
  }
489 490 491 492
  if (sizeof (T) <= 8)
  {
    /* "bithacks" */
    unsigned int c = 64;
B
Behdad Esfahbod 已提交
493
    v &= - (int64_t) (v);
494
    if (v) c--;
B
Behdad Esfahbod 已提交
495 496 497 498 499 500
    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;
501 502 503 504 505 506 507 508 509 510
    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 已提交
511 512
}

513 514 515 516 517 518
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 已提交
519 520 521
static inline unsigned int
_hb_ceil_to_4 (unsigned int v)
{
B
Behdad Esfahbod 已提交
522
  return ((v - 1) | 3) + 1;
B
Behdad Esfahbod 已提交
523 524
}

525

B
Behdad Esfahbod 已提交
526 527 528 529

/* arrays and maps */


B
Behdad Esfahbod 已提交
530
#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
531
template <typename Type, unsigned int StaticSize=16>
B
Behdad Esfahbod 已提交
532 533
struct hb_prealloced_array_t
{
B
Behdad Esfahbod 已提交
534 535 536 537 538
  unsigned int len;
  unsigned int allocated;
  Type *array;
  Type static_array[StaticSize];

539 540 541 542 543 544
  void init (void)
  {
    len = 0;
    allocated = ARRAY_LENGTH (static_array);
    array = static_array;
  }
545

546 547
  inline Type& operator [] (unsigned int i) { return array[i]; }
  inline const Type& operator [] (unsigned int i) const { return array[i]; }
B
Behdad Esfahbod 已提交
548 549

  inline Type *push (void)
B
Behdad Esfahbod 已提交
550 551 552 553 554 555 556
  {
    if (unlikely (!resize (len + 1)))
      return nullptr;

    return &array[len - 1];
  }

B
Minor  
Behdad Esfahbod 已提交
557
  /* Allocate for size but don't adjust len. */
558
  inline bool alloc(unsigned int size)
B
Behdad Esfahbod 已提交
559
  {
B
Minor  
Behdad Esfahbod 已提交
560
    if (likely (size <= allocated))
561
      return true;
B
Minor  
Behdad Esfahbod 已提交
562 563

    /* Reallocate */
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578

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

    Type *new_array = nullptr;

    if (array == static_array) {
      new_array = (Type *) calloc (new_allocated, sizeof (Type));
      if (new_array)
        memcpy (new_array, array, len * sizeof (Type));
          } else {
      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
      if (likely (!overflows)) {
        new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
B
Behdad Esfahbod 已提交
579
      }
580
    }
581

582 583
    if (unlikely (!new_array))
      return false;
B
Behdad Esfahbod 已提交
584

585
    array = new_array;
R
Rod Sheeter 已提交
586
    allocated = new_allocated;
B
Minor  
Behdad Esfahbod 已提交
587

R
Rod Sheeter 已提交
588
    return true;
589
  }
B
Behdad Esfahbod 已提交
590

591 592
  inline bool resize (unsigned int size)
  {
B
Minor  
Behdad Esfahbod 已提交
593
    if (!alloc (size))
594
      return false;
595

B
Behdad Esfahbod 已提交
596 597
    len = size;
    return true;
B
Behdad Esfahbod 已提交
598 599 600 601 602
  }

  inline void pop (void)
  {
    len--;
B
Minor  
Behdad Esfahbod 已提交
603 604 605 606 607 608 609 610 611 612
  }

  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 已提交
613
  }
614 615 616 617 618 619 620

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

621 622 623 624 625
  template <typename T>
  inline Type *find (T v) {
    for (unsigned int i = 0; i < len; i++)
      if (array[i] == v)
	return &array[i];
B
Behdad Esfahbod 已提交
626
    return nullptr;
627 628 629 630 631 632
  }
  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];
B
Behdad Esfahbod 已提交
633
    return nullptr;
634 635
  }

636 637 638 639 640
  inline void qsort (int (*cmp)(const void*, const void*))
  {
    ::qsort (array, len, sizeof (Type), cmp);
  }

B
Behdad Esfahbod 已提交
641
  inline void qsort (void)
642
  {
B
Behdad Esfahbod 已提交
643
    ::qsort (array, len, sizeof (Type), Type::cmp);
644
  }
645

B
Behdad Esfahbod 已提交
646
  inline void qsort (unsigned int start, unsigned int end)
647
  {
B
Behdad Esfahbod 已提交
648
    ::qsort (array + start, end - start, sizeof (Type), Type::cmp);
649 650
  }

B
Behdad Esfahbod 已提交
651
  template <typename T>
B
Behdad Esfahbod 已提交
652
  inline Type *lsearch (const T &x)
B
Behdad Esfahbod 已提交
653 654
  {
    for (unsigned int i = 0; i < len; i++)
B
Behdad Esfahbod 已提交
655
      if (0 == this->array[i].cmp (&x))
B
Behdad Esfahbod 已提交
656 657 658 659
	return &array[i];
    return nullptr;
  }

660
  template <typename T>
B
Behdad Esfahbod 已提交
661
  inline Type *bsearch (const T &x)
662
  {
663 664
    unsigned int i;
    return bfind (x, &i) ? &array[i] : nullptr;
665 666
  }
  template <typename T>
B
Behdad Esfahbod 已提交
667
  inline const Type *bsearch (const T &x) const
668 669 670 671 672
  {
    unsigned int i;
    return bfind (x, &i) ? &array[i] : nullptr;
  }
  template <typename T>
B
Behdad Esfahbod 已提交
673
  inline bool bfind (const T &x, unsigned int *i) const
674
  {
B
Behdad Esfahbod 已提交
675 676 677 678
    int min = 0, max = (int) this->len - 1;
    while (min <= max)
    {
      int mid = (min + max) / 2;
B
Behdad Esfahbod 已提交
679
      int c = this->array[mid].cmp (&x);
B
Behdad Esfahbod 已提交
680 681 682 683 684
      if (c < 0)
        max = mid - 1;
      else if (c > 0)
        min = mid + 1;
      else
685 686 687 688
      {
        *i = mid;
	return true;
      }
B
Behdad Esfahbod 已提交
689
    }
B
Behdad Esfahbod 已提交
690
    if (max < 0 || (max < (int) this->len && this->array[max].cmp (&x) > 0))
691 692 693
      max++;
    *i = max;
    return false;
694
  }
B
Behdad Esfahbod 已提交
695 696 697 698 699

  inline void finish (void)
  {
    if (array != static_array)
      free (array);
B
Behdad Esfahbod 已提交
700
    array = nullptr;
B
Behdad Esfahbod 已提交
701 702
    allocated = len = 0;
  }
B
Behdad Esfahbod 已提交
703 704
};

B
Behdad Esfahbod 已提交
705
template <typename Type>
706
struct hb_auto_array_t : hb_prealloced_array_t <Type>
B
Behdad Esfahbod 已提交
707
{
708 709
  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 已提交
710 711
};

712

B
Behdad Esfahbod 已提交
713
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
714 715
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
B
Behdad Esfahbod 已提交
716
{
717
  hb_prealloced_array_t <item_t, 1> items;
B
Behdad Esfahbod 已提交
718

719 720
  inline void init (void) { items.init (); }

721
  template <typename T>
722
  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
B
Behdad Esfahbod 已提交
723
  {
724
    l.lock ();
725
    item_t *item = items.find (v);
726
    if (item) {
727 728 729 730 731 732 733
      if (replace) {
	item_t old = *item;
	*item = v;
	l.unlock ();
	old.finish ();
      }
      else {
B
Behdad Esfahbod 已提交
734
        item = nullptr;
735 736
	l.unlock ();
      }
737
    } else {
B
Behdad Esfahbod 已提交
738
      item = items.push ();
739 740 741 742
      if (likely (item))
	*item = v;
      l.unlock ();
    }
743
    return item;
B
Behdad Esfahbod 已提交
744 745
  }

746
  template <typename T>
747
  inline void remove (T v, lock_t &l)
B
Behdad Esfahbod 已提交
748
  {
749
    l.lock ();
750
    item_t *item = items.find (v);
751 752 753 754 755 756 757 758 759
    if (item) {
      item_t old = *item;
      *item = items[items.len - 1];
      items.pop ();
      l.unlock ();
      old.finish ();
    } else {
      l.unlock ();
    }
B
Behdad Esfahbod 已提交
760
  }
761

762
  template <typename T>
763
  inline bool find (T v, item_t *i, lock_t &l)
B
Behdad Esfahbod 已提交
764
  {
765 766 767 768 769 770
    l.lock ();
    item_t *item = items.find (v);
    if (item)
      *i = *item;
    l.unlock ();
    return !!item;
771 772
  }

773
  template <typename T>
774 775 776 777
  inline item_t *find_or_insert (T v, lock_t &l)
  {
    l.lock ();
    item_t *item = items.find (v);
778 779 780 781 782
    if (!item) {
      item = items.push ();
      if (likely (item))
        *item = v;
    }
783
    l.unlock ();
784 785 786
    return item;
  }

787 788
  inline void finish (lock_t &l)
  {
789 790 791 792 793
    if (!items.len) {
      /* No need for locking. */
      items.finish ();
      return;
    }
794 795 796 797 798 799 800 801
    l.lock ();
    while (items.len) {
      item_t old = items[items.len - 1];
	items.pop ();
	l.unlock ();
	old.finish ();
	l.lock ();
    }
B
Behdad Esfahbod 已提交
802
    items.finish ();
803 804 805 806 807
    l.unlock ();
  }

};

B
Behdad Esfahbod 已提交
808

B
Behdad Esfahbod 已提交
809
/* ASCII tag/character handling */
B
Behdad Esfahbod 已提交
810

811
static inline bool ISALPHA (unsigned char c)
812
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
813
static inline bool ISALNUM (unsigned char c)
814
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
815 816
static inline bool ISSPACE (unsigned char c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
817 818 819 820
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 已提交
821 822


B
Behdad Esfahbod 已提交
823 824 825 826 827 828 829 830 831
/* 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
#define HB_NDEBUG
#endif

832 833 834

/* Misc */

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

B
Behdad Esfahbod 已提交
841
template <typename T> static inline bool
B
Minor  
Behdad Esfahbod 已提交
842
hb_in_range (T u, T lo, T hi)
B
Minor  
Behdad Esfahbod 已提交
843
{
844 845 846
  /* 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 已提交
847
   * is unusable on some platforms and unused types are less likely
848
   * to generate a warning than unused variables. */
849
  static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
850

851 852 853
  /* 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 已提交
854 855
}

B
Behdad Esfahbod 已提交
856 857 858 859 860 861
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);
}

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

B
Minor  
Behdad Esfahbod 已提交
868

B
Behdad Esfahbod 已提交
869
/* Enable bitwise ops on enums marked as flags_t */
870 871
/* 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 已提交
872 873
 * originally had in mind... :(.
 *
874
 * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
B
Behdad Esfahbod 已提交
875 876 877 878
 */
#ifdef _MSC_VER
# pragma warning(disable:4200)
# pragma warning(disable:4800)
C
Chun-wei Fan 已提交
879
#endif
B
Behdad Esfahbod 已提交
880 881 882 883 884 885 886 887 888 889
#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 已提交
890 891


B
Behdad Esfahbod 已提交
892 893
/* Useful for set-operations on small enums.
 * For example, for testing "x ∈ {x1, x2, x3}" use:
B
Behdad Esfahbod 已提交
894
 * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
B
Behdad Esfahbod 已提交
895
 */
B
Behdad Esfahbod 已提交
896 897
#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)
898
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
B
Minor  
Behdad Esfahbod 已提交
899

B
Minor  
Behdad Esfahbod 已提交
900

B
Behdad Esfahbod 已提交
901
template <typename T, typename T2> static inline void
902
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
B
Behdad Esfahbod 已提交
903
{
904 905 906 907 908 909 910 911 912
  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 已提交
913
      T t = array[i];
914 915 916 917 918
      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
      array[j] = t;
    }
    if (array2)
    {
B
Minor  
Behdad Esfahbod 已提交
919
      T2 t = array2[i];
920 921 922 923
      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
      array2[j] = t;
    }
  }
B
Behdad Esfahbod 已提交
924 925
}

B
Behdad Esfahbod 已提交
926
template <typename T> static inline void
927
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
928
{
B
Behdad Esfahbod 已提交
929
  hb_stable_sort (array, len, compar, (int *) nullptr);
930
}
B
Behdad Esfahbod 已提交
931

932 933 934 935 936
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];
937 938 939
  len = MIN (ARRAY_LENGTH (buf) - 1, len);
  strncpy (buf, s, len);
  buf[len] = '\0';
940 941 942 943 944 945 946 947 948

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

B
Behdad Esfahbod 已提交
950

951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
/* 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; }
};

/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
template <typename elt_t, unsigned int byte_size>
struct hb_vector_size_t
{
  elt_t& operator [] (unsigned int i) { return v[i]; }
  const elt_t& operator [] (unsigned int i) const { return v[i]; }

  template <class Op>
  inline hb_vector_size_t process (const hb_vector_size_t &o) const
  {
    hb_vector_size_t r;
    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
      Op::process (r.v[i], v[i], o.v[i]);
    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;
    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
      r.v[i] = ~v[i];
    return r;
  }

  private:
B
Behdad Esfahbod 已提交
1008
  static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
1009 1010 1011 1012 1013 1014 1015 1016 1017
  elt_t v[byte_size / sizeof (elt_t)];
};

/* The `vector_size' attribute was introduced in gcc 3.1. */
#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
#define HAVE_VECTOR_SIZE 1
#endif


1018 1019 1020 1021
/* Global runtime options. */

struct hb_options_t
{
B
Behdad Esfahbod 已提交
1022 1023
  unsigned int initialized : 1;
  unsigned int uniscribe_bug_compatible : 1;
1024 1025 1026
};

union hb_options_union_t {
B
Behdad Esfahbod 已提交
1027
  unsigned int i;
1028 1029
  hb_options_t opts;
};
1030
static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045

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 已提交
1046 1047
/* Size signifying variable-sized array */
#define VAR 1
1048

B
Behdad Esfahbod 已提交
1049 1050 1051 1052 1053 1054 1055 1056

/* String type. */

struct hb_string_t
{
  inline hb_string_t (void) : bytes (nullptr), len (0) {}
  inline hb_string_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}

1057
  inline int cmp (const hb_string_t &a) const
B
Behdad Esfahbod 已提交
1058
  {
1059 1060
    if (len != a.len)
      return (int) a.len - (int) len;
B
Behdad Esfahbod 已提交
1061

1062
    return memcmp (a.bytes, bytes, len);
B
Behdad Esfahbod 已提交
1063 1064 1065 1066 1067
  }
  static inline int cmp (const void *pa, const void *pb)
  {
    hb_string_t *a = (hb_string_t *) pa;
    hb_string_t *b = (hb_string_t *) pb;
1068
    return b->cmp (*a);
B
Behdad Esfahbod 已提交
1069 1070 1071 1072 1073 1074 1075
  }

  const char *bytes;
  unsigned int len;
};


1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
/* 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


1089
#endif /* HB_PRIVATE_HH */