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

B
Behdad Esfahbod 已提交
55 56 57
#define HB_PASTE1(a,b) a##b
#define HB_PASTE(a,b) HB_PASTE1(a,b)

58 59 60 61 62 63
/* Compile-time custom allocator support. */

#if defined(hb_malloc_impl) \
 && defined(hb_calloc_impl) \
 && defined(hb_realloc_impl) \
 && defined(hb_free_impl)
64 65 66 67
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);
68 69 70 71 72 73 74
#define malloc hb_malloc_impl
#define calloc hb_calloc_impl
#define realloc hb_realloc_impl
#define free hb_free_impl
#endif


B
Behdad Esfahbod 已提交
75
/* Compiler attributes */
B
Behdad Esfahbod 已提交
76 77


78 79
#if __cplusplus < 201103L

80 81 82
#ifndef nullptr
#define nullptr NULL
#endif
83 84 85 86

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

#endif // __cplusplus < 201103L

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

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

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

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

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

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
#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
228 229 230 231 232 233
#  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
234 235
#  endif
#endif
B
Minor  
Behdad Esfahbod 已提交
236

B
Behdad Esfahbod 已提交
237 238 239
/* Basics */

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

243
#undef MAX
244 245
template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
246

247 248 249
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }

250

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

257 258
#define HB_STMT_START do
#define HB_STMT_END   while (0)
B
Behdad Esfahbod 已提交
259

260 261
template <unsigned int cond> class hb_assert_constant_t;
template <> class hb_assert_constant_t<1> {};
262 263

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

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

267 268 269 270 271 272 273 274
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 已提交
275

276 277 278 279
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 已提交
280

281 282 283

/* We like our types POD */

B
Minor  
Behdad Esfahbod 已提交
284 285 286
#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)
287 288

#ifdef __GNUC__
B
Behdad Esfahbod 已提交
289 290 291 292 293
# define _ASSERT_INSTANCE_POD1(_line, _instance) \
	HB_STMT_START { \
		typedef __typeof__(_instance) _type_##_line; \
		_ASSERT_TYPE_POD1 (_line, _type_##_line); \
	} HB_STMT_END
294
#else
B
Minor  
Behdad Esfahbod 已提交
295
# define _ASSERT_INSTANCE_POD1(_line, _instance)	typedef int _assertion_on_line_##_line##_not_tested
296
#endif
B
Minor  
Behdad Esfahbod 已提交
297 298
# define _ASSERT_INSTANCE_POD0(_line, _instance)	_ASSERT_INSTANCE_POD1 (_line, _instance)
# define ASSERT_INSTANCE_POD(_instance)			_ASSERT_INSTANCE_POD0 (__LINE__, _instance)
299 300 301

/* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \
B
Behdad Esfahbod 已提交
302
	HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
B
Minor  
Behdad Esfahbod 已提交
303 304 305
	{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line)	_ASSERT_POD1 (_line)
# define ASSERT_POD()		_ASSERT_POD0 (__LINE__)
306 307 308



B
Behdad Esfahbod 已提交
309 310
/* Misc */

311 312 313 314
/*
 * Void!
 */
typedef const struct _hb_void_t *hb_void_t;
B
Behdad Esfahbod 已提交
315
#define HB_VOID ((const _hb_void_t *) nullptr)
316

B
Behdad Esfahbod 已提交
317
/* Return the number of 1 bits in mask. */
B
Behdad Esfahbod 已提交
318
static inline HB_CONST_FUNC unsigned int
B
Behdad Esfahbod 已提交
319 320 321
_hb_popcount32 (uint32_t mask)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
B
Behdad Esfahbod 已提交
322
  return __builtin_popcount (mask);
B
Behdad Esfahbod 已提交
323
#else
B
Behdad Esfahbod 已提交
324
  /* "HACKMEM 169" */
325
  uint32_t y;
B
Behdad Esfahbod 已提交
326 327 328
  y = (mask >> 1) &033333333333;
  y = mask - y - ((y >>1) & 033333333333);
  return (((y + (y >> 3)) & 030707070707) % 077);
B
Behdad Esfahbod 已提交
329 330
#endif
}
B
Behdad Esfahbod 已提交
331 332 333 334
static inline HB_CONST_FUNC unsigned int
_hb_popcount64 (uint64_t mask)
{
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
335 336
  if (sizeof (long) >= sizeof (mask))
    return __builtin_popcountl (mask);
B
Behdad Esfahbod 已提交
337
#endif
B
Minor  
Behdad Esfahbod 已提交
338
  return _hb_popcount32 (mask & 0xFFFFFFFF) + _hb_popcount32 (mask >> 32);
B
Behdad Esfahbod 已提交
339 340 341 342
}
template <typename T> static inline unsigned int _hb_popcount (T mask);
template <> inline unsigned int _hb_popcount<uint32_t> (uint32_t mask) { return _hb_popcount32 (mask); }
template <> inline unsigned int _hb_popcount<uint64_t> (uint64_t mask) { return _hb_popcount64 (mask); }
B
Behdad Esfahbod 已提交
343

