1/*
2 * Copyright © 2007,2008,2009  Red Hat, Inc.
3 * Copyright © 2011,2012  Google, Inc.
4 *
5 *  This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29#ifndef HB_PRIVATE_HH
30#define HB_PRIVATE_HH
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include "hb.h"
37#define HB_H_IN
38#ifdef HAVE_OT
39#include "hb-ot.h"
40#define HB_OT_H_IN
41#endif
42
43#include <stdlib.h>
44#include <stddef.h>
45#include <string.h>
46#include <assert.h>
47
48/* We only use these two for debug output.  However, the debug code is
49 * always seen by the compiler (and optimized out in non-debug builds.
50 * If including these becomes a problem, we can start thinking about
51 * someway around that. */
52#include <stdio.h>
53#include <errno.h>
54#include <stdarg.h>
55
56
57/* Compiler attributes */
58
59
60#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
61#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
62#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
63#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
64#else
65#define likely(expr) (expr)
66#define unlikely(expr) (expr)
67#endif
68
69#ifndef __GNUC__
70#undef __attribute__
71#define __attribute__(x)
72#endif
73
74#if __GNUC__ >= 3
75#define HB_PURE_FUNC	__attribute__((pure))
76#define HB_CONST_FUNC	__attribute__((const))
77#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
78#else
79#define HB_PURE_FUNC
80#define HB_CONST_FUNC
81#define HB_PRINTF_FUNC(format_idx, arg_idx)
82#endif
83#if __GNUC__ >= 4
84#define HB_UNUSED	__attribute__((unused))
85#else
86#define HB_UNUSED
87#endif
88
89#ifndef HB_INTERNAL
90# if !defined(__MINGW32__) && !defined(__CYGWIN__)
91#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
92# else
93#  define HB_INTERNAL
94# endif
95#endif
96
97#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
98#define snprintf _snprintf
99/* Windows CE only has _strdup, while rest of Windows has both. */
100#define strdup _strdup
101#endif
102
103#ifdef _MSC_VER
104#undef inline
105#define inline __inline
106#endif
107
108#ifdef __STRICT_ANSI__
109#undef inline
110#define inline __inline__
111#endif
112
113#if __GNUC__ >= 3
114#define HB_FUNC __PRETTY_FUNCTION__
115#elif defined(_MSC_VER)
116#define HB_FUNC __FUNCSIG__
117#else
118#define HB_FUNC __func__
119#endif
120
121#if defined(_WIN32) || defined(__CYGWIN__)
122   /* We need Windows Vista for both Uniscribe backend and for
123    * MemoryBarrier.  We don't support compiling on Windows XP,
124    * though we run on it fine. */
125#  if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
126#    undef _WIN32_WINNT
127#  endif
128#  ifndef _WIN32_WINNT
129#    define _WIN32_WINNT 0x0600
130#  endif
131#  ifndef WIN32_LEAN_AND_MEAN
132#    define WIN32_LEAN_AND_MEAN 1
133#  endif
134#  ifndef STRICT
135#    define STRICT 1
136#  endif
137#endif
138
139#ifdef _WIN32_WCE
140/* Some things not defined on Windows CE. */
141#define MemoryBarrier()
142#define getenv(Name) NULL
143#define setlocale(Category, Locale) "C"
144static int errno = 0; /* Use something better? */
145#endif
146
147#if HAVE_ATEXIT
148/* atexit() is only safe to be called from shared libraries on certain
149 * platforms.  Whitelist.
150 * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
151#  if defined(__linux) && defined(__GLIBC_PREREQ)
152#    if __GLIBC_PREREQ(2,3)
153/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
154#      define HB_USE_ATEXIT 1
155#    endif
156#  elif defined(_MSC_VER) || defined(__MINGW32__)
157/* For MSVC:
158 * http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
159 * http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
160 * mingw32 headers say atexit is safe to use in shared libraries.
161 */
162#    define HB_USE_ATEXIT 1
163#  elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
164/* This was fixed in Android NKD r8 or r8b:
165 * https://code.google.com/p/android/issues/detail?id=6455
166 * which introduced GCC 4.6:
167 * https://developer.android.com/tools/sdk/ndk/index.html
168 */
169#    define HB_USE_ATEXIT 1
170#  endif
171#endif
172
173/* Basics */
174
175
176#ifndef NULL
177# define NULL ((void *) 0)
178#endif
179
180#undef MIN
181template <typename Type>
182static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
183
184#undef MAX
185template <typename Type>
186static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
187
188static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
189{ return (a + (b - 1)) / b; }
190
191
192#undef  ARRAY_LENGTH
193template <typename Type, unsigned int n>
194static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
195/* A const version, but does not detect erratically being called on pointers. */
196#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
197
198#define HB_STMT_START do
199#define HB_STMT_END   while (0)
200
201#define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
202#define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
203#define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
204
205#define ASSERT_STATIC_EXPR(_cond)((void) sizeof (char[(_cond) ? 1 : -1]))
206#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
207
208#define _PASTE1(a,b) a##b
209#define PASTE(a,b) _PASTE1(a,b)
210
211/* Lets assert int types.  Saves trouble down the road. */
212
213ASSERT_STATIC (sizeof (int8_t) == 1);
214ASSERT_STATIC (sizeof (uint8_t) == 1);
215ASSERT_STATIC (sizeof (int16_t) == 2);
216ASSERT_STATIC (sizeof (uint16_t) == 2);
217ASSERT_STATIC (sizeof (int32_t) == 4);
218ASSERT_STATIC (sizeof (uint32_t) == 4);
219ASSERT_STATIC (sizeof (int64_t) == 8);
220ASSERT_STATIC (sizeof (uint64_t) == 8);
221
222ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
223ASSERT_STATIC (sizeof (hb_position_t) == 4);
224ASSERT_STATIC (sizeof (hb_mask_t) == 4);
225ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
226
227
228/* We like our types POD */
229
230#define _ASSERT_TYPE_POD1(_line, _type)	union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; }
231#define _ASSERT_TYPE_POD0(_line, _type)	_ASSERT_TYPE_POD1 (_line, _type)
232#define ASSERT_TYPE_POD(_type)		_ASSERT_TYPE_POD0 (__LINE__, _type)
233
234#ifdef __GNUC__
235# define _ASSERT_INSTANCE_POD1(_line, _instance) \
236	HB_STMT_START { \
237		typedef __typeof__(_instance) _type_##_line; \
238		_ASSERT_TYPE_POD1 (_line, _type_##_line); \
239	} HB_STMT_END
240#else
241# define _ASSERT_INSTANCE_POD1(_line, _instance)	typedef int _assertion_on_line_##_line##_not_tested
242#endif
243# define _ASSERT_INSTANCE_POD0(_line, _instance)	_ASSERT_INSTANCE_POD1 (_line, _instance)
244# define ASSERT_INSTANCE_POD(_instance)			_ASSERT_INSTANCE_POD0 (__LINE__, _instance)
245
246/* Check _assertion in a method environment */
247#define _ASSERT_POD1(_line) \
248	HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
249	{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
250# define _ASSERT_POD0(_line)	_ASSERT_POD1 (_line)
251# define ASSERT_POD()		_ASSERT_POD0 (__LINE__)
252
253
254
255/* Misc */
256
257/* Void! */
258struct _hb_void_t {};
259typedef const _hb_void_t &hb_void_t;
260#define HB_VOID (* (const _hb_void_t *) NULL)
261
262/* Return the number of 1 bits in mask. */
263static inline HB_CONST_FUNC unsigned int
264_hb_popcount32 (uint32_t mask)
265{
266#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
267  return __builtin_popcount (mask);
268#else
269  /* "HACKMEM 169" */
270  uint32_t y;
271  y = (mask >> 1) &033333333333;
272  y = mask - y - ((y >>1) & 033333333333);
273  return (((y + (y >> 3)) & 030707070707) % 077);
274#endif
275}
276
277/* Returns the number of bits needed to store number */
278static inline HB_CONST_FUNC unsigned int
279_hb_bit_storage (unsigned int number)
280{
281#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
282  return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
283#else
284  unsigned int n_bits = 0;
285  while (number) {
286    n_bits++;
287    number >>= 1;
288  }
289  return n_bits;
290#endif
291}
292
293/* Returns the number of zero bits in the least significant side of number */
294static inline HB_CONST_FUNC unsigned int
295_hb_ctz (unsigned int number)
296{
297#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
298  return likely (number) ? __builtin_ctz (number) : 0;
299#else
300  unsigned int n_bits = 0;
301  if (unlikely (!number)) return 0;
302  while (!(number & 1)) {
303    n_bits++;
304    number >>= 1;
305  }
306  return n_bits;
307#endif
308}
309
310static inline bool
311_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
312{
313  return (size > 0) && (count >= ((unsigned int) -1) / size);
314}
315
316
317/* Type of bsearch() / qsort() compare function */
318typedef int (*hb_compare_func_t) (const void *, const void *);
319
320
321
322
323/* arrays and maps */
324
325
326#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
327template <typename Type, unsigned int StaticSize=16>
328struct hb_prealloced_array_t
329{
330  unsigned int len;
331  unsigned int allocated;
332  Type *array;
333  Type static_array[StaticSize];
334
335  void init (void) { memset (this, 0, sizeof (*this)); }
336
337  inline Type& operator [] (unsigned int i) { return array[i]; }
338  inline const Type& operator [] (unsigned int i) const { return array[i]; }
339
340  inline Type *push (void)
341  {
342    if (!array) {
343      array = static_array;
344      allocated = ARRAY_LENGTH (static_array);
345    }
346    if (likely (len < allocated))
347      return &array[len++];
348
349    /* Need to reallocate */
350    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
351    Type *new_array = NULL;
352
353    if (array == static_array) {
354      new_array = (Type *) calloc (new_allocated, sizeof (Type));
355      if (new_array)
356        memcpy (new_array, array, len * sizeof (Type));
357    } else {
358      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
359      if (likely (!overflows)) {
360	new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
361      }
362    }
363
364    if (unlikely (!new_array))
365      return NULL;
366
367    array = new_array;
368    allocated = new_allocated;
369    return &array[len++];
370  }
371
372  inline void pop (void)
373  {
374    len--;
375  }
376
377  inline void remove (unsigned int i)
378  {
379     if (unlikely (i >= len))
380       return;
381     memmove (static_cast<void *> (&array[i]),
382	      static_cast<void *> (&array[i + 1]),
383	      (len - i - 1) * sizeof (Type));
384     len--;
385  }
386
387  inline void shrink (unsigned int l)
388  {
389     if (l < len)
390       len = l;
391  }
392
393  template <typename T>
394  inline Type *find (T v) {
395    for (unsigned int i = 0; i < len; i++)
396      if (array[i] == v)
397	return &array[i];
398    return NULL;
399  }
400  template <typename T>
401  inline const Type *find (T v) const {
402    for (unsigned int i = 0; i < len; i++)
403      if (array[i] == v)
404	return &array[i];
405    return NULL;
406  }
407
408  inline void qsort (void)
409  {
410    ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
411  }
412
413  inline void qsort (unsigned int start, unsigned int end)
414  {
415    ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
416  }
417
418  template <typename T>
419  inline Type *bsearch (T *key)
420  {
421    return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
422  }
423  template <typename T>
424  inline const Type *bsearch (T *key) const
425  {
426    return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
427  }
428
429  inline void finish (void)
430  {
431    if (array != static_array)
432      free (array);
433    array = NULL;
434    allocated = len = 0;
435  }
436};
437
438template <typename Type>
439struct hb_auto_array_t : hb_prealloced_array_t <Type>
440{
441  hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
442  ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
443};
444
445
446#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
447template <typename item_t, typename lock_t>
448struct hb_lockable_set_t
449{
450  hb_prealloced_array_t <item_t, 2> items;
451
452  inline void init (void) { items.init (); }
453
454  template <typename T>
455  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
456  {
457    l.lock ();
458    item_t *item = items.find (v);
459    if (item) {
460      if (replace) {
461	item_t old = *item;
462	*item = v;
463	l.unlock ();
464	old.finish ();
465      }
466      else {
467        item = NULL;
468	l.unlock ();
469      }
470    } else {
471      item = items.push ();
472      if (likely (item))
473	*item = v;
474      l.unlock ();
475    }
476    return item;
477  }
478
479  template <typename T>
480  inline void remove (T v, lock_t &l)
481  {
482    l.lock ();
483    item_t *item = items.find (v);
484    if (item) {
485      item_t old = *item;
486      *item = items[items.len - 1];
487      items.pop ();
488      l.unlock ();
489      old.finish ();
490    } else {
491      l.unlock ();
492    }
493  }
494
495  template <typename T>
496  inline bool find (T v, item_t *i, lock_t &l)
497  {
498    l.lock ();
499    item_t *item = items.find (v);
500    if (item)
501      *i = *item;
502    l.unlock ();
503    return !!item;
504  }
505
506  template <typename T>
507  inline item_t *find_or_insert (T v, lock_t &l)
508  {
509    l.lock ();
510    item_t *item = items.find (v);
511    if (!item) {
512      item = items.push ();
513      if (likely (item))
514        *item = v;
515    }
516    l.unlock ();
517    return item;
518  }
519
520  inline void finish (lock_t &l)
521  {
522    if (!items.len) {
523      /* No need for locking. */
524      items.finish ();
525      return;
526    }
527    l.lock ();
528    while (items.len) {
529      item_t old = items[items.len - 1];
530	items.pop ();
531	l.unlock ();
532	old.finish ();
533	l.lock ();
534    }
535    items.finish ();
536    l.unlock ();
537  }
538
539};
540
541
542
543
544/* Big-endian handling */
545
546static inline uint16_t hb_be_uint16 (const uint16_t v)
547{
548  const uint8_t *V = (const uint8_t *) &v;
549  return (V[0] << 8) | V[1];
550}
551
552static inline uint16_t hb_uint16_swap (const uint16_t v)
553{
554  return (v >> 8) | (v << 8);
555}
556
557static inline uint32_t hb_uint32_swap (const uint32_t v)
558{
559  return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16);
560}
561
562/* Note, of the following macros, uint16_get is the one called many many times.
563 * If there is any optimizations to be done, it's in that macro.  However, I
564 * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
565 * results in a single ror instruction, does NOT speed this up.  In fact, it
566 * resulted in a minor slowdown.  At any rate, note that v may not be correctly
567 * aligned, so I think the current implementation is optimal.
568 */
569
570#define hb_be_uint16_put(v,V)	HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
571#define hb_be_uint16_get(v)	(uint16_t) ((v[0] << 8) + v[1])
572#define hb_be_uint16_eq(a,b)	(a[0] == b[0] && a[1] == b[1])
573
574#define hb_be_uint32_put(v,V)	HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END
575#define hb_be_uint32_get(v)	(uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
576#define hb_be_uint32_eq(a,b)	(a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
577
578#define hb_be_uint24_put(v,V)	HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] = (V); } HB_STMT_END
579#define hb_be_uint24_get(v)	(uint32_t) ((v[0] << 16) + (v[1] << 8) + v[2])
580#define hb_be_uint24_eq(a,b)	(a[0] == b[0] && a[1] == b[1] && a[2] == b[2])
581
582
583/* ASCII tag/character handling */
584
585static inline bool ISALPHA (unsigned char c)
586{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
587static inline bool ISALNUM (unsigned char c)
588{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
589static inline bool ISSPACE (unsigned char c)
590{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
591static inline unsigned char TOUPPER (unsigned char c)
592{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
593static inline unsigned char TOLOWER (unsigned char c)
594{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
595
596#define HB_TAG_CHAR4(s)   (HB_TAG(((const char *) s)[0], \
597				  ((const char *) s)[1], \
598				  ((const char *) s)[2], \
599				  ((const char *) s)[3]))
600
601
602/* C++ helpers */
603
604/* Makes class uncopyable.  Use in private: section. */
605#define NO_COPY(T) \
606  T (const T &o); \
607  T &operator = (const T &o)
608
609
610/* Debug */
611
612
613#ifndef HB_DEBUG
614#define HB_DEBUG 0
615#endif
616
617static inline bool
618_hb_debug (unsigned int level,
619	   unsigned int max_level)
620{
621  return level < max_level;
622}
623
624#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
625#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
626
627template <int max_level> static inline void
628_hb_debug_msg_va (const char *what,
629		  const void *obj,
630		  const char *func,
631		  bool indented,
632		  unsigned int level,
633		  int level_dir,
634		  const char *message,
635		  va_list ap) HB_PRINTF_FUNC(7, 0);
636template <int max_level> static inline void
637_hb_debug_msg_va (const char *what,
638		  const void *obj,
639		  const char *func,
640		  bool indented,
641		  unsigned int level,
642		  int level_dir,
643		  const char *message,
644		  va_list ap)
645{
646  if (!_hb_debug (level, max_level))
647    return;
648
649  fprintf (stderr, "%-10s", what ? what : "");
650
651  if (obj)
652    fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
653  else
654    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
655
656  if (indented) {
657/* One may want to add ASCII version of these.  See:
658 * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
659#define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
660#define VRBAR	"\342\224\234"	/* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
661#define DLBAR	"\342\225\256"	/* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
662#define ULBAR	"\342\225\257"	/* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
663#define LBAR	"\342\225\264"	/* U+2574 BOX DRAWINGS LIGHT LEFT */
664    static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
665    fprintf (stderr, "%2u %s" VRBAR "%s",
666	     level,
667	     bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
668	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
669  } else
670    fprintf (stderr, "   " VRBAR LBAR);
671
672  if (func)
673  {
674    unsigned int func_len = strlen (func);
675#ifndef HB_DEBUG_VERBOSE
676    /* Skip "typename" */
677    if (0 == strncmp (func, "typename ", 9))
678      func += 9;
679    /* Skip return type */
680    const char *space = strchr (func, ' ');
681    if (space)
682      func = space + 1;
683    /* Skip parameter list */
684    const char *paren = strchr (func, '(');
685    if (paren)
686      func_len = paren - func;
687#endif
688    fprintf (stderr, "%.*s: ", func_len, func);
689  }
690
691  if (message)
692    vfprintf (stderr, message, ap);
693
694  fprintf (stderr, "\n");
695}
696template <> inline void
697_hb_debug_msg_va<0> (const char *what HB_UNUSED,
698		     const void *obj HB_UNUSED,
699		     const char *func HB_UNUSED,
700		     bool indented HB_UNUSED,
701		     unsigned int level HB_UNUSED,
702		     int level_dir HB_UNUSED,
703		     const char *message HB_UNUSED,
704		     va_list ap HB_UNUSED) {}
705
706template <int max_level> static inline void
707_hb_debug_msg (const char *what,
708	       const void *obj,
709	       const char *func,
710	       bool indented,
711	       unsigned int level,
712	       int level_dir,
713	       const char *message,
714	       ...) HB_PRINTF_FUNC(7, 8);
715template <int max_level> static inline void
716_hb_debug_msg (const char *what,
717	       const void *obj,
718	       const char *func,
719	       bool indented,
720	       unsigned int level,
721	       int level_dir,
722	       const char *message,
723	       ...)
724{
725  va_list ap;
726  va_start (ap, message);
727  _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
728  va_end (ap);
729}
730template <> inline void
731_hb_debug_msg<0> (const char *what HB_UNUSED,
732		  const void *obj HB_UNUSED,
733		  const char *func HB_UNUSED,
734		  bool indented HB_UNUSED,
735		  unsigned int level HB_UNUSED,
736		  int level_dir HB_UNUSED,
737		  const char *message HB_UNUSED,
738		  ...) HB_PRINTF_FUNC(7, 8);
739template <> inline void
740_hb_debug_msg<0> (const char *what HB_UNUSED,
741		  const void *obj HB_UNUSED,
742		  const char *func HB_UNUSED,
743		  bool indented HB_UNUSED,
744		  unsigned int level HB_UNUSED,
745		  int level_dir HB_UNUSED,
746		  const char *message HB_UNUSED,
747		  ...) {}
748
749#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
750#define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    false, 0, 0, __VA_ARGS__)
751#define DEBUG_MSG_FUNC(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
752
753
754/*
755 * Printer
756 */
757
758template <typename T>
759struct hb_printer_t {};
760
761template <>
762struct hb_printer_t<bool> {
763  const char *print (bool v) { return v ? "true" : "false"; }
764};
765
766template <>
767struct hb_printer_t<hb_void_t> {
768  const char *print (hb_void_t) { return ""; }
769};
770
771
772/*
773 * Trace
774 */
775
776template <typename T>
777static inline void _hb_warn_no_return (bool returned)
778{
779  if (unlikely (!returned)) {
780    fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.\n");
781  }
782}
783template <>
784/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
785{}
786
787template <int max_level, typename ret_t>
788struct hb_auto_trace_t {
789  explicit inline hb_auto_trace_t (unsigned int *plevel_,
790				   const char *what_,
791				   const void *obj_,
792				   const char *func,
793				   const char *message,
794				   ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
795  {
796    if (plevel) ++*plevel;
797
798    va_list ap;
799    va_start (ap, message);
800    _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
801    va_end (ap);
802  }
803  inline ~hb_auto_trace_t (void)
804  {
805    _hb_warn_no_return<ret_t> (returned);
806    if (!returned) {
807      _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
808    }
809    if (plevel) --*plevel;
810  }
811
812  inline ret_t ret (ret_t v, unsigned int line = 0)
813  {
814    if (unlikely (returned)) {
815      fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
816      return v;
817    }
818
819    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
820			      "return %s (line %d)",
821			      hb_printer_t<ret_t>().print (v), line);
822    if (plevel) --*plevel;
823    plevel = NULL;
824    returned = true;
825    return v;
826  }
827
828  private:
829  unsigned int *plevel;
830  const char *what;
831  const void *obj;
832  bool returned;
833};
834template <typename ret_t> /* Optimize when tracing is disabled */
835struct hb_auto_trace_t<0, ret_t> {
836  explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
837				   const char *what HB_UNUSED,
838				   const void *obj HB_UNUSED,
839				   const char *func HB_UNUSED,
840				   const char *message HB_UNUSED,
841				   ...) {}
842
843  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
844};
845
846#define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
847
848/* Misc */
849
850template <typename T> class hb_assert_unsigned_t;
851template <> class hb_assert_unsigned_t<unsigned char> {};
852template <> class hb_assert_unsigned_t<unsigned short> {};
853template <> class hb_assert_unsigned_t<unsigned int> {};
854template <> class hb_assert_unsigned_t<unsigned long> {};
855
856template <typename T> static inline bool
857hb_in_range (T u, T lo, T hi)
858{
859  /* The sizeof() is here to force template instantiation.
860   * I'm sure there are better ways to do this but can't think of
861   * one right now.  Declaring a variable won't work as HB_UNUSED
862   * is unsable on some platforms and unused types are less likely
863   * to generate a warning than unused variables. */
864  ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
865
866  /* The casts below are important as if T is smaller than int,
867   * the subtract results will become a signed int! */
868  return (T)(u - lo) <= (T)(hi - lo);
869}
870
871template <typename T> static inline bool
872hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
873{
874  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
875}
876
877template <typename T> static inline bool
878hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
879{
880  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
881}
882
883
884/* Useful for set-operations on small enums.
885 * For example, for testing "x ∈ {x1, x2, x3}" use:
886 * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
887 */
888#define FLAG(x) (1<<(x))
889#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
890
891
892template <typename T, typename T2> inline void
893hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
894{
895  if (unlikely (!len))
896    return;
897
898  unsigned int k = len - 1;
899  do {
900    unsigned int new_k = 0;
901
902    for (unsigned int j = 0; j < k; j++)
903      if (compar (&array[j], &array[j+1]) > 0)
904      {
905        {
906	  T t;
907	  t = array[j];
908	  array[j] = array[j + 1];
909	  array[j + 1] = t;
910	}
911        if (array2)
912        {
913	  T2 t;
914	  t = array2[j];
915	  array2[j] = array2[j + 1];
916	  array2[j + 1] = t;
917	}
918
919	new_k = j;
920      }
921    k = new_k;
922  } while (k);
923}
924
925template <typename T> inline void
926hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
927{
928  hb_bubble_sort (array, len, compar, (int *) NULL);
929}
930
931static inline hb_bool_t
932hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
933{
934  /* Pain because we don't know whether s is nul-terminated. */
935  char buf[64];
936  len = MIN (ARRAY_LENGTH (buf) - 1, len);
937  strncpy (buf, s, len);
938  buf[len] = '\0';
939
940  char *end;
941  errno = 0;
942  unsigned long v = strtoul (buf, &end, base);
943  if (errno) return false;
944  if (*end) return false;
945  *out = v;
946  return true;
947}
948
949
950/* Global runtime options. */
951
952struct hb_options_t
953{
954  int initialized : 1;
955  int uniscribe_bug_compatible : 1;
956};
957
958union hb_options_union_t {
959  int i;
960  hb_options_t opts;
961};
962ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));
963
964HB_INTERNAL void
965_hb_options_init (void);
966
967extern HB_INTERNAL hb_options_union_t _hb_options;
968
969static inline hb_options_t
970hb_options (void)
971{
972  if (unlikely (!_hb_options.i))
973    _hb_options_init ();
974
975  return _hb_options.opts;
976}
977
978
979#endif /* HB_PRIVATE_HH */
980