blob: f2290448ced7a0df115cae57e2294c731dd4af91 [file] [log] [blame]
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009 Red Hat, Inc.
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02003 * Copyright © 2011,2012 Google, Inc.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05006 *
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
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -050027 */
28
Behdad Esfahbodc57d4542011-04-20 18:50:27 -040029#ifndef HB_PRIVATE_HH
30#define HB_PRIVATE_HH
Behdad Esfahbod5b3f7702006-12-28 06:42:37 -050031
Behdad Esfahbod5ddd9cc2011-09-16 16:40:44 -040032#ifdef HAVE_CONFIG_H
Behdad Esfahboddf660282009-08-01 20:46:02 -040033#include "config.h"
34#endif
Behdad Esfahbod12360f72008-01-23 15:50:38 -050035
Behdad Esfahbodd1c9eb42012-04-12 13:17:44 -040036#include "hb.h"
Behdad Esfahbodd1c9eb42012-04-12 13:17:44 -040037#define HB_H_IN
Behdad Esfahbod3e32cd92012-04-23 13:20:52 -040038#ifdef HAVE_OT
39#include "hb-ot.h"
Behdad Esfahbodd1c9eb42012-04-12 13:17:44 -040040#define HB_OT_H_IN
Behdad Esfahbod3e32cd92012-04-23 13:20:52 -040041#endif
Behdad Esfahbodb28815c2009-08-04 22:35:36 -040042
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040043#include <stdlib.h>
Behdad Esfahbodb65c0602011-07-28 16:48:43 -040044#include <stddef.h>
Behdad Esfahbodf0954d12009-07-30 15:33:57 -040045#include <string.h>
46#include <assert.h>
Behdad Esfahbod1d521512010-04-28 13:18:41 -040047
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. */
Behdad Esfahbod7acb3892009-08-05 15:20:34 -040052#include <stdio.h>
53#include <errno.h>
Behdad Esfahbodcc06c242011-07-25 20:25:44 -040054#include <stdarg.h>
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040055
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040056
Behdad Esfahbod52b41852015-10-03 13:20:55 +010057/* Compile-time custom allocator support. */
58
59#if defined(hb_malloc_impl) \
60 && defined(hb_calloc_impl) \
61 && defined(hb_realloc_impl) \
62 && defined(hb_free_impl)
Behdad Esfahbodcc6ea302015-10-12 17:21:52 -040063extern "C" void* hb_malloc_impl(size_t size);
64extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
65extern "C" void* hb_realloc_impl(void *ptr, size_t size);
66extern "C" void hb_free_impl(void *ptr);
Behdad Esfahbod52b41852015-10-03 13:20:55 +010067#define malloc hb_malloc_impl
68#define calloc hb_calloc_impl
69#define realloc hb_realloc_impl
70#define free hb_free_impl
71#endif
72
73
Behdad Esfahbodae2b8542014-06-03 16:59:09 -040074/* Compiler attributes */
Behdad Esfahbodbc200452010-04-29 01:40:26 -040075
Behdad Esfahbodbc200452010-04-29 01:40:26 -040076
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +020077#if __cplusplus < 201103L
78
79// Null pointer literal
80// Source: SC22/WG21/N2431 = J16/07-0301
81// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
82
83const // this is a const object...
84class {
85public:
86 template<class T> // convertible to any type
87 operator T*() const { // of null non-member
88 return 0; // pointer...
89 }
90 template<class C, class T> // or any type of null
91 operator T C::*() const { // member pointer...
92 return 0;
93 }
94private:
95 void operator&() const; // whose address can't be taken
Behdad Esfahbod3c13e152017-10-15 14:02:58 +020096} _hb_nullptr = {}; // and whose name is nullptr
97#define nullptr _hb_nullptr
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +020098
99// Static assertions
100#ifndef static_assert
101#define _PASTE1(a,b) a##b
102#define _PASTE(a,b) _PASTE1(a,b)
103#define static_assert(e, msg) \
Behdad Esfahbodc3448e82017-10-15 12:02:00 +0200104 HB_UNUSED typedef int _PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200105#endif // static_assert
106
107#endif // __cplusplus < 201103L
108
109
Ebrahim Byagowi76c48732017-06-02 21:53:10 +0430110#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
111#define likely(expr) (__builtin_expect (!!(expr), 1))
112#define unlikely(expr) (__builtin_expect (!!(expr), 0))
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400113#else
114#define likely(expr) (expr)
115#define unlikely(expr) (expr)
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400116#endif
117
Steve Lhomme0b8f3ab2016-07-11 21:57:26 +0200118#if !defined(__GNUC__) && !defined(__clang__)
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400119#undef __attribute__
120#define __attribute__(x)
121#endif
Behdad Esfahboda794ebf2009-08-06 12:32:35 -0400122
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400123#if __GNUC__ >= 3
124#define HB_PURE_FUNC __attribute__((pure))
125#define HB_CONST_FUNC __attribute__((const))
126#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
127#else
128#define HB_PURE_FUNC
129#define HB_CONST_FUNC
130#define HB_PRINTF_FUNC(format_idx, arg_idx)
131#endif
132#if __GNUC__ >= 4
133#define HB_UNUSED __attribute__((unused))
134#else
135#define HB_UNUSED
136#endif
137
138#ifndef HB_INTERNAL
Behdad Esfahbodf1a8d502014-07-19 16:52:32 -0400139# if !defined(__MINGW32__) && !defined(__CYGWIN__)
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400140# define HB_INTERNAL __attribute__((__visibility__("hidden")))
141# else
142# define HB_INTERNAL
143# endif
144#endif
145
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400146#if __GNUC__ >= 3
147#define HB_FUNC __PRETTY_FUNCTION__
148#elif defined(_MSC_VER)
149#define HB_FUNC __FUNCSIG__
150#else
151#define HB_FUNC __func__
152#endif
153
Behdad Esfahbod305d2fb2015-10-21 11:04:28 -0200154/*
155 * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
156 * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
157 * cases that fall through without a break or return statement. HB_FALLTHROUGH
158 * is only needed on cases that have code:
159 *
160 * switch (foo) {
161 * case 1: // These cases have no code. No fallthrough annotations are needed.
162 * case 2:
163 * case 3:
164 * foo = 4; // This case has code, so a fallthrough annotation is needed:
165 * HB_FALLTHROUGH;
166 * default:
167 * return foo;
168 * }
169 */
170#if defined(__clang__) && __cplusplus >= 201103L
171 /* clang's fallthrough annotations are only available starting in C++11. */
172# define HB_FALLTHROUGH [[clang::fallthrough]]
173#elif defined(_MSC_VER)
174 /*
175 * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
176 * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
177 */
178# include <sal.h>
179# define HB_FALLTHROUGH __fallthrough
180#else
181# define HB_FALLTHROUGH /* FALLTHROUGH */
182#endif
183
Behdad Esfahbod0fc0a102014-07-21 11:12:54 -0400184#if defined(_WIN32) || defined(__CYGWIN__)
Behdad Esfahboddb308282014-07-19 16:32:04 -0400185 /* We need Windows Vista for both Uniscribe backend and for
186 * MemoryBarrier. We don't support compiling on Windows XP,
187 * though we run on it fine. */
188# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
189# undef _WIN32_WINNT
190# endif
191# ifndef _WIN32_WINNT
192# define _WIN32_WINNT 0x0600
193# endif
Behdad Esfahbod270971a2014-08-15 14:28:04 -0400194# ifndef WIN32_LEAN_AND_MEAN
195# define WIN32_LEAN_AND_MEAN 1
196# endif
197# ifndef STRICT
198# define STRICT 1
199# endif
Behdad Esfahboddabe6982012-11-23 14:21:35 -0500200
Konstantin Rittf3537b62015-01-25 09:50:51 +0400201# if defined(_WIN32_WCE)
202 /* Some things not defined on Windows CE. */
Konstantin Ritt50690622016-04-26 12:02:26 +0400203# define vsnprintf _vsnprintf
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200204# define getenv(Name) nullptr
Konstantin Ritt855a5d72015-04-10 17:18:01 +0400205# if _WIN32_WCE < 0x800
206# define setlocale(Category, Locale) "C"
Behdad Esfahbod26a963b2014-08-10 18:04:50 -0400207static int errno = 0; /* Use something better? */
Konstantin Ritt855a5d72015-04-10 17:18:01 +0400208# endif
Konstantin Rittf3537b62015-01-25 09:50:51 +0400209# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200210# define getenv(Name) nullptr
Konstantin Rittf3537b62015-01-25 09:50:51 +0400211# endif
Behdad Esfahbodce01ad72015-04-01 11:05:59 -0700212# if defined(_MSC_VER) && _MSC_VER < 1900
Konstantin Rittf3537b62015-01-25 09:50:51 +0400213# define snprintf _snprintf
Konstantin Rittf3537b62015-01-25 09:50:51 +0400214# endif
Behdad Esfahbod26a963b2014-08-10 18:04:50 -0400215#endif
216
Behdad Esfahbod38fb30d2014-08-06 13:34:49 -0400217#if HAVE_ATEXIT
218/* atexit() is only safe to be called from shared libraries on certain
219 * platforms. Whitelist.
220 * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
221# if defined(__linux) && defined(__GLIBC_PREREQ)
222# if __GLIBC_PREREQ(2,3)
223/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
224# define HB_USE_ATEXIT 1
225# endif
226# elif defined(_MSC_VER) || defined(__MINGW32__)
227/* For MSVC:
228 * http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
229 * http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
230 * mingw32 headers say atexit is safe to use in shared libraries.
231 */
232# define HB_USE_ATEXIT 1
233# elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
234/* This was fixed in Android NKD r8 or r8b:
235 * https://code.google.com/p/android/issues/detail?id=6455
236 * which introduced GCC 4.6:
237 * https://developer.android.com/tools/sdk/ndk/index.html
238 */
239# define HB_USE_ATEXIT 1
240# endif
241#endif
Behdad Esfahboddabe6982012-11-23 14:21:35 -0500242
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400243/* Basics */
244
245#undef MIN
Behdad Esfahbod25326c22012-08-04 16:43:18 -0700246template <typename Type>
247static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400248
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500249#undef MAX
Behdad Esfahbod25326c22012-08-04 16:43:18 -0700250template <typename Type>
251static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400252
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500253static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
254{ return (a + (b - 1)) / b; }
255
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500256
Behdad Esfahbod45917532009-11-04 18:15:59 -0500257#undef ARRAY_LENGTH
Behdad Esfahbod25326c22012-08-04 16:43:18 -0700258template <typename Type, unsigned int n>
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500259static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400260/* A const version, but does not detect erratically being called on pointers. */
261#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400262
Behdad Esfahbod35a73832009-08-01 19:30:31 -0400263#define HB_STMT_START do
264#define HB_STMT_END while (0)
Behdad Esfahbod5b3f7702006-12-28 06:42:37 -0500265
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200266template <unsigned int cond> class hb_assert_constant_t;
267template <> class hb_assert_constant_t<1> {};
Behdad Esfahbod672ca3b2015-10-26 14:05:05 -0700268
269#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
Behdad Esfahboddcb70262011-04-21 16:34:22 -0400270
Behdad Esfahbod6fd53642011-04-11 11:47:14 -0400271/* Lets assert int types. Saves trouble down the road. */
272
Behdad Esfahbodc3448e82017-10-15 12:02:00 +0200273static_assert ((sizeof (int8_t) == 1), "");
274static_assert ((sizeof (uint8_t) == 1), "");
275static_assert ((sizeof (int16_t) == 2), "");
276static_assert ((sizeof (uint16_t) == 2), "");
277static_assert ((sizeof (int32_t) == 4), "");
278static_assert ((sizeof (uint32_t) == 4), "");
279static_assert ((sizeof (int64_t) == 8), "");
280static_assert ((sizeof (uint64_t) == 8), "");
Behdad Esfahbod6fd53642011-04-11 11:47:14 -0400281
Behdad Esfahbodc3448e82017-10-15 12:02:00 +0200282static_assert ((sizeof (hb_codepoint_t) == 4), "");
283static_assert ((sizeof (hb_position_t) == 4), "");
284static_assert ((sizeof (hb_mask_t) == 4), "");
285static_assert ((sizeof (hb_var_int_t) == 4), "");
Behdad Esfahbod6fd53642011-04-11 11:47:14 -0400286
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400287
288/* We like our types POD */
289
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400290#define _ASSERT_TYPE_POD1(_line, _type) union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; }
291#define _ASSERT_TYPE_POD0(_line, _type) _ASSERT_TYPE_POD1 (_line, _type)
292#define ASSERT_TYPE_POD(_type) _ASSERT_TYPE_POD0 (__LINE__, _type)
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400293
294#ifdef __GNUC__
Behdad Esfahbod79e2b472012-06-06 11:27:17 -0400295# define _ASSERT_INSTANCE_POD1(_line, _instance) \
296 HB_STMT_START { \
297 typedef __typeof__(_instance) _type_##_line; \
298 _ASSERT_TYPE_POD1 (_line, _type_##_line); \
299 } HB_STMT_END
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400300#else
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400301# define _ASSERT_INSTANCE_POD1(_line, _instance) typedef int _assertion_on_line_##_line##_not_tested
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400302#endif
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400303# define _ASSERT_INSTANCE_POD0(_line, _instance) _ASSERT_INSTANCE_POD1 (_line, _instance)
304# define ASSERT_INSTANCE_POD(_instance) _ASSERT_INSTANCE_POD0 (__LINE__, _instance)
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400305
306/* Check _assertion in a method environment */
307#define _ASSERT_POD1(_line) \
Behdad Esfahboddac86022014-06-03 17:57:00 -0400308 HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400309 { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
310# define _ASSERT_POD0(_line) _ASSERT_POD1 (_line)
311# define ASSERT_POD() _ASSERT_POD0 (__LINE__)
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400312
313
314
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400315/* Misc */
316
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400317/* Void! */
318struct _hb_void_t {};
Behdad Esfahboda5e4f6d2015-06-10 10:57:46 -0700319typedef const _hb_void_t *hb_void_t;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200320#define HB_VOID ((const _hb_void_t *) nullptr)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400321
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100322/* Return the number of 1 bits in mask. */
Behdad Esfahbod97e7f8f2010-05-11 00:11:36 -0400323static inline HB_CONST_FUNC unsigned int
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400324_hb_popcount32 (uint32_t mask)
325{
326#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100327 return __builtin_popcount (mask);
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400328#else
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100329 /* "HACKMEM 169" */
Behdad Esfahboda949cd32014-03-16 20:22:42 -0700330 uint32_t y;
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100331 y = (mask >> 1) &033333333333;
332 y = mask - y - ((y >>1) & 033333333333);
333 return (((y + (y >> 3)) & 030707070707) % 077);
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400334#endif
335}
Behdad Esfahbod6fb4ac72017-10-15 16:00:09 +0200336static inline HB_CONST_FUNC unsigned int
337_hb_popcount64 (uint64_t mask)
338{
339#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
340 return __builtin_popcountl (mask);
341#else
342 return _hb_popcount32 (mask) + _hb_popcount32 (mask >> 32);
343#endif
344}
345template <typename T> static inline unsigned int _hb_popcount (T mask);
346template <> inline unsigned int _hb_popcount<uint32_t> (uint32_t mask) { return _hb_popcount32 (mask); }
347template <> inline unsigned int _hb_popcount<uint64_t> (uint64_t mask) { return _hb_popcount64 (mask); }
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400348
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100349/* Returns the number of bits needed to store number */
350static inline HB_CONST_FUNC unsigned int
351_hb_bit_storage (unsigned int number)
352{
353#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100354 return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100355#else
Behdad Esfahboda949cd32014-03-16 20:22:42 -0700356 unsigned int n_bits = 0;
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100357 while (number) {
358 n_bits++;
359 number >>= 1;
360 }
361 return n_bits;
362#endif
363}
Behdad Esfahboddf660282009-08-01 20:46:02 -0400364
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100365/* Returns the number of zero bits in the least significant side of number */
366static inline HB_CONST_FUNC unsigned int
367_hb_ctz (unsigned int number)
368{
369#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
370 return likely (number) ? __builtin_ctz (number) : 0;
371#else
Behdad Esfahboda949cd32014-03-16 20:22:42 -0700372 unsigned int n_bits = 0;
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100373 if (unlikely (!number)) return 0;
374 while (!(number & 1)) {
375 n_bits++;
376 number >>= 1;
377 }
378 return n_bits;
379#endif
380}
381
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400382static inline bool
383_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
384{
385 return (size > 0) && (count >= ((unsigned int) -1) / size);
386}
387
388
Behdad Esfahbod8f08c322010-10-08 19:43:48 -0400389/* Type of bsearch() / qsort() compare function */
390typedef int (*hb_compare_func_t) (const void *, const void *);
391
392
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400393
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400394
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400395/* arrays and maps */
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400396
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400397
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200398#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
Behdad Esfahbod546b1ad2014-06-26 19:10:21 -0400399template <typename Type, unsigned int StaticSize=16>
Behdad Esfahbod0e253e92012-06-05 15:37:19 -0400400struct hb_prealloced_array_t
401{
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400402 unsigned int len;
403 unsigned int allocated;
404 Type *array;
405 Type static_array[StaticSize];
406
Behdad Esfahbodbf93b632012-06-05 14:17:32 -0400407 void init (void) { memset (this, 0, sizeof (*this)); }
Behdad Esfahbodefde8112011-08-23 00:04:57 +0200408
Behdad Esfahbod265ac612011-05-05 14:38:16 -0400409 inline Type& operator [] (unsigned int i) { return array[i]; }
410 inline const Type& operator [] (unsigned int i) const { return array[i]; }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400411
412 inline Type *push (void)
413 {
414 if (!array) {
415 array = static_array;
416 allocated = ARRAY_LENGTH (static_array);
417 }
418 if (likely (len < allocated))
419 return &array[len++];
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400420
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400421 /* Need to reallocate */
422 unsigned int new_allocated = allocated + (allocated >> 1) + 8;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200423 Type *new_array = nullptr;
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400424
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400425 if (array == static_array) {
426 new_array = (Type *) calloc (new_allocated, sizeof (Type));
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400427 if (new_array)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400428 memcpy (new_array, array, len * sizeof (Type));
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400429 } else {
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400430 bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400431 if (likely (!overflows)) {
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400432 new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400433 }
434 }
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400435
436 if (unlikely (!new_array))
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200437 return nullptr;
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400438
439 array = new_array;
440 allocated = new_allocated;
441 return &array[len++];
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400442 }
443
444 inline void pop (void)
445 {
446 len--;
Behdad Esfahbod639afdc2013-08-06 14:28:12 -0400447 }
448
449 inline void remove (unsigned int i)
450 {
451 if (unlikely (i >= len))
452 return;
453 memmove (static_cast<void *> (&array[i]),
454 static_cast<void *> (&array[i + 1]),
455 (len - i - 1) * sizeof (Type));
456 len--;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400457 }
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400458
459 inline void shrink (unsigned int l)
460 {
461 if (l < len)
462 len = l;
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400463 }
464
Behdad Esfahbod68435692011-05-05 14:12:37 -0400465 template <typename T>
466 inline Type *find (T v) {
467 for (unsigned int i = 0; i < len; i++)
468 if (array[i] == v)
469 return &array[i];
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200470 return nullptr;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400471 }
472 template <typename T>
473 inline const Type *find (T v) const {
474 for (unsigned int i = 0; i < len; i++)
475 if (array[i] == v)
476 return &array[i];
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200477 return nullptr;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400478 }
479
Behdad Esfahbodfb8cc862014-06-19 15:30:18 -0400480 inline void qsort (void)
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400481 {
Behdad Esfahbodfb8cc862014-06-19 15:30:18 -0400482 ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400483 }
Behdad Esfahbod68435692011-05-05 14:12:37 -0400484
Behdad Esfahbodfb8cc862014-06-19 15:30:18 -0400485 inline void qsort (unsigned int start, unsigned int end)
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400486 {
Behdad Esfahbodfb8cc862014-06-19 15:30:18 -0400487 ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400488 }
489
Behdad Esfahbod68435692011-05-05 14:12:37 -0400490 template <typename T>
Behdad Esfahboddb5f7ef2017-10-15 16:00:22 +0200491 inline Type *bsearch (T *x)
Behdad Esfahbod68435692011-05-05 14:12:37 -0400492 {
Behdad Esfahboddb5f7ef2017-10-15 16:00:22 +0200493 int min = 0, max = (int) this->len - 1;
494 while (min <= max)
495 {
496 int mid = (min + max) / 2;
497 int c = this->array[mid].cmp (x);
498 if (c < 0)
499 max = mid - 1;
500 else if (c > 0)
501 min = mid + 1;
502 else
503 return &this->array[mid];
504 }
505 return nullptr;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400506 }
507 template <typename T>
Behdad Esfahboddb5f7ef2017-10-15 16:00:22 +0200508 inline const Type *bsearch (T *x) const
Behdad Esfahbod68435692011-05-05 14:12:37 -0400509 {
Behdad Esfahboddb5f7ef2017-10-15 16:00:22 +0200510 int min = 0, max = (int) this->len - 1;
511 while (min <= max)
512 {
513 int mid = (min + max) / 2;
514 int c = this->array[mid].cmp (x);
515 if (c < 0)
516 max = mid - 1;
517 else if (c > 0)
518 min = mid + 1;
519 else
520 return &this->array[mid];
521 }
522 return nullptr;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400523 }
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400524
525 inline void finish (void)
526 {
527 if (array != static_array)
528 free (array);
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200529 array = nullptr;
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400530 allocated = len = 0;
531 }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400532};
533
Behdad Esfahbodc5d91f32013-03-09 04:34:21 -0500534template <typename Type>
Behdad Esfahbod546b1ad2014-06-26 19:10:21 -0400535struct hb_auto_array_t : hb_prealloced_array_t <Type>
Behdad Esfahbodc5d91f32013-03-09 04:34:21 -0500536{
Behdad Esfahbod546b1ad2014-06-26 19:10:21 -0400537 hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
538 ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
Behdad Esfahbodc5d91f32013-03-09 04:34:21 -0500539};
540
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400541
Behdad Esfahbod0e253e92012-06-05 15:37:19 -0400542#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400543template <typename item_t, typename lock_t>
544struct hb_lockable_set_t
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400545{
Behdad Esfahbod0e253e92012-06-05 15:37:19 -0400546 hb_prealloced_array_t <item_t, 2> items;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400547
Behdad Esfahbodbf93b632012-06-05 14:17:32 -0400548 inline void init (void) { items.init (); }
549
Behdad Esfahbod478a4252011-05-05 12:39:51 -0400550 template <typename T>
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200551 inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400552 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400553 l.lock ();
Behdad Esfahbod68435692011-05-05 14:12:37 -0400554 item_t *item = items.find (v);
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400555 if (item) {
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200556 if (replace) {
557 item_t old = *item;
558 *item = v;
559 l.unlock ();
560 old.finish ();
561 }
562 else {
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200563 item = nullptr;
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200564 l.unlock ();
565 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400566 } else {
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400567 item = items.push ();
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400568 if (likely (item))
569 *item = v;
570 l.unlock ();
571 }
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400572 return item;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400573 }
574
Behdad Esfahbod811482b2011-05-05 13:21:04 -0400575 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400576 inline void remove (T v, lock_t &l)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400577 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400578 l.lock ();
Behdad Esfahbod68435692011-05-05 14:12:37 -0400579 item_t *item = items.find (v);
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400580 if (item) {
581 item_t old = *item;
582 *item = items[items.len - 1];
583 items.pop ();
584 l.unlock ();
585 old.finish ();
586 } else {
587 l.unlock ();
588 }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400589 }
590
Behdad Esfahbod478a4252011-05-05 12:39:51 -0400591 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400592 inline bool find (T v, item_t *i, lock_t &l)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400593 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400594 l.lock ();
595 item_t *item = items.find (v);
596 if (item)
597 *i = *item;
598 l.unlock ();
599 return !!item;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400600 }
601
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400602 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400603 inline item_t *find_or_insert (T v, lock_t &l)
604 {
605 l.lock ();
606 item_t *item = items.find (v);
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400607 if (!item) {
608 item = items.push ();
609 if (likely (item))
610 *item = v;
611 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400612 l.unlock ();
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400613 return item;
614 }
615
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400616 inline void finish (lock_t &l)
617 {
Behdad Esfahbod3f4764b2012-07-30 10:06:42 -0400618 if (!items.len) {
619 /* No need for locking. */
620 items.finish ();
621 return;
622 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400623 l.lock ();
624 while (items.len) {
625 item_t old = items[items.len - 1];
626 items.pop ();
627 l.unlock ();
628 old.finish ();
629 l.lock ();
630 }
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400631 items.finish ();
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400632 l.unlock ();
633 }
634
635};
636
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400637
Behdad Esfahbod41880962011-04-11 14:58:28 -0400638/* ASCII tag/character handling */
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400639
Behdad Esfahbod20b817a2013-02-27 18:39:37 -0500640static inline bool ISALPHA (unsigned char c)
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400641{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
Behdad Esfahbod20b817a2013-02-27 18:39:37 -0500642static inline bool ISALNUM (unsigned char c)
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400643{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
Behdad Esfahbod20b817a2013-02-27 18:39:37 -0500644static inline bool ISSPACE (unsigned char c)
645{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400646static inline unsigned char TOUPPER (unsigned char c)
647{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
648static inline unsigned char TOLOWER (unsigned char c)
649{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400650
Behdad Esfahbod41880962011-04-11 14:58:28 -0400651#define HB_TAG_CHAR4(s) (HB_TAG(((const char *) s)[0], \
652 ((const char *) s)[1], \
653 ((const char *) s)[2], \
654 ((const char *) s)[3]))
655
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400656
Behdad Esfahbod831886a2011-05-11 21:27:52 -0400657/* C++ helpers */
658
659/* Makes class uncopyable. Use in private: section. */
660#define NO_COPY(T) \
661 T (const T &o); \
Behdad Esfahbod970e0922011-06-14 14:35:44 -0400662 T &operator = (const T &o)
Behdad Esfahbod831886a2011-05-11 21:27:52 -0400663
664
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400665/* Debug */
666
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400667
Behdad Esfahbod91dd1152016-02-25 13:56:47 +0900668/* HB_NDEBUG disables some sanity checks that are very safe to disable and
669 * should be disabled in production systems. If NDEBUG is defined, enable
670 * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
671 * light-weight) to be enabled, then HB_DEBUG can be defined to disable
672 * the costlier checks. */
673#ifdef NDEBUG
674#define HB_NDEBUG
675#endif
676
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400677#ifndef HB_DEBUG
678#define HB_DEBUG 0
679#endif
680
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400681static inline bool
682_hb_debug (unsigned int level,
683 unsigned int max_level)
684{
685 return level < max_level;
686}
687
Behdad Esfahbod6c15ddf2013-04-30 11:34:00 -0400688#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
689#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
Behdad Esfahbod43ff2032011-07-25 17:35:24 -0400690
Behdad Esfahbod5f541f82015-02-21 16:51:17 +0300691static inline void
692_hb_print_func (const char *func)
693{
694 if (func)
695 {
696 unsigned int func_len = strlen (func);
697 /* Skip "static" */
698 if (0 == strncmp (func, "static ", 7))
699 func += 7;
700 /* Skip "typename" */
701 if (0 == strncmp (func, "typename ", 9))
702 func += 9;
703 /* Skip return type */
704 const char *space = strchr (func, ' ');
705 if (space)
706 func = space + 1;
707 /* Skip parameter list */
708 const char *paren = strchr (func, '(');
709 if (paren)
710 func_len = paren - func;
711 fprintf (stderr, "%.*s", func_len, func);
712 }
713}
714
Behdad Esfahbod2d1dcb32012-10-07 17:13:46 -0400715template <int max_level> static inline void
Behdad Esfahbod20810972012-05-10 23:06:58 +0200716_hb_debug_msg_va (const char *what,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200717 const void *obj,
718 const char *func,
719 bool indented,
720 unsigned int level,
721 int level_dir,
722 const char *message,
Behdad Esfahbod29e25552014-08-12 17:02:59 -0400723 va_list ap) HB_PRINTF_FUNC(7, 0);
724template <int max_level> static inline void
725_hb_debug_msg_va (const char *what,
726 const void *obj,
727 const char *func,
728 bool indented,
729 unsigned int level,
730 int level_dir,
731 const char *message,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200732 va_list ap)
Behdad Esfahbod20810972012-05-10 23:06:58 +0200733{
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200734 if (!_hb_debug (level, max_level))
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200735 return;
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200736
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200737 fprintf (stderr, "%-10s", what ? what : "");
738
739 if (obj)
Behdad Esfahbod5ccfe8e2012-05-11 02:19:41 +0200740 fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200741 else
742 fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
743
Behdad Esfahbodd7bba012012-05-11 02:46:26 +0200744 if (indented) {
Behdad Esfahbod6932a412012-06-26 10:46:31 -0400745#define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
746#define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
747#define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
748#define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
749#define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */
Behdad Esfahboddf98ce52016-12-21 19:27:30 -0600750 static const char bars[] =
751 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
752 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
753 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
754 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
755 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
Behdad Esfahbod7235f332013-06-10 14:39:51 -0400756 fprintf (stderr, "%2u %s" VRBAR "%s",
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200757 level,
Behdad Esfahboddf98ce52016-12-21 19:27:30 -0600758 bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
Behdad Esfahbod6932a412012-06-26 10:46:31 -0400759 level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
Behdad Esfahbodd7bba012012-05-11 02:46:26 +0200760 } else
Behdad Esfahbod6932a412012-06-26 10:46:31 -0400761 fprintf (stderr, " " VRBAR LBAR);
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200762
Behdad Esfahbod5f541f82015-02-21 16:51:17 +0300763 _hb_print_func (func);
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200764
765 if (message)
Behdad Esfahbod5f541f82015-02-21 16:51:17 +0300766 {
767 fprintf (stderr, ": ");
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200768 vfprintf (stderr, message, ap);
Behdad Esfahbod5f541f82015-02-21 16:51:17 +0300769 }
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200770
771 fprintf (stderr, "\n");
Behdad Esfahbod20810972012-05-10 23:06:58 +0200772}
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200773template <> inline void
Behdad Esfahbod93345ed2012-05-13 16:01:08 +0200774_hb_debug_msg_va<0> (const char *what HB_UNUSED,
775 const void *obj HB_UNUSED,
776 const char *func HB_UNUSED,
777 bool indented HB_UNUSED,
778 unsigned int level HB_UNUSED,
779 int level_dir HB_UNUSED,
780 const char *message HB_UNUSED,
781 va_list ap HB_UNUSED) {}
Behdad Esfahbod20810972012-05-10 23:06:58 +0200782
Behdad Esfahbod2d1dcb32012-10-07 17:13:46 -0400783template <int max_level> static inline void
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400784_hb_debug_msg (const char *what,
785 const void *obj,
786 const char *func,
787 bool indented,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200788 unsigned int level,
789 int level_dir,
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400790 const char *message,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200791 ...) HB_PRINTF_FUNC(7, 8);
Behdad Esfahbod2d1dcb32012-10-07 17:13:46 -0400792template <int max_level> static inline void
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400793_hb_debug_msg (const char *what,
794 const void *obj,
795 const char *func,
796 bool indented,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200797 unsigned int level,
798 int level_dir,
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400799 const char *message,
800 ...)
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400801{
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400802 va_list ap;
803 va_start (ap, message);
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200804 _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400805 va_end (ap);
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400806}
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200807template <> inline void
Behdad Esfahbod93345ed2012-05-13 16:01:08 +0200808_hb_debug_msg<0> (const char *what HB_UNUSED,
809 const void *obj HB_UNUSED,
810 const char *func HB_UNUSED,
811 bool indented HB_UNUSED,
812 unsigned int level HB_UNUSED,
813 int level_dir HB_UNUSED,
814 const char *message HB_UNUSED,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200815 ...) HB_PRINTF_FUNC(7, 8);
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200816template <> inline void
Behdad Esfahbod93345ed2012-05-13 16:01:08 +0200817_hb_debug_msg<0> (const char *what HB_UNUSED,
818 const void *obj HB_UNUSED,
819 const char *func HB_UNUSED,
820 bool indented HB_UNUSED,
821 unsigned int level HB_UNUSED,
822 int level_dir HB_UNUSED,
823 const char *message HB_UNUSED,
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200824 ...) {}
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400825
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200826#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
827#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, false, 0, 0, __VA_ARGS__)
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400828#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400829
830
831/*
Behdad Esfahboddabe6982012-11-23 14:21:35 -0500832 * Printer
833 */
834
835template <typename T>
Behdad Esfahbod5c7d6f02014-12-12 20:28:49 -0800836struct hb_printer_t {
837 const char *print (const T&) { return "something"; }
838};
Behdad Esfahboddabe6982012-11-23 14:21:35 -0500839
840template <>
841struct hb_printer_t<bool> {
842 const char *print (bool v) { return v ? "true" : "false"; }
843};
844
845template <>
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500846struct hb_printer_t<hb_void_t> {
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500847 const char *print (hb_void_t) { return ""; }
Behdad Esfahboddabe6982012-11-23 14:21:35 -0500848};
849
850
851/*
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400852 * Trace
853 */
854
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500855template <typename T>
856static inline void _hb_warn_no_return (bool returned)
857{
858 if (unlikely (!returned)) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100859 fprintf (stderr, "OUCH, returned with no call to return_trace(). This is a bug, please report.\n");
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500860 }
861}
862template <>
Behdad Esfahbod6faff8e2014-04-28 14:29:39 -0700863/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500864{}
865
866template <int max_level, typename ret_t>
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400867struct hb_auto_trace_t {
868 explicit inline hb_auto_trace_t (unsigned int *plevel_,
Behdad Esfahbod96595232012-05-11 03:33:36 +0200869 const char *what_,
870 const void *obj_,
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400871 const char *func,
Behdad Esfahbod20810972012-05-10 23:06:58 +0200872 const char *message,
Behdad Esfahbod96595232012-05-11 03:33:36 +0200873 ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400874 {
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200875 if (plevel) ++*plevel;
Behdad Esfahbod20810972012-05-10 23:06:58 +0200876
877 va_list ap;
878 va_start (ap, message);
Behdad Esfahbod0594a242012-06-05 20:35:40 -0400879 _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
Behdad Esfahbod20810972012-05-10 23:06:58 +0200880 va_end (ap);
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400881 }
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200882 inline ~hb_auto_trace_t (void)
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200883 {
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500884 _hb_warn_no_return<ret_t> (returned);
885 if (!returned) {
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200886 _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " ");
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200887 }
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200888 if (plevel) --*plevel;
889 }
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400890
Behdad Esfahbod2c9d6482012-11-23 16:49:19 -0500891 inline ret_t ret (ret_t v, unsigned int line = 0)
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200892 {
893 if (unlikely (returned)) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100894 fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200895 return v;
896 }
897
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200898 _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1,
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500899 "return %s (line %d)",
900 hb_printer_t<ret_t>().print (v), line);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200901 if (plevel) --*plevel;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200902 plevel = nullptr;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200903 returned = true;
904 return v;
905 }
906
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400907 private:
908 unsigned int *plevel;
Behdad Esfahbod96595232012-05-11 03:33:36 +0200909 const char *what;
910 const void *obj;
Behdad Esfahbodc779d822012-11-23 14:07:24 -0500911 bool returned;
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400912};
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500913template <typename ret_t> /* Optimize when tracing is disabled */
914struct hb_auto_trace_t<0, ret_t> {
Behdad Esfahbod93345ed2012-05-13 16:01:08 +0200915 explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
916 const char *what HB_UNUSED,
917 const void *obj HB_UNUSED,
918 const char *func HB_UNUSED,
919 const char *message HB_UNUSED,
Behdad Esfahbod20810972012-05-10 23:06:58 +0200920 ...) {}
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200921
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500922 inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400923};
924
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100925#define return_trace(RET) return trace.ret (RET, __LINE__)
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400926
927/* Misc */
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400928
Behdad Esfahboda8b89a02014-07-11 14:18:01 -0400929template <typename T> class hb_assert_unsigned_t;
930template <> class hb_assert_unsigned_t<unsigned char> {};
Dominik Röttsches9e7c7202014-07-17 14:40:34 +0300931template <> class hb_assert_unsigned_t<unsigned short> {};
Behdad Esfahboda8b89a02014-07-11 14:18:01 -0400932template <> class hb_assert_unsigned_t<unsigned int> {};
933template <> class hb_assert_unsigned_t<unsigned long> {};
Behdad Esfahbodf60f2162010-04-21 02:12:45 -0400934
Behdad Esfahbodb5aeb952012-07-13 09:45:54 -0400935template <typename T> static inline bool
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -0400936hb_in_range (T u, T lo, T hi)
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -0400937{
Behdad Esfahbod385cf372014-07-17 18:22:07 -0400938 /* The sizeof() is here to force template instantiation.
939 * I'm sure there are better ways to do this but can't think of
940 * one right now. Declaring a variable won't work as HB_UNUSED
Behdad Esfahbod68e04af2015-02-21 16:30:28 +0300941 * is unusable on some platforms and unused types are less likely
Behdad Esfahbod385cf372014-07-17 18:22:07 -0400942 * to generate a warning than unused variables. */
Behdad Esfahbodc3448e82017-10-15 12:02:00 +0200943 static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
Behdad Esfahbod385cf372014-07-17 18:22:07 -0400944
Behdad Esfahbodc2b151d2014-08-10 18:52:07 -0400945 /* The casts below are important as if T is smaller than int,
946 * the subtract results will become a signed int! */
947 return (T)(u - lo) <= (T)(hi - lo);
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -0400948}
949
Behdad Esfahbod4a7f4f32012-07-23 13:15:33 -0400950template <typename T> static inline bool
Behdad Esfahbodc98b7182013-12-31 15:55:40 +0800951hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
952{
953 return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
954}
955
956template <typename T> static inline bool
Behdad Esfahbod093cd582012-07-23 14:04:42 -0400957hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
Behdad Esfahbod4a7f4f32012-07-23 13:15:33 -0400958{
Behdad Esfahbod093cd582012-07-23 14:04:42 -0400959 return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
Behdad Esfahbod4a7f4f32012-07-23 13:15:33 -0400960}
961
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -0400962
Behdad Esfahbodaa7044d2015-11-04 16:25:57 -0800963/* Enable bitwise ops on enums marked as flags_t */
Behdad Esfahbod69862082015-11-04 18:46:22 -0800964/* To my surprise, looks like the function resolver is happy to silently cast
965 * one enum to another... So this doesn't provide the type-checking that I
Behdad Esfahbode0082ae2015-11-17 18:42:13 -0800966 * originally had in mind... :(.
967 *
Behdad Esfahbodf94c0ec2015-11-20 13:21:29 -0800968 * For MSVC warnings, see: https://github.com/behdad/harfbuzz/pull/163
Behdad Esfahbode0082ae2015-11-17 18:42:13 -0800969 */
970#ifdef _MSC_VER
971# pragma warning(disable:4200)
972# pragma warning(disable:4800)
Chun-wei Fan167c3272015-11-09 17:17:56 +0800973#endif
Behdad Esfahbod1dc32ea2015-11-20 13:24:19 -0800974#define HB_MARK_AS_FLAG_T(T) \
975 extern "C++" { \
976 static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
977 static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
978 static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
979 static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
980 static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
981 static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
982 static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
983 }
Behdad Esfahbodaa7044d2015-11-04 16:25:57 -0800984
985
Behdad Esfahbod45d6f292011-07-30 14:44:30 -0400986/* Useful for set-operations on small enums.
987 * For example, for testing "x ∈ {x1, x2, x3}" use:
Behdad Esfahbodf8160a42015-07-21 15:50:02 +0100988 * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
Behdad Esfahbod45d6f292011-07-30 14:44:30 -0400989 */
Behdad Esfahbodf8160a42015-07-21 15:50:02 +0100990#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((x) < 32) + (1U << (x)))
991#define FLAG_SAFE(x) (1U << (x))
Behdad Esfahbod5b5617e2015-07-21 15:52:15 +0100992#define FLAG_UNSAFE(x) ((x) < 32 ? FLAG_SAFE(x) : 0)
Behdad Esfahbod2c372b82012-07-20 13:37:48 -0400993#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -0400994
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -0400995
Behdad Esfahbodc1e87442014-10-01 11:07:08 -0400996template <typename T, typename T2> static inline void
Behdad Esfahbod85846b32015-09-01 15:07:52 +0100997hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
Behdad Esfahbod45d6f292011-07-30 14:44:30 -0400998{
Behdad Esfahbod85846b32015-09-01 15:07:52 +0100999 for (unsigned int i = 1; i < len; i++)
1000 {
1001 unsigned int j = i;
1002 while (j && compar (&array[j - 1], &array[i]) > 0)
1003 j--;
1004 if (i == j)
1005 continue;
1006 /* Move item i to occupy place for item j, shift what's in between. */
1007 {
Behdad Esfahbod93099742015-09-01 16:11:27 +01001008 T t = array[i];
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001009 memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
1010 array[j] = t;
1011 }
1012 if (array2)
1013 {
Behdad Esfahbod93099742015-09-01 16:11:27 +01001014 T2 t = array2[i];
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001015 memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
1016 array2[j] = t;
1017 }
1018 }
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001019}
1020
Behdad Esfahbod250398b2014-10-01 11:28:01 -04001021template <typename T> static inline void
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001022hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
Behdad Esfahbod39b17832012-07-17 17:09:29 -04001023{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001024 hb_stable_sort (array, len, compar, (int *) nullptr);
Behdad Esfahbod39b17832012-07-17 17:09:29 -04001025}
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001026
Behdad Esfahbod6f3a3002012-08-07 22:13:25 -04001027static inline hb_bool_t
1028hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
1029{
1030 /* Pain because we don't know whether s is nul-terminated. */
1031 char buf[64];
Behdad Esfahbod847794e2013-02-27 17:59:28 -05001032 len = MIN (ARRAY_LENGTH (buf) - 1, len);
1033 strncpy (buf, s, len);
1034 buf[len] = '\0';
Behdad Esfahbod6f3a3002012-08-07 22:13:25 -04001035
1036 char *end;
1037 errno = 0;
1038 unsigned long v = strtoul (buf, &end, base);
1039 if (errno) return false;
1040 if (*end) return false;
1041 *out = v;
1042 return true;
1043}
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001044
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001045
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001046/* Global runtime options. */
1047
1048struct hb_options_t
1049{
Behdad Esfahbod5c871202014-10-14 20:07:31 -07001050 unsigned int initialized : 1;
1051 unsigned int uniscribe_bug_compatible : 1;
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001052};
1053
1054union hb_options_union_t {
Behdad Esfahbod5c871202014-10-14 20:07:31 -07001055 unsigned int i;
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001056 hb_options_t opts;
1057};
Behdad Esfahbodc3448e82017-10-15 12:02:00 +02001058static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001059
1060HB_INTERNAL void
1061_hb_options_init (void);
1062
1063extern HB_INTERNAL hb_options_union_t _hb_options;
1064
1065static inline hb_options_t
1066hb_options (void)
1067{
1068 if (unlikely (!_hb_options.i))
1069 _hb_options_init ();
1070
1071 return _hb_options.opts;
1072}
1073
Steven R. Loomisa13b0232015-12-11 10:21:27 -08001074/* Size signifying variable-sized array */
1075#define VAR 1
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001076
Behdad Esfahbodc57d4542011-04-20 18:50:27 -04001077#endif /* HB_PRIVATE_HH */