B
Behdad Esfahbod 已提交
344 345 346 347 348
/* 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 已提交
349
  return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
B
Behdad Esfahbod 已提交
350
#else
351
  unsigned int n_bits = 0;
B
Behdad Esfahbod 已提交
352 353 354 355 356 357 358
  while (number) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}
B
Behdad Esfahbod 已提交
359

B
Behdad Esfahbod 已提交
360 361 362 363 364 365 366
/* 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
367
  unsigned int n_bits = 0;
B
Behdad Esfahbod 已提交
368 369 370 371 372 373 374 375 376
  if (unlikely (!number)) return 0;
  while (!(number & 1)) {
    n_bits++;
    number >>= 1;
  }
  return n_bits;
#endif
}

377 378 379 380 381 382 383
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 已提交
384 385 386 387

/* arrays and maps */


B
Behdad Esfahbod 已提交
388
#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
389
template <typename Type, unsigned int StaticSize=16>
B
Behdad Esfahbod 已提交
390 391
struct hb_prealloced_array_t
{
B
Behdad Esfahbod 已提交
392 393 394 395 396
  unsigned int len;
  unsigned int allocated;
  Type *array;
  Type static_array[StaticSize];

397 398 399 400 401 402
  void init (void)
  {
    len = 0;
    allocated = ARRAY_LENGTH (static_array);
    array = static_array;
  }
403

404 405
  inline Type& operator [] (unsigned int i) { return array[i]; }
  inline const Type& operator [] (unsigned int i) const { return array[i]; }
B
Behdad Esfahbod 已提交
406 407

  inline Type *push (void)
B
Behdad Esfahbod 已提交
408 409 410 411 412 413 414 415
  {
    if (unlikely (!resize (len + 1)))
      return nullptr;

    return &array[len - 1];
  }

  inline bool resize (unsigned int size)
B
Behdad Esfahbod 已提交
416
  {
417
    if (unlikely (size > allocated))
B
Behdad Esfahbod 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
    {
      /* Need to reallocate */

      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 已提交
436
      }
437

B
Behdad Esfahbod 已提交
438 439 440 441 442 443
      if (unlikely (!new_array))
	return false;

      array = new_array;
      allocated = new_allocated;
    }
444

B
Behdad Esfahbod 已提交
445 446
    len = size;
    return true;
B
Behdad Esfahbod 已提交
447 448 449 450 451
  }

  inline void pop (void)
  {
    len--;
B
Minor  
Behdad Esfahbod 已提交
452 453 454 455 456 457 458 459 460 461
  }

  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 已提交
462
  }
463 464 465 466 467 468 469

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

470 471 472 473 474
  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 已提交
475
    return nullptr;
476 477 478 479 480 481
  }
  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 已提交
482
    return nullptr;
483 484
  }

B
Behdad Esfahbod 已提交
485
  inline void qsort (void)
486
  {
B
Behdad Esfahbod 已提交
487
    ::qsort (array, len, sizeof (Type), Type::cmp);
488
  }
489

B
Behdad Esfahbod 已提交
490
  inline void qsort (unsigned int start, unsigned int end)
491
  {
B
Behdad Esfahbod 已提交
492
    ::qsort (array + start, end - start, sizeof (Type), Type::cmp);
493 494
  }

B
Behdad Esfahbod 已提交
495 496 497 498 499 500 501 502 503
  template <typename T>
  inline Type *lsearch (T *x)
  {
    for (unsigned int i = 0; i < len; i++)
      if (0 == this->array[i].cmp (x))
	return &array[i];
    return nullptr;
  }

504
  template <typename T>
B
Behdad Esfahbod 已提交
505
  inline Type *bsearch (T *x)
506
  {
507 508
    unsigned int i;
    return bfind (x, &i) ? &array[i] : nullptr;
509 510
  }
  template <typename T>
B
Behdad Esfahbod 已提交
511
  inline const Type *bsearch (T *x) const
512 513 514 515 516 517
  {
    unsigned int i;
    return bfind (x, &i) ? &array[i] : nullptr;
  }
  template <typename T>
  inline bool bfind (T *x, unsigned int *i) const
518
  {
B
Behdad Esfahbod 已提交
519 520 521 522 523 524 525 526 527 528
    int min = 0, max = (int) this->len - 1;
    while (min <= max)
    {
      int mid = (min + max) / 2;
      int c = this->array[mid].cmp (x);
      if (c < 0)
        max = mid - 1;
      else if (c > 0)
        min = mid + 1;
      else
529 530 531 532
      {
        *i = mid;
	return true;
      }
B
Behdad Esfahbod 已提交
533
    }
B
Behdad Esfahbod 已提交
534
    if (max < 0 || (max < (int) this->len && this->array[max].cmp (x) > 0))
535 536 537
      max++;
    *i = max;
    return false;
538
  }
B
Behdad Esfahbod 已提交
539 540 541 542 543

  inline void finish (void)
  {
    if (array != static_array)
      free (array);
B
Behdad Esfahbod 已提交
544
    array = nullptr;
B
Behdad Esfahbod 已提交
545 546
    allocated = len = 0;
  }
B
Behdad Esfahbod 已提交
547 548
};

B
Behdad Esfahbod 已提交
549
template <typename Type>
550
struct hb_auto_array_t : hb_prealloced_array_t <Type>
B
Behdad Esfahbod 已提交
551
{
552 553
  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 已提交
554 555
};

556

B
Behdad Esfahbod 已提交
557
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
558 559
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
B
Behdad Esfahbod 已提交
560
{
561
  hb_prealloced_array_t <item_t, 1> items;
B
Behdad Esfahbod 已提交
562

563 564
  inline void init (void) { items.init (); }

565
  template <typename T>
566
  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
B
Behdad Esfahbod 已提交
567
  {
568
    l.lock ();
569
    item_t *item = items.find (v);
570
    if (item) {
571 572 573 574 575 576 577
      if (replace) {
	item_t old = *item;
	*item = v;
	l.unlock ();
	old.finish ();
      }
      else {
B
Behdad Esfahbod 已提交
578
        item = nullptr;
579 580
	l.unlock ();
      }
581
    } else {
B
Behdad Esfahbod 已提交
582
      item = items.push ();
583 584 585 586
      if (likely (item))
	*item = v;
      l.unlock ();
    }
587
    return item;
B
Behdad Esfahbod 已提交
588 589
  }

590
  template <typename T>
591
  inline void remove (T v, lock_t &l)
B
Behdad Esfahbod 已提交
592
  {
593
    l.lock ();
594
    item_t *item = items.find (v);
595 596 597 598 599 600 601 602 603
    if (item) {
      item_t old = *item;
      *item = items[items.len - 1];
      items.pop ();
      l.unlock ();
      old.finish ();
    } else {
      l.unlock ();
    }
B
Behdad Esfahbod 已提交
604
  }
605

606
  template <typename T>
607
  inline bool find (T v, item_t *i, lock_t &l)
B
Behdad Esfahbod 已提交
608
  {
609 610 611 612 613 614
    l.lock ();
    item_t *item = items.find (v);
    if (item)
      *i = *item;
    l.unlock ();
    return !!item;
615 616
  }

617
  template <typename T>
618 619 620 621
  inline item_t *find_or_insert (T v, lock_t &l)
  {
    l.lock ();
    item_t *item = items.find (v);
622 623 624 625 626
    if (!item) {
      item = items.push ();
      if (likely (item))
        *item = v;
    }
627
    l.unlock ();
628 629 630
    return item;
  }

631 632
  inline void finish (lock_t &l)
  {
633 634 635 636 637
    if (!items.len) {
      /* No need for locking. */
      items.finish ();
      return;
    }
638 639 640 641 642 643 644 645
    l.lock ();
    while (items.len) {
      item_t old = items[items.len - 1];
	items.pop ();
	l.unlock ();
	old.finish ();
	l.lock ();
    }
B
Behdad Esfahbod 已提交
646
    items.finish ();
647 648 649 650 651
    l.unlock ();
  }

};

B
Behdad Esfahbod 已提交
652

B
Behdad Esfahbod 已提交
653
/* ASCII tag/character handling */
B
Behdad Esfahbod 已提交
654

655
static inline bool ISALPHA (unsigned char c)
656
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
657
static inline bool ISALNUM (unsigned char c)
658
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
659 660
static inline bool ISSPACE (unsigned char c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
661 662 663 664
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 已提交
665 666


B
Behdad Esfahbod 已提交
667 668 669 670 671 672 673 674 675
/* 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

676 677 678

/* Misc */

B
Behdad Esfahbod 已提交
679 680
template <typename T> class hb_assert_unsigned_t;
template <> class hb_assert_unsigned_t<unsigned char> {};
681
template <> class hb_assert_unsigned_t<unsigned short> {};
B
Behdad Esfahbod 已提交
682 683
template <> class hb_assert_unsigned_t<unsigned int> {};
template <> class hb_assert_unsigned_t<unsigned long> {};
B
Behdad Esfahbod 已提交
684

B
Behdad Esfahbod 已提交
685
template <typename T> static inline bool
B
Minor  
Behdad Esfahbod 已提交
686
hb_in_range (T u, T lo, T hi)
B
Minor  
Behdad Esfahbod 已提交
687
{
688 689 690
  /* 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 已提交
691
   * is unusable on some platforms and unused types are less likely
692
   * to generate a warning than unused variables. */
693
  static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
694

695 696 697
  /* 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 已提交
698 699
}

B
Behdad Esfahbod 已提交
700 701 702 703 704 705
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);
}

706
template <typename T> static inline bool
B
Behdad Esfahbod 已提交
707
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
708
{
B
Behdad Esfahbod 已提交
709
  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
710 711
}

B
Minor  
Behdad Esfahbod 已提交
712

B
Behdad Esfahbod 已提交
713
/* Enable bitwise ops on enums marked as flags_t */
714 715
/* 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 已提交
716 717
 * originally had in mind... :(.
 *
718
 * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
B
Behdad Esfahbod 已提交
719 720 721 722
 */
#ifdef _MSC_VER
# pragma warning(disable:4200)
# pragma warning(disable:4800)
C
Chun-wei Fan 已提交
723
#endif
B
Behdad Esfahbod 已提交
724 725 726 727 728 729 730 731 732 733
#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 已提交
734 735


B
Behdad Esfahbod 已提交
736 737
/* Useful for set-operations on small enums.
 * For example, for testing "x ∈ {x1, x2, x3}" use:
B
Behdad Esfahbod 已提交
738
 * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
B
Behdad Esfahbod 已提交
739
 */
B
Behdad Esfahbod 已提交
740 741
#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)
742
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
B
Minor  
Behdad Esfahbod 已提交
743

B
Minor  
Behdad Esfahbod 已提交
744

B
Behdad Esfahbod 已提交
745
template <typename T, typename T2> static inline void
746
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
B
Behdad Esfahbod 已提交
747
{
748 749 750 751 752 753 754 755 756
  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 已提交
757
      T t = array[i];
758 759 760 761 762
      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
      array[j] = t;
    }
    if (array2)
    {
B
Minor  
Behdad Esfahbod 已提交
763
      T2 t = array2[i];
764 765 766 767
      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
      array2[j] = t;
    }
  }
B
Behdad Esfahbod 已提交
768 769
}

B
Behdad Esfahbod 已提交
770
template <typename T> static inline void
771
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
772
{
B
Behdad Esfahbod 已提交
773
  hb_stable_sort (array, len, compar, (int *) nullptr);
774
}
B
Behdad Esfahbod 已提交
775

776 777 778 779 780
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];
781 782 783
  len = MIN (ARRAY_LENGTH (buf) - 1, len);
  strncpy (buf, s, len);
  buf[len] = '\0';
784 785 786 787 788 789 790 791 792

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

B
Behdad Esfahbod 已提交
794

795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
/* 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 已提交
852
  static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
853 854 855 856 857 858 859 860 861
  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


862 863 864 865
/* Global runtime options. */

struct hb_options_t
{
B
Behdad Esfahbod 已提交
866 867
  unsigned int initialized : 1;
  unsigned int uniscribe_bug_compatible : 1;
868 869 870
};

union hb_options_union_t {
B
Behdad Esfahbod 已提交
871
  unsigned int i;
872 873
  hb_options_t opts;
};
874
static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889

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 已提交
890 891
/* Size signifying variable-sized array */
#define VAR 1
892

B
Behdad Esfahbod 已提交
893 894 895 896 897 898 899 900

/* 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_) {}

901
  inline int cmp (const hb_string_t &a) const
B
Behdad Esfahbod 已提交
902
  {
903 904
    if (len != a.len)
      return (int) a.len - (int) len;
B
Behdad Esfahbod 已提交
905

906
    return memcmp (a.bytes, bytes, len);
B
Behdad Esfahbod 已提交
907 908 909 910 911
  }
  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;
912
    return b->cmp (*a);
B
Behdad Esfahbod 已提交
913 914 915 916 917 918 919
  }

  const char *bytes;
  unsigned int len;
};


920
#endif /* HB_PRIVATE_HH */