blob: c4fae17b642bb55e200cb5c4f11b1a333fa36873 [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
Ebrahim Byagowi5dbbd0f2018-01-11 12:33:22 +033032#define _GNU_SOURCE 1
33
Behdad Esfahbod5ddd9cc2011-09-16 16:40:44 -040034#ifdef HAVE_CONFIG_H
Behdad Esfahboddf660282009-08-01 20:46:02 -040035#include "config.h"
36#endif
Behdad Esfahbod12360f72008-01-23 15:50:38 -050037
Behdad Esfahbodd1c9eb42012-04-12 13:17:44 -040038#include "hb.h"
Behdad Esfahbodd1c9eb42012-04-12 13:17:44 -040039#define HB_H_IN
Behdad Esfahbod3e32cd92012-04-23 13:20:52 -040040#ifdef HAVE_OT
41#include "hb-ot.h"
Behdad Esfahbodd1c9eb42012-04-12 13:17:44 -040042#define HB_OT_H_IN
Behdad Esfahbod3e32cd92012-04-23 13:20:52 -040043#endif
Behdad Esfahbodb28815c2009-08-04 22:35:36 -040044
Behdad Esfahbod7cdd6ab2018-01-10 04:33:08 +010045#include <math.h>
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040046#include <stdlib.h>
Behdad Esfahbodb65c0602011-07-28 16:48:43 -040047#include <stddef.h>
Behdad Esfahbodf0954d12009-07-30 15:33:57 -040048#include <string.h>
49#include <assert.h>
Behdad Esfahbod7acb3892009-08-05 15:20:34 -040050#include <errno.h>
Behdad Esfahbod40ec3bb2017-11-03 16:57:30 -040051#include <stdio.h>
Behdad Esfahbodcc06c242011-07-25 20:25:44 -040052#include <stdarg.h>
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040053
Tor Andersson8f4c1232018-04-13 23:01:54 +043054#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
Arkady Shapkin6c103282018-02-15 23:17:46 +030055#include <intrin.h>
56#endif
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040057
Behdad Esfahbod2a749682017-10-26 19:48:33 -060058#define HB_PASTE1(a,b) a##b
59#define HB_PASTE(a,b) HB_PASTE1(a,b)
60
Behdad Esfahbod83ea2772018-07-10 13:17:27 +020061
Behdad Esfahbod52b41852015-10-03 13:20:55 +010062/* Compile-time custom allocator support. */
63
64#if defined(hb_malloc_impl) \
65 && defined(hb_calloc_impl) \
66 && defined(hb_realloc_impl) \
67 && defined(hb_free_impl)
Behdad Esfahbodcc6ea302015-10-12 17:21:52 -040068extern "C" void* hb_malloc_impl(size_t size);
69extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
70extern "C" void* hb_realloc_impl(void *ptr, size_t size);
71extern "C" void hb_free_impl(void *ptr);
Behdad Esfahbod52b41852015-10-03 13:20:55 +010072#define malloc hb_malloc_impl
73#define calloc hb_calloc_impl
74#define realloc hb_realloc_impl
75#define free hb_free_impl
Behdad Esfahbod83ea2772018-07-10 13:17:27 +020076
Behdad Esfahbod763f8782018-07-10 13:47:41 +020077#if defined(hb_memalign_impl)
Behdad Esfahbod83ea2772018-07-10 13:17:27 +020078extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size);
79#define posix_memalign hb_memalign_impl
80#else
81#undef HAVE_POSIX_MEMALIGN
82#endif
83
Behdad Esfahbod52b41852015-10-03 13:20:55 +010084#endif
85
86
Behdad Esfahbodae2b8542014-06-03 16:59:09 -040087/* Compiler attributes */
Behdad Esfahbodbc200452010-04-29 01:40:26 -040088
Behdad Esfahbodbc200452010-04-29 01:40:26 -040089
Behdad Esfahbod292c1002018-07-10 13:16:52 +020090template <typename T>
91struct _hb_alignof
92{
93 struct s
94 {
95 char c;
96 T t;
97 };
98 static constexpr unsigned int value = offsetof (s, t);
99};
100
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200101#if __cplusplus < 201103L
102
Behdad Esfahbod62e312e2017-10-27 09:29:20 -0600103#ifndef nullptr
104#define nullptr NULL
105#endif
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200106
Behdad Esfahbodbca83612018-07-10 12:58:13 +0200107#ifndef constexpr
108#define constexpr const
109#endif
110
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200111// Static assertions
112#ifndef static_assert
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200113#define static_assert(e, msg) \
Behdad Esfahbod6f08b122017-10-26 18:23:03 -0600114 HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200115#endif // static_assert
116
Behdad Esfahbodf83e9922018-05-24 11:46:57 -0700117#ifdef __GNUC__
118#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
119#define thread_local __thread
120#endif
121#else
122#define thread_local
123#endif
124
Behdad Esfahbodbca83612018-07-10 12:58:13 +0200125#ifndef alignof
Behdad Esfahbod27c53172018-07-10 13:03:42 +0200126#define alignof(x) (_hb_alignof<x>::value)
Behdad Esfahbodbca83612018-07-10 12:58:13 +0200127#endif // alignof
128
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200129#endif // __cplusplus < 201103L
130
Ebrahim Byagowi76c48732017-06-02 21:53:10 +0430131#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
132#define likely(expr) (__builtin_expect (!!(expr), 1))
133#define unlikely(expr) (__builtin_expect (!!(expr), 0))
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400134#else
135#define likely(expr) (expr)
136#define unlikely(expr) (expr)
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400137#endif
138
Steve Lhomme0b8f3ab2016-07-11 21:57:26 +0200139#if !defined(__GNUC__) && !defined(__clang__)
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400140#undef __attribute__
141#define __attribute__(x)
142#endif
Behdad Esfahboda794ebf2009-08-06 12:32:35 -0400143
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400144#if __GNUC__ >= 3
145#define HB_PURE_FUNC __attribute__((pure))
146#define HB_CONST_FUNC __attribute__((const))
147#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
148#else
149#define HB_PURE_FUNC
150#define HB_CONST_FUNC
151#define HB_PRINTF_FUNC(format_idx, arg_idx)
152#endif
153#if __GNUC__ >= 4
154#define HB_UNUSED __attribute__((unused))
Behdad Esfahbodbe59f3c2017-12-05 09:01:28 -0800155#elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */
156#define HB_UNUSED __pragma(warning(suppress: 4100 4101))
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400157#else
158#define HB_UNUSED
159#endif
160
161#ifndef HB_INTERNAL
Behdad Esfahbod90d1c742018-02-11 19:08:59 -0800162# if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC)
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400163# define HB_INTERNAL __attribute__((__visibility__("hidden")))
164# else
165# define HB_INTERNAL
Behdad Esfahbodb87cbe22018-02-07 14:11:26 -0500166# define HB_NO_VISIBILITY 1
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400167# endif
168#endif
169
Behdad Esfahbodae2b8542014-06-03 16:59:09 -0400170#if __GNUC__ >= 3
171#define HB_FUNC __PRETTY_FUNCTION__
172#elif defined(_MSC_VER)
173#define HB_FUNC __FUNCSIG__
174#else
175#define HB_FUNC __func__
176#endif
177
prrace498e4372018-06-09 16:04:28 -0700178#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5140)
Behdad Esfahbod8cef3a62018-02-09 16:04:23 -0600179/* https://github.com/harfbuzz/harfbuzz/issues/630 */
180#define __restrict
181#endif
182
Behdad Esfahbod305d2fb2015-10-21 11:04:28 -0200183/*
184 * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
185 * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
186 * cases that fall through without a break or return statement. HB_FALLTHROUGH
187 * is only needed on cases that have code:
188 *
189 * switch (foo) {
190 * case 1: // These cases have no code. No fallthrough annotations are needed.
191 * case 2:
192 * case 3:
193 * foo = 4; // This case has code, so a fallthrough annotation is needed:
194 * HB_FALLTHROUGH;
195 * default:
196 * return foo;
197 * }
198 */
199#if defined(__clang__) && __cplusplus >= 201103L
200 /* clang's fallthrough annotations are only available starting in C++11. */
201# define HB_FALLTHROUGH [[clang::fallthrough]]
Behdad Esfahbodf41b9212018-02-05 19:51:09 -0500202#elif __GNUC__ >= 7
203 /* GNU fallthrough attribute is available from GCC7 */
204# define HB_FALLTHROUGH __attribute__((fallthrough))
Behdad Esfahbod305d2fb2015-10-21 11:04:28 -0200205#elif defined(_MSC_VER)
206 /*
207 * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
208 * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
209 */
210# include <sal.h>
211# define HB_FALLTHROUGH __fallthrough
212#else
213# define HB_FALLTHROUGH /* FALLTHROUGH */
214#endif
215
Behdad Esfahbod0fc0a102014-07-21 11:12:54 -0400216#if defined(_WIN32) || defined(__CYGWIN__)
Behdad Esfahboddb308282014-07-19 16:32:04 -0400217 /* We need Windows Vista for both Uniscribe backend and for
218 * MemoryBarrier. We don't support compiling on Windows XP,
219 * though we run on it fine. */
220# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
221# undef _WIN32_WINNT
222# endif
223# ifndef _WIN32_WINNT
224# define _WIN32_WINNT 0x0600
225# endif
Behdad Esfahbod270971a2014-08-15 14:28:04 -0400226# ifndef WIN32_LEAN_AND_MEAN
227# define WIN32_LEAN_AND_MEAN 1
228# endif
229# ifndef STRICT
230# define STRICT 1
231# endif
Behdad Esfahboddabe6982012-11-23 14:21:35 -0500232
Konstantin Rittf3537b62015-01-25 09:50:51 +0400233# if defined(_WIN32_WCE)
234 /* Some things not defined on Windows CE. */
Konstantin Ritt50690622016-04-26 12:02:26 +0400235# define vsnprintf _vsnprintf
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200236# define getenv(Name) nullptr
Konstantin Ritt855a5d72015-04-10 17:18:01 +0400237# if _WIN32_WCE < 0x800
238# define setlocale(Category, Locale) "C"
Behdad Esfahbod26a963b2014-08-10 18:04:50 -0400239static int errno = 0; /* Use something better? */
Konstantin Ritt855a5d72015-04-10 17:18:01 +0400240# endif
Konstantin Rittf3537b62015-01-25 09:50:51 +0400241# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200242# define getenv(Name) nullptr
Konstantin Rittf3537b62015-01-25 09:50:51 +0400243# endif
Behdad Esfahbodce01ad72015-04-01 11:05:59 -0700244# if defined(_MSC_VER) && _MSC_VER < 1900
Konstantin Rittf3537b62015-01-25 09:50:51 +0400245# define snprintf _snprintf
Konstantin Rittf3537b62015-01-25 09:50:51 +0400246# endif
Behdad Esfahbod26a963b2014-08-10 18:04:50 -0400247#endif
248
Behdad Esfahbod38fb30d2014-08-06 13:34:49 -0400249#if HAVE_ATEXIT
250/* atexit() is only safe to be called from shared libraries on certain
251 * platforms. Whitelist.
252 * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
253# if defined(__linux) && defined(__GLIBC_PREREQ)
254# if __GLIBC_PREREQ(2,3)
255/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
256# define HB_USE_ATEXIT 1
257# endif
258# elif defined(_MSC_VER) || defined(__MINGW32__)
259/* For MSVC:
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +0430260 * https://msdn.microsoft.com/en-us/library/tze57ck3.aspx
261 * https://msdn.microsoft.com/en-us/library/zk17ww08.aspx
Behdad Esfahbod38fb30d2014-08-06 13:34:49 -0400262 * mingw32 headers say atexit is safe to use in shared libraries.
263 */
264# define HB_USE_ATEXIT 1
Ebrahim Byagowi632713b2018-04-12 14:17:03 +0430265# elif defined(__ANDROID__)
266/* This is available since Android NKD r8 or r8b:
267 * https://issuetracker.google.com/code/p/android/issues/detail?id=6455
Behdad Esfahbod38fb30d2014-08-06 13:34:49 -0400268 */
269# define HB_USE_ATEXIT 1
Bruce Mitchenere8859fc2018-02-04 01:26:57 +0700270# elif defined(__APPLE__)
271/* For macOS and related platforms, the atexit man page indicates
272 * that it will be invoked when the library is unloaded, not only
273 * at application exit.
274 */
275# define HB_USE_ATEXIT 1
Behdad Esfahbod38fb30d2014-08-06 13:34:49 -0400276# endif
277#endif
Behdad Esfahbodc14b24f2018-03-26 10:44:54 -0700278#ifdef HB_NO_ATEXIT
279# undef HB_USE_ATEXIT
280#endif
Behdad Esfahboddabe6982012-11-23 14:21:35 -0500281
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400282/* Basics */
283
284#undef MIN
Behdad Esfahbod25326c22012-08-04 16:43:18 -0700285template <typename Type>
286static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400287
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500288#undef MAX
Behdad Esfahbod25326c22012-08-04 16:43:18 -0700289template <typename Type>
290static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400291
Behdad Esfahbod16f175c2013-11-12 17:22:49 -0500292static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
293{ return (a + (b - 1)) / b; }
294
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -0500295
Behdad Esfahbod45917532009-11-04 18:15:59 -0500296#undef ARRAY_LENGTH
Behdad Esfahbod25326c22012-08-04 16:43:18 -0700297template <typename Type, unsigned int n>
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500298static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400299/* A const version, but does not detect erratically being called on pointers. */
300#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400301
Behdad Esfahbod35a73832009-08-01 19:30:31 -0400302#define HB_STMT_START do
303#define HB_STMT_END while (0)
Behdad Esfahbod5b3f7702006-12-28 06:42:37 -0500304
Behdad Esfahbod76dcbf82017-10-15 11:24:35 +0200305template <unsigned int cond> class hb_assert_constant_t;
306template <> class hb_assert_constant_t<1> {};
Behdad Esfahbod672ca3b2015-10-26 14:05:05 -0700307
308#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
Behdad Esfahboddcb70262011-04-21 16:34:22 -0400309
Behdad Esfahbod6fd53642011-04-11 11:47:14 -0400310/* Lets assert int types. Saves trouble down the road. */
311
Behdad Esfahbodc3448e82017-10-15 12:02:00 +0200312static_assert ((sizeof (int8_t) == 1), "");
313static_assert ((sizeof (uint8_t) == 1), "");
314static_assert ((sizeof (int16_t) == 2), "");
315static_assert ((sizeof (uint16_t) == 2), "");
316static_assert ((sizeof (int32_t) == 4), "");
317static_assert ((sizeof (uint32_t) == 4), "");
318static_assert ((sizeof (int64_t) == 8), "");
319static_assert ((sizeof (uint64_t) == 8), "");
Behdad Esfahbod6fd53642011-04-11 11:47:14 -0400320
Behdad Esfahbodc3448e82017-10-15 12:02:00 +0200321static_assert ((sizeof (hb_codepoint_t) == 4), "");
322static_assert ((sizeof (hb_position_t) == 4), "");
323static_assert ((sizeof (hb_mask_t) == 4), "");
324static_assert ((sizeof (hb_var_int_t) == 4), "");
Behdad Esfahbod6fd53642011-04-11 11:47:14 -0400325
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400326
327/* We like our types POD */
328
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400329#define _ASSERT_TYPE_POD1(_line, _type) union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; }
330#define _ASSERT_TYPE_POD0(_line, _type) _ASSERT_TYPE_POD1 (_line, _type)
331#define ASSERT_TYPE_POD(_type) _ASSERT_TYPE_POD0 (__LINE__, _type)
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400332
333#ifdef __GNUC__
Behdad Esfahbod79e2b472012-06-06 11:27:17 -0400334# define _ASSERT_INSTANCE_POD1(_line, _instance) \
335 HB_STMT_START { \
336 typedef __typeof__(_instance) _type_##_line; \
337 _ASSERT_TYPE_POD1 (_line, _type_##_line); \
338 } HB_STMT_END
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400339#else
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400340# define _ASSERT_INSTANCE_POD1(_line, _instance) typedef int _assertion_on_line_##_line##_not_tested
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400341#endif
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400342# define _ASSERT_INSTANCE_POD0(_line, _instance) _ASSERT_INSTANCE_POD1 (_line, _instance)
343# define ASSERT_INSTANCE_POD(_instance) _ASSERT_INSTANCE_POD0 (__LINE__, _instance)
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400344
345/* Check _assertion in a method environment */
346#define _ASSERT_POD1(_line) \
Behdad Esfahboddac86022014-06-03 17:57:00 -0400347 HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
Behdad Esfahbod73cb02d2012-06-06 11:29:25 -0400348 { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
349# define _ASSERT_POD0(_line) _ASSERT_POD1 (_line)
350# define ASSERT_POD() _ASSERT_POD0 (__LINE__)
Behdad Esfahboda00a63b2012-06-06 03:07:01 -0400351
352
353
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700354/* Tiny functions */
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400355
Behdad Esfahbodca42d962018-01-11 09:15:34 +0100356/*
357 * Void!
358 */
359typedef const struct _hb_void_t *hb_void_t;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200360#define HB_VOID ((const _hb_void_t *) nullptr)
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400361
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800362/* Return the number of 1 bits in v. */
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800363template <typename T>
Behdad Esfahbod97e7f8f2010-05-11 00:11:36 -0400364static inline HB_CONST_FUNC unsigned int
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800365_hb_popcount (T v)
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400366{
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800367#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800368 if (sizeof (T) <= sizeof (unsigned int))
369 return __builtin_popcount (v);
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800370
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800371 if (sizeof (T) <= sizeof (unsigned long))
372 return __builtin_popcountl (v);
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800373
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800374 if (sizeof (T) <= sizeof (unsigned long long))
375 return __builtin_popcountll (v);
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400376#endif
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800377
378 if (sizeof (T) <= 4)
379 {
380 /* "HACKMEM 169" */
381 uint32_t y;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800382 y = (v >> 1) &033333333333;
383 y = v - y - ((y >>1) & 033333333333);
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800384 return (((y + (y >> 3)) & 030707070707) % 077);
385 }
386
387 if (sizeof (T) == 8)
388 {
389 unsigned int shift = 32;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800390 return _hb_popcount<uint32_t> ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift));
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800391 }
392
393 if (sizeof (T) == 16)
394 {
395 unsigned int shift = 64;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800396 return _hb_popcount<uint64_t> ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift));
Behdad Esfahbod978ace62018-02-16 16:06:17 -0800397 }
398
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800399 assert (0);
Behdad Esfahbod676b19f2018-06-06 15:23:35 -0700400 return 0; /* Shut up stupid compiler. */
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400401}
402
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100403/* Returns the number of bits needed to store number */
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800404template <typename T>
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100405static inline HB_CONST_FUNC unsigned int
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800406_hb_bit_storage (T v)
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100407{
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800408 if (unlikely (!v)) return 0;
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800409
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100410#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800411 if (sizeof (T) <= sizeof (unsigned int))
412 return sizeof (unsigned int) * 8 - __builtin_clz (v);
413
414 if (sizeof (T) <= sizeof (unsigned long))
Behdad Esfahbod6a91a2e2018-02-16 17:49:41 -0800415 return sizeof (unsigned long) * 8 - __builtin_clzl (v);
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800416
417 if (sizeof (T) <= sizeof (unsigned long long))
Behdad Esfahbod6a91a2e2018-02-16 17:49:41 -0800418 return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800419#endif
420
Tor Andersson8f4c1232018-04-13 23:01:54 +0430421#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800422 if (sizeof (T) <= sizeof (unsigned int))
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800423 {
424 unsigned long where;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800425 _BitScanReverse (&where, v);
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800426 return 1 + where;
427 }
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800428# if _WIN64
429 if (sizeof (T) <= 8)
430 {
431 unsigned long where;
432 _BitScanReverse64 (&where, v);
433 return 1 + where;
434 }
435# endif
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800436#endif
437
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800438 if (sizeof (T) <= 4)
439 {
440 /* "bithacks" */
441 const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
442 const unsigned int S[] = {1, 2, 4, 8, 16};
Behdad Esfahbod4e517ec2018-02-16 18:20:12 -0800443 unsigned int r = 0;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800444 for (int i = 4; i >= 0; i--)
445 if (v & b[i])
446 {
447 v >>= S[i];
448 r |= S[i];
449 }
Behdad Esfahbod4e517ec2018-02-16 18:20:12 -0800450 return r + 1;
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100451 }
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800452 if (sizeof (T) <= 8)
453 {
454 /* "bithacks" */
Behdad Esfahbod7ec3ba22018-03-24 14:12:12 -0700455 const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800456 const unsigned int S[] = {1, 2, 4, 8, 16, 32};
Behdad Esfahbod4e517ec2018-02-16 18:20:12 -0800457 unsigned int r = 0;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800458 for (int i = 5; i >= 0; i--)
459 if (v & b[i])
460 {
461 v >>= S[i];
462 r |= S[i];
463 }
Behdad Esfahbod4e517ec2018-02-16 18:20:12 -0800464 return r + 1;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800465 }
466 if (sizeof (T) == 16)
467 {
468 unsigned int shift = 64;
Behdad Esfahbod78d92e02018-06-06 15:24:43 -0700469 return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800470 _hb_bit_storage<uint64_t> ((uint64_t) v);
471 }
472
473 assert (0);
Behdad Esfahbod676b19f2018-06-06 15:23:35 -0700474 return 0; /* Shut up stupid compiler. */
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100475}
Behdad Esfahboddf660282009-08-01 20:46:02 -0400476
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800477/* Returns the number of zero bits in the least significant side of v */
478template <typename T>
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100479static inline HB_CONST_FUNC unsigned int
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800480_hb_ctz (T v)
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100481{
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800482 if (unlikely (!v)) return 0;
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800483
484#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800485 if (sizeof (T) <= sizeof (unsigned int))
486 return __builtin_ctz (v);
487
488 if (sizeof (T) <= sizeof (unsigned long))
489 return __builtin_ctzl (v);
490
491 if (sizeof (T) <= sizeof (unsigned long long))
492 return __builtin_ctzll (v);
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800493#endif
494
Tor Andersson8f4c1232018-04-13 23:01:54 +0430495#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800496 if (sizeof (T) <= sizeof (unsigned int))
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800497 {
498 unsigned long where;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800499 _BitScanForward (&where, v);
Behdad Esfahbod97a71102018-02-18 10:50:24 -0800500 return where;
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800501 }
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800502# if _WIN64
503 if (sizeof (T) <= 8)
504 {
505 unsigned long where;
506 _BitScanForward64 (&where, v);
Behdad Esfahbod97a71102018-02-18 10:50:24 -0800507 return where;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800508 }
509# endif
Behdad Esfahbod864a2dd2018-02-16 14:21:40 -0800510#endif
511
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800512 if (sizeof (T) <= 4)
513 {
514 /* "bithacks" */
515 unsigned int c = 32;
Behdad Esfahbodcd111072018-02-16 18:28:58 -0800516 v &= - (int32_t) v;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800517 if (v) c--;
518 if (v & 0x0000FFFF) c -= 16;
519 if (v & 0x00FF00FF) c -= 8;
520 if (v & 0x0F0F0F0F) c -= 4;
521 if (v & 0x33333333) c -= 2;
522 if (v & 0x55555555) c -= 1;
523 return c;
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100524 }
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800525 if (sizeof (T) <= 8)
526 {
527 /* "bithacks" */
528 unsigned int c = 64;
Behdad Esfahbodcd111072018-02-16 18:28:58 -0800529 v &= - (int64_t) (v);
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800530 if (v) c--;
Behdad Esfahbodebccd012018-03-24 17:51:55 -0700531 if (v & 0x00000000FFFFFFFFULL) c -= 32;
532 if (v & 0x0000FFFF0000FFFFULL) c -= 16;
533 if (v & 0x00FF00FF00FF00FFULL) c -= 8;
534 if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
535 if (v & 0x3333333333333333ULL) c -= 2;
536 if (v & 0x5555555555555555ULL) c -= 1;
Behdad Esfahbod82eb1da2018-02-16 16:52:09 -0800537 return c;
538 }
539 if (sizeof (T) == 16)
540 {
541 unsigned int shift = 64;
542 return (uint64_t) v ? _hb_bit_storage<uint64_t> ((uint64_t) v) :
543 _hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift;
544 }
545
546 assert (0);
Behdad Esfahbod676b19f2018-06-06 15:23:35 -0700547 return 0; /* Shut up stupid compiler. */
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100548}
549
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400550static inline bool
551_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
552{
553 return (size > 0) && (count >= ((unsigned int) -1) / size);
554}
555
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600556static inline unsigned int
557_hb_ceil_to_4 (unsigned int v)
558{
Behdad Esfahbod931f8b72018-02-07 21:42:03 -0600559 return ((v - 1) | 3) + 1;
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600560}
561
Behdad Esfahbod83ea2772018-07-10 13:17:27 +0200562static inline bool _hb_ispow2 (unsigned int v)
563{
564 return 0 == (v & (v - 1));
565}
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400566
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400567
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700568/*
569 *
570 * Utility types
571 *
572 */
573
Behdad Esfahboda7dd90f2018-06-01 16:07:55 -0700574#define HB_DISALLOW_COPY_AND_ASSIGN(TypeName) \
Behdad Esfahbodfb07d1a2018-06-01 17:32:07 -0700575 TypeName(const TypeName&); \
576 void operator=(const TypeName&)
Behdad Esfahbod6c222762018-05-25 16:21:27 -0700577
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700578/*
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700579 * Static pools
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700580 */
581
582/* Global nul-content Null pool. Enlarge as necessary. */
583
Behdad Esfahbod4ca211b2018-06-01 17:18:57 -0700584#define HB_NULL_POOL_SIZE 264
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700585static_assert (HB_NULL_POOL_SIZE % sizeof (void *) == 0, "Align HB_NULL_POOL_SIZE.");
586
587#ifdef HB_NO_VISIBILITY
588static
589#else
590extern HB_INTERNAL
591#endif
Behdad Esfahbod7f7b1372018-05-24 14:09:04 -0700592void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)]
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700593#ifdef HB_NO_VISIBILITY
594= {}
595#endif
596;
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700597/* Generic nul-content Null objects. */
598template <typename Type>
Behdad Esfahbod7f7b1372018-05-24 14:09:04 -0700599static inline Type const & Null (void) {
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700600 static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
Behdad Esfahbod7f7b1372018-05-24 14:09:04 -0700601 return *reinterpret_cast<Type const *> (_hb_NullPool);
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700602}
603#define Null(Type) Null<Type>()
604
605/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
606#define DEFINE_NULL_DATA(Namespace, Type, data) \
607} /* Close namespace. */ \
608static const char _Null##Type[sizeof (Namespace::Type) + 1] = data; /* +1 is for nul-termination in data */ \
609template <> \
610/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
611 return *reinterpret_cast<const Namespace::Type *> (_Null##Type); \
612} \
613namespace Namespace { \
614/* The following line really exists such that we end in a place needing semicolon */ \
615static_assert (Namespace::Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small. Enlarge.")
616
617
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700618/* Global writable pool. Enlarge as necessary. */
619
Behdad Esfahbodf83e9922018-05-24 11:46:57 -0700620/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool
621 * for correct operation. It only exist to catch and divert program logic bugs instead of
622 * causing bad memory access. So, races there are not actually introducing incorrectness
Behdad Esfahbodefbab6b2018-05-29 18:21:55 -0700623 * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700624#ifdef HB_NO_VISIBILITY
625static
626#else
627extern HB_INTERNAL
628#endif
Behdad Esfahbodefbab6b2018-05-29 18:21:55 -0700629/*thread_local*/ void * _hb_CrapPool[HB_NULL_POOL_SIZE / sizeof (void *)]
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700630#ifdef HB_NO_VISIBILITY
631= {}
632#endif
633;
634/* CRAP pool: Common Region for Access Protection. */
635template <typename Type>
636static inline Type& Crap (void) {
637 static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
638 Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
639 *obj = Null(Type);
640 return *obj;
641}
642#define Crap(Type) Crap<Type>()
643
Behdad Esfahbodd600e842018-05-30 16:25:46 -0700644template <typename Type>
645struct CrapOrNull {
646 static inline Type & get (void) { return Crap(Type); }
647};
648template <typename Type>
649struct CrapOrNull<const Type> {
650 static inline Type const & get (void) { return Null(Type); }
651};
652#define CrapOrNull(Type) CrapOrNull<Type>::get ()
653
654
Behdad Esfahbod673b7642018-05-23 20:12:23 -0700655
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400656/* arrays and maps */
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400657
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400658
Behdad Esfahbod39f11d82018-07-10 14:01:39 +0200659#define HB_VECTOR_INIT {0, 0, false, nullptr}
Behdad Esfahbod975bdd52018-06-01 17:37:13 -0700660template <typename Type, unsigned int StaticSize=8>
Behdad Esfahbod5c3112a2018-05-01 19:07:04 -0400661struct hb_vector_t
Behdad Esfahbod0e253e92012-06-05 15:37:19 -0400662{
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400663 unsigned int len;
664 unsigned int allocated;
Behdad Esfahbod975bdd52018-06-01 17:37:13 -0700665 bool successful;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700666 Type *arrayZ;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400667 Type static_array[StaticSize];
668
Behdad Esfahbod56ef4e02017-10-15 16:38:29 -0400669 void init (void)
670 {
671 len = 0;
672 allocated = ARRAY_LENGTH (static_array);
Behdad Esfahbod975bdd52018-06-01 17:37:13 -0700673 successful = true;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700674 arrayZ = static_array;
Behdad Esfahbod56ef4e02017-10-15 16:38:29 -0400675 }
Behdad Esfahbodefde8112011-08-23 00:04:57 +0200676
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700677 inline Type& operator [] (unsigned int i)
678 {
679 if (unlikely (i >= len))
680 return Crap (Type);
681 return arrayZ[i];
682 }
683 inline const Type& operator [] (unsigned int i) const
684 {
685 if (unlikely (i >= len))
Behdad Esfahbod353f4d22018-05-31 19:52:16 -0700686 return Null(Type);
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700687 return arrayZ[i];
688 }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400689
690 inline Type *push (void)
691 {
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200692 if (unlikely (!resize (len + 1)))
Behdad Esfahbodf7515762018-06-01 17:48:37 -0700693 return &Crap(Type);
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700694 return &arrayZ[len - 1];
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200695 }
Behdad Esfahbod65aeabd2018-05-23 16:15:28 -0700696 inline Type *push (const Type& v)
697 {
Behdad Esfahbodf7515762018-06-01 17:48:37 -0700698 Type *p = push ();
699 *p = v;
700 return p;
Behdad Esfahbod65aeabd2018-05-23 16:15:28 -0700701 }
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200702
Behdad Esfahbodaf274502018-02-10 13:25:49 -0600703 /* Allocate for size but don't adjust len. */
Behdad Esfahbod65aeabd2018-05-23 16:15:28 -0700704 inline bool alloc (unsigned int size)
Rod Sheeter59c658c2018-02-08 19:22:47 -0800705 {
Behdad Esfahbod975bdd52018-06-01 17:37:13 -0700706 if (unlikely (!successful))
707 return false;
708
Behdad Esfahbodaf274502018-02-10 13:25:49 -0600709 if (likely (size <= allocated))
Rod Sheeter59c658c2018-02-08 19:22:47 -0800710 return true;
Behdad Esfahbodaf274502018-02-10 13:25:49 -0600711
712 /* Reallocate */
Rod Sheeter59c658c2018-02-08 19:22:47 -0800713
714 unsigned int new_allocated = allocated;
715 while (size >= new_allocated)
716 new_allocated += (new_allocated >> 1) + 8;
717
718 Type *new_array = nullptr;
719
Behdad Esfahbod1ab3c3e2018-06-01 17:34:24 -0700720 if (arrayZ == static_array)
721 {
Rod Sheeter59c658c2018-02-08 19:22:47 -0800722 new_array = (Type *) calloc (new_allocated, sizeof (Type));
723 if (new_array)
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700724 memcpy (new_array, arrayZ, len * sizeof (Type));
Behdad Esfahbod1ab3c3e2018-06-01 17:34:24 -0700725 }
726 else
727 {
Rod Sheeter59c658c2018-02-08 19:22:47 -0800728 bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
Behdad Esfahbod1ab3c3e2018-06-01 17:34:24 -0700729 if (likely (!overflows))
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700730 new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
Rod Sheeter59c658c2018-02-08 19:22:47 -0800731 }
732
733 if (unlikely (!new_array))
Behdad Esfahbod975bdd52018-06-01 17:37:13 -0700734 {
735 successful = false;
Rod Sheeter59c658c2018-02-08 19:22:47 -0800736 return false;
Behdad Esfahbod975bdd52018-06-01 17:37:13 -0700737 }
Rod Sheeter59c658c2018-02-08 19:22:47 -0800738
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700739 arrayZ = new_array;
Rod Sheeter48160642018-02-09 17:14:37 -0800740 allocated = new_allocated;
Behdad Esfahbodaf274502018-02-10 13:25:49 -0600741
Rod Sheeter48160642018-02-09 17:14:37 -0800742 return true;
Rod Sheeter59c658c2018-02-08 19:22:47 -0800743 }
744
Behdad Esfahbod31c42362018-05-24 13:38:46 -0700745 inline bool resize (int size_)
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200746 {
Behdad Esfahbod31c42362018-05-24 13:38:46 -0700747 unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
Behdad Esfahbodaf274502018-02-10 13:25:49 -0600748 if (!alloc (size))
Rod Sheeter59c658c2018-02-08 19:22:47 -0800749 return false;
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400750
Behdad Esfahbodc4d0d112018-06-11 22:11:45 -0400751 if (size > len)
752 memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
753
Behdad Esfahboddeed4a42017-10-15 16:53:09 +0200754 len = size;
755 return true;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400756 }
757
758 inline void pop (void)
759 {
Behdad Esfahbod31c42362018-05-24 13:38:46 -0700760 if (!len) return;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400761 len--;
Behdad Esfahbod639afdc2013-08-06 14:28:12 -0400762 }
763
764 inline void remove (unsigned int i)
765 {
766 if (unlikely (i >= len))
767 return;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700768 memmove (static_cast<void *> (&arrayZ[i]),
769 static_cast<void *> (&arrayZ[i + 1]),
Behdad Esfahbod639afdc2013-08-06 14:28:12 -0400770 (len - i - 1) * sizeof (Type));
771 len--;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400772 }
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400773
Behdad Esfahbod31c42362018-05-24 13:38:46 -0700774 inline void shrink (int size_)
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400775 {
Behdad Esfahbod31c42362018-05-24 13:38:46 -0700776 unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
777 if (size < len)
778 len = size;
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400779 }
780
Behdad Esfahbod68435692011-05-05 14:12:37 -0400781 template <typename T>
782 inline Type *find (T v) {
783 for (unsigned int i = 0; i < len; i++)
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700784 if (arrayZ[i] == v)
785 return &arrayZ[i];
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200786 return nullptr;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400787 }
788 template <typename T>
789 inline const Type *find (T v) const {
790 for (unsigned int i = 0; i < len; i++)
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700791 if (arrayZ[i] == v)
792 return &arrayZ[i];
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200793 return nullptr;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400794 }
795
Rod Sheeter59c658c2018-02-08 19:22:47 -0800796 inline void qsort (int (*cmp)(const void*, const void*))
797 {
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700798 ::qsort (arrayZ, len, sizeof (Type), cmp);
Rod Sheeter59c658c2018-02-08 19:22:47 -0800799 }
800
Behdad Esfahbodfb8cc862014-06-19 15:30:18 -0400801 inline void qsort (void)
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400802 {
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700803 ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400804 }
Behdad Esfahbod68435692011-05-05 14:12:37 -0400805
Behdad Esfahbodfb8cc862014-06-19 15:30:18 -0400806 inline void qsort (unsigned int start, unsigned int end)
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400807 {
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700808 ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400809 }
810
Behdad Esfahbod68435692011-05-05 14:12:37 -0400811 template <typename T>
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600812 inline Type *lsearch (const T &x)
Behdad Esfahbod6804b612018-02-07 13:47:35 -0500813 {
814 for (unsigned int i = 0; i < len; i++)
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700815 if (0 == this->arrayZ[i].cmp (&x))
816 return &arrayZ[i];
Behdad Esfahbod6804b612018-02-07 13:47:35 -0500817 return nullptr;
818 }
819
820 template <typename T>
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600821 inline Type *bsearch (const T &x)
Behdad Esfahbod68435692011-05-05 14:12:37 -0400822 {
Behdad Esfahbod5e740442017-10-15 16:15:06 +0200823 unsigned int i;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700824 return bfind (x, &i) ? &arrayZ[i] : nullptr;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400825 }
826 template <typename T>
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600827 inline const Type *bsearch (const T &x) const
Behdad Esfahbod68435692011-05-05 14:12:37 -0400828 {
Behdad Esfahbod5e740442017-10-15 16:15:06 +0200829 unsigned int i;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700830 return bfind (x, &i) ? &arrayZ[i] : nullptr;
Behdad Esfahbod5e740442017-10-15 16:15:06 +0200831 }
832 template <typename T>
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600833 inline bool bfind (const T &x, unsigned int *i) const
Behdad Esfahbod5e740442017-10-15 16:15:06 +0200834 {
Behdad Esfahboddb5f7ef2017-10-15 16:00:22 +0200835 int min = 0, max = (int) this->len - 1;
836 while (min <= max)
837 {
838 int mid = (min + max) / 2;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700839 int c = this->arrayZ[mid].cmp (&x);
Behdad Esfahboddb5f7ef2017-10-15 16:00:22 +0200840 if (c < 0)
841 max = mid - 1;
842 else if (c > 0)
843 min = mid + 1;
844 else
Behdad Esfahbod5e740442017-10-15 16:15:06 +0200845 {
846 *i = mid;
847 return true;
848 }
Behdad Esfahboddb5f7ef2017-10-15 16:00:22 +0200849 }
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700850 if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
Behdad Esfahbod5e740442017-10-15 16:15:06 +0200851 max++;
852 *i = max;
853 return false;
Behdad Esfahbod68435692011-05-05 14:12:37 -0400854 }
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400855
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400856 inline void fini (void)
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400857 {
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700858 if (arrayZ != static_array)
859 free (arrayZ);
860 arrayZ = nullptr;
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400861 allocated = len = 0;
862 }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400863};
864
Behdad Esfahbodc5d91f32013-03-09 04:34:21 -0500865template <typename Type>
Behdad Esfahbod4a01eb12018-05-01 19:05:58 -0400866struct hb_auto_t : Type
Behdad Esfahbodc5d91f32013-03-09 04:34:21 -0500867{
Behdad Esfahbod4a01eb12018-05-01 19:05:58 -0400868 hb_auto_t (void) { Type::init (); }
869 ~hb_auto_t (void) { Type::fini (); }
870 private: /* Hide */
871 void init (void) {}
872 void fini (void) {}
Behdad Esfahbodc5d91f32013-03-09 04:34:21 -0500873};
Behdad Esfahbod4a01eb12018-05-01 19:05:58 -0400874template <typename Type>
Behdad Esfahbod5c3112a2018-05-01 19:07:04 -0400875struct hb_auto_array_t : hb_auto_t <hb_vector_t <Type> > {};
Behdad Esfahbodc5d91f32013-03-09 04:34:21 -0500876
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400877
Behdad Esfahbod39f11d82018-07-10 14:01:39 +0200878#define HB_LOCKABLE_SET_INIT {HB_VECTOR_INIT}
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400879template <typename item_t, typename lock_t>
880struct hb_lockable_set_t
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400881{
Behdad Esfahbod5c3112a2018-05-01 19:07:04 -0400882 hb_vector_t <item_t, 1> items;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400883
Behdad Esfahbodbf93b632012-06-05 14:17:32 -0400884 inline void init (void) { items.init (); }
885
Behdad Esfahbod478a4252011-05-05 12:39:51 -0400886 template <typename T>
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200887 inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400888 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400889 l.lock ();
Behdad Esfahbod68435692011-05-05 14:12:37 -0400890 item_t *item = items.find (v);
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400891 if (item) {
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200892 if (replace) {
893 item_t old = *item;
894 *item = v;
895 l.unlock ();
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400896 old.fini ();
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200897 }
898 else {
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200899 item = nullptr;
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200900 l.unlock ();
901 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400902 } else {
Behdad Esfahbod65aeabd2018-05-23 16:15:28 -0700903 item = items.push (v);
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400904 l.unlock ();
905 }
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400906 return item;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400907 }
908
Behdad Esfahbod811482b2011-05-05 13:21:04 -0400909 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400910 inline void remove (T v, lock_t &l)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400911 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400912 l.lock ();
Behdad Esfahbod68435692011-05-05 14:12:37 -0400913 item_t *item = items.find (v);
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400914 if (item) {
915 item_t old = *item;
916 *item = items[items.len - 1];
917 items.pop ();
918 l.unlock ();
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400919 old.fini ();
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400920 } else {
921 l.unlock ();
922 }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400923 }
924
Behdad Esfahbod478a4252011-05-05 12:39:51 -0400925 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400926 inline bool find (T v, item_t *i, lock_t &l)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400927 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400928 l.lock ();
929 item_t *item = items.find (v);
930 if (item)
931 *i = *item;
932 l.unlock ();
933 return !!item;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400934 }
935
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400936 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400937 inline item_t *find_or_insert (T v, lock_t &l)
938 {
939 l.lock ();
940 item_t *item = items.find (v);
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400941 if (!item) {
Behdad Esfahbod65aeabd2018-05-23 16:15:28 -0700942 item = items.push (v);
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400943 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400944 l.unlock ();
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400945 return item;
946 }
947
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400948 inline void fini (lock_t &l)
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400949 {
Behdad Esfahbod3f4764b2012-07-30 10:06:42 -0400950 if (!items.len) {
951 /* No need for locking. */
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400952 items.fini ();
Behdad Esfahbod3f4764b2012-07-30 10:06:42 -0400953 return;
954 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400955 l.lock ();
956 while (items.len) {
957 item_t old = items[items.len - 1];
958 items.pop ();
959 l.unlock ();
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400960 old.fini ();
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400961 l.lock ();
962 }
Behdad Esfahboda60ba792018-05-01 19:01:25 -0400963 items.fini ();
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400964 l.unlock ();
965 }
966
967};
968
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400969
Behdad Esfahbod41880962011-04-11 14:58:28 -0400970/* ASCII tag/character handling */
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400971
Behdad Esfahbod20b817a2013-02-27 18:39:37 -0500972static inline bool ISALPHA (unsigned char c)
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400973{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
Behdad Esfahbod20b817a2013-02-27 18:39:37 -0500974static inline bool ISALNUM (unsigned char c)
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400975{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
Behdad Esfahbod20b817a2013-02-27 18:39:37 -0500976static inline bool ISSPACE (unsigned char c)
977{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400978static inline unsigned char TOUPPER (unsigned char c)
979{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
980static inline unsigned char TOLOWER (unsigned char c)
981{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400982
983
Behdad Esfahbod91dd1152016-02-25 13:56:47 +0900984/* HB_NDEBUG disables some sanity checks that are very safe to disable and
985 * should be disabled in production systems. If NDEBUG is defined, enable
986 * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
987 * light-weight) to be enabled, then HB_DEBUG can be defined to disable
988 * the costlier checks. */
989#ifdef NDEBUG
Behdad Esfahbodbd021a62018-05-08 01:50:30 -0700990#define HB_NDEBUG 1
Behdad Esfahbod91dd1152016-02-25 13:56:47 +0900991#endif
992
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400993
994/* Misc */
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400995
Behdad Esfahboda8b89a02014-07-11 14:18:01 -0400996template <typename T> class hb_assert_unsigned_t;
997template <> class hb_assert_unsigned_t<unsigned char> {};
Dominik Röttsches9e7c7202014-07-17 14:40:34 +0300998template <> class hb_assert_unsigned_t<unsigned short> {};
Behdad Esfahboda8b89a02014-07-11 14:18:01 -0400999template <> class hb_assert_unsigned_t<unsigned int> {};
1000template <> class hb_assert_unsigned_t<unsigned long> {};
Behdad Esfahbodf60f2162010-04-21 02:12:45 -04001001
Behdad Esfahbodb5aeb952012-07-13 09:45:54 -04001002template <typename T> static inline bool
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -04001003hb_in_range (T u, T lo, T hi)
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -04001004{
Behdad Esfahbod385cf372014-07-17 18:22:07 -04001005 /* The sizeof() is here to force template instantiation.
1006 * I'm sure there are better ways to do this but can't think of
1007 * one right now. Declaring a variable won't work as HB_UNUSED
Behdad Esfahbod68e04af2015-02-21 16:30:28 +03001008 * is unusable on some platforms and unused types are less likely
Behdad Esfahbod385cf372014-07-17 18:22:07 -04001009 * to generate a warning than unused variables. */
Behdad Esfahbodc3448e82017-10-15 12:02:00 +02001010 static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
Behdad Esfahbod385cf372014-07-17 18:22:07 -04001011
Behdad Esfahbodc2b151d2014-08-10 18:52:07 -04001012 /* The casts below are important as if T is smaller than int,
1013 * the subtract results will become a signed int! */
1014 return (T)(u - lo) <= (T)(hi - lo);
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -04001015}
1016
Behdad Esfahbod4a7f4f32012-07-23 13:15:33 -04001017template <typename T> static inline bool
Behdad Esfahbodc98b7182013-12-31 15:55:40 +08001018hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
1019{
1020 return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
1021}
1022
1023template <typename T> static inline bool
Behdad Esfahbod093cd582012-07-23 14:04:42 -04001024hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
Behdad Esfahbod4a7f4f32012-07-23 13:15:33 -04001025{
Behdad Esfahbod093cd582012-07-23 14:04:42 -04001026 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 -04001027}
1028
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -04001029
Behdad Esfahbodaa7044d2015-11-04 16:25:57 -08001030/* Enable bitwise ops on enums marked as flags_t */
Behdad Esfahbod69862082015-11-04 18:46:22 -08001031/* To my surprise, looks like the function resolver is happy to silently cast
1032 * one enum to another... So this doesn't provide the type-checking that I
Behdad Esfahbode0082ae2015-11-17 18:42:13 -08001033 * originally had in mind... :(.
1034 *
ebraminio7c6937e2017-11-20 14:49:22 -05001035 * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
Behdad Esfahbode0082ae2015-11-17 18:42:13 -08001036 */
1037#ifdef _MSC_VER
1038# pragma warning(disable:4200)
1039# pragma warning(disable:4800)
Chun-wei Fan167c3272015-11-09 17:17:56 +08001040#endif
Behdad Esfahbod1dc32ea2015-11-20 13:24:19 -08001041#define HB_MARK_AS_FLAG_T(T) \
1042 extern "C++" { \
1043 static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
1044 static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
1045 static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
1046 static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
1047 static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
1048 static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
1049 static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
1050 }
Behdad Esfahbodaa7044d2015-11-04 16:25:57 -08001051
1052
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001053/* Useful for set-operations on small enums.
1054 * For example, for testing "x ∈ {x1, x2, x3}" use:
Behdad Esfahbod6058f982017-10-19 11:39:52 -07001055 * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001056 */
Behdad Esfahbodd8adaa92017-10-20 13:57:43 -04001057#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned int)(x) < 32) + (1U << (unsigned int)(x)))
1058#define FLAG_UNSAFE(x) ((unsigned int)(x) < 32 ? (1U << (unsigned int)(x)) : 0)
Behdad Esfahbod2c372b82012-07-20 13:37:48 -04001059#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -04001060
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -04001061
Behdad Esfahbodc1e87442014-10-01 11:07:08 -04001062template <typename T, typename T2> static inline void
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001063hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001064{
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001065 for (unsigned int i = 1; i < len; i++)
1066 {
1067 unsigned int j = i;
1068 while (j && compar (&array[j - 1], &array[i]) > 0)
1069 j--;
1070 if (i == j)
1071 continue;
1072 /* Move item i to occupy place for item j, shift what's in between. */
1073 {
Behdad Esfahbod93099742015-09-01 16:11:27 +01001074 T t = array[i];
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001075 memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
1076 array[j] = t;
1077 }
1078 if (array2)
1079 {
Behdad Esfahbod93099742015-09-01 16:11:27 +01001080 T2 t = array2[i];
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001081 memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
1082 array2[j] = t;
1083 }
1084 }
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001085}
1086
Behdad Esfahbod250398b2014-10-01 11:28:01 -04001087template <typename T> static inline void
Behdad Esfahbod85846b32015-09-01 15:07:52 +01001088hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
Behdad Esfahbod39b17832012-07-17 17:09:29 -04001089{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001090 hb_stable_sort (array, len, compar, (int *) nullptr);
Behdad Esfahbod39b17832012-07-17 17:09:29 -04001091}
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001092
Behdad Esfahbod6f3a3002012-08-07 22:13:25 -04001093static inline hb_bool_t
1094hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
1095{
1096 /* Pain because we don't know whether s is nul-terminated. */
1097 char buf[64];
Behdad Esfahbod847794e2013-02-27 17:59:28 -05001098 len = MIN (ARRAY_LENGTH (buf) - 1, len);
1099 strncpy (buf, s, len);
1100 buf[len] = '\0';
Behdad Esfahbod6f3a3002012-08-07 22:13:25 -04001101
1102 char *end;
1103 errno = 0;
1104 unsigned long v = strtoul (buf, &end, base);
1105 if (errno) return false;
1106 if (*end) return false;
1107 *out = v;
1108 return true;
1109}
Behdad Esfahbod45d6f292011-07-30 14:44:30 -04001110
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001111
Behdad Esfahbod7737e872017-10-15 16:21:03 -04001112/* Vectorization */
1113
1114struct HbOpOr
1115{
1116 static const bool passthru_left = true;
1117 static const bool passthru_right = true;
1118 template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
1119};
1120struct HbOpAnd
1121{
1122 static const bool passthru_left = false;
1123 static const bool passthru_right = false;
1124 template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
1125};
1126struct HbOpMinus
1127{
1128 static const bool passthru_left = true;
1129 static const bool passthru_right = false;
1130 template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
1131};
1132struct HbOpXor
1133{
1134 static const bool passthru_left = true;
1135 static const bool passthru_right = true;
1136 template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
1137};
1138
Behdad Esfahbodb995b502018-05-22 21:06:22 -07001139
1140/* Compiler-assisted vectorization. */
1141
Behdad Esfahbod1ebaa092018-07-05 14:04:13 +04301142/*
1143 * Disable vectorization for now. To correctly use them, we should
1144 * use posix_memalign() to allocate them. Otherwise, can cause
1145 * misaligned access.
1146 *
1147 * https://bugs.chromium.org/p/chromium/issues/detail?id=860184
1148 */
1149#if !defined(HB_VECTOR_SIZE)
1150# define HB_VECTOR_SIZE 0
1151#endif
1152
1153
Behdad Esfahbodb995b502018-05-22 21:06:22 -07001154/* The `vector_size' attribute was introduced in gcc 3.1. */
Behdad Esfahbod058708a2018-07-05 13:16:00 +04301155#if !defined(HB_VECTOR_SIZE)
1156# if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
1157# define HB_VECTOR_SIZE 128
1158# else
1159# define HB_VECTOR_SIZE 0
1160# endif
Behdad Esfahbodb995b502018-05-22 21:06:22 -07001161#endif
1162
Behdad Esfahbod7737e872017-10-15 16:21:03 -04001163/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
1164template <typename elt_t, unsigned int byte_size>
1165struct hb_vector_size_t
1166{
Behdad Esfahbodf56a2502018-05-22 21:36:07 -07001167 elt_t& operator [] (unsigned int i) { return u.v[i]; }
1168 const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
Behdad Esfahbod7737e872017-10-15 16:21:03 -04001169
1170 template <class Op>
1171 inline hb_vector_size_t process (const hb_vector_size_t &o) const
1172 {
1173 hb_vector_size_t r;
Behdad Esfahbod6c818c52018-05-22 22:00:05 -07001174#if HB_VECTOR_SIZE
Behdad Esfahbodf56a2502018-05-22 21:36:07 -07001175 if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
1176 for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
1177 Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
Behdad Esfahbodb995b502018-05-22 21:06:22 -07001178 else
Behdad Esfahbodf56a2502018-05-22 21:36:07 -07001179#endif
1180 for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
1181 Op::process (r.u.v[i], u.v[i], o.u.v[i]);
Behdad Esfahbod7737e872017-10-15 16:21:03 -04001182 return r;
1183 }
1184 inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
1185 { return process<HbOpOr> (o); }
1186 inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
1187 { return process<HbOpAnd> (o); }
1188 inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
1189 { return process<HbOpXor> (o); }
1190 inline hb_vector_size_t operator ~ () const
1191 {
1192 hb_vector_size_t r;
Behdad Esfahbodf56a2502018-05-22 21:36:07 -07001193#if HB_VECTOR_SIZE && 0
1194 if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
1195 for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
1196 r.u.vec[i] = ~u.vec[i];
1197 else
1198#endif
1199 for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
1200 r.u.v[i] = ~u.v[i];
Behdad Esfahbod7737e872017-10-15 16:21:03 -04001201 return r;
1202 }
1203
1204 private:
Behdad Esfahbod221ce6c2017-10-15 17:58:58 -04001205 static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
Behdad Esfahbodb995b502018-05-22 21:06:22 -07001206 union {
1207 elt_t v[byte_size / sizeof (elt_t)];
Behdad Esfahbodf56a2502018-05-22 21:36:07 -07001208#if HB_VECTOR_SIZE
Behdad Esfahbod4ca211b2018-06-01 17:18:57 -07001209 typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
Behdad Esfahbodf56a2502018-05-22 21:36:07 -07001210 vec_t vec[byte_size / sizeof (vec_t)];
1211#endif
1212 } u;
Behdad Esfahbod7737e872017-10-15 16:21:03 -04001213};
1214
Behdad Esfahbod7737e872017-10-15 16:21:03 -04001215
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001216/* Global runtime options. */
1217
1218struct hb_options_t
1219{
Behdad Esfahbod5c871202014-10-14 20:07:31 -07001220 unsigned int initialized : 1;
1221 unsigned int uniscribe_bug_compatible : 1;
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001222};
1223
1224union hb_options_union_t {
Behdad Esfahbod5c871202014-10-14 20:07:31 -07001225 unsigned int i;
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001226 hb_options_t opts;
1227};
Behdad Esfahbodc3448e82017-10-15 12:02:00 +02001228static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001229
1230HB_INTERNAL void
1231_hb_options_init (void);
1232
1233extern HB_INTERNAL hb_options_union_t _hb_options;
1234
1235static inline hb_options_t
1236hb_options (void)
1237{
1238 if (unlikely (!_hb_options.i))
1239 _hb_options_init ();
1240
1241 return _hb_options.opts;
1242}
1243
Steven R. Loomisa13b0232015-12-11 10:21:27 -08001244/* Size signifying variable-sized array */
1245#define VAR 1
Behdad Esfahbodbab02d32013-02-12 15:26:45 -05001246
Behdad Esfahbode1a37f32017-10-30 11:42:28 -06001247
1248/* String type. */
1249
Behdad Esfahbod08e280f2018-05-08 01:57:27 -07001250struct hb_bytes_t
Behdad Esfahbode1a37f32017-10-30 11:42:28 -06001251{
Behdad Esfahbod08e280f2018-05-08 01:57:27 -07001252 inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
1253 inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
Behdad Esfahbode1a37f32017-10-30 11:42:28 -06001254
Behdad Esfahbod08e280f2018-05-08 01:57:27 -07001255 inline int cmp (const hb_bytes_t &a) const
Behdad Esfahbode1a37f32017-10-30 11:42:28 -06001256 {
Behdad Esfahbode35a7632017-10-30 13:15:05 -06001257 if (len != a.len)
1258 return (int) a.len - (int) len;
Behdad Esfahbode1a37f32017-10-30 11:42:28 -06001259
Behdad Esfahbode35a7632017-10-30 13:15:05 -06001260 return memcmp (a.bytes, bytes, len);
Behdad Esfahbode1a37f32017-10-30 11:42:28 -06001261 }
1262 static inline int cmp (const void *pa, const void *pb)
1263 {
Behdad Esfahbod08e280f2018-05-08 01:57:27 -07001264 hb_bytes_t *a = (hb_bytes_t *) pa;
1265 hb_bytes_t *b = (hb_bytes_t *) pb;
Behdad Esfahbode35a7632017-10-30 13:15:05 -06001266 return b->cmp (*a);
Behdad Esfahbode1a37f32017-10-30 11:42:28 -06001267 }
1268
1269 const char *bytes;
1270 unsigned int len;
1271};
1272
1273
Chun-wei Fan19256be2018-03-12 13:33:03 +08001274/* fallback for round() */
Chun-wei Fan19256be2018-03-12 13:33:03 +08001275static inline double
Behdad Esfahbod01dff1e2018-06-26 18:00:58 -04001276_hb_round (double x)
Chun-wei Fan19256be2018-03-12 13:33:03 +08001277{
1278 if (x >= 0)
1279 return floor (x + 0.5);
1280 else
1281 return ceil (x - 0.5);
1282}
Behdad Esfahbod292c1002018-07-10 13:16:52 +02001283#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
Behdad Esfahbod01dff1e2018-06-26 18:00:58 -04001284#define round(x) _hb_round(x)
Chun-wei Fan19256be2018-03-12 13:33:03 +08001285#endif
1286
1287
Behdad Esfahbod83ea2772018-07-10 13:17:27 +02001288/* fallback for posix_memalign() */
1289static inline int
1290_hb_memalign(void **memptr, size_t alignment, size_t size)
1291{
1292 if (unlikely (!_hb_ispow2 (alignment) ||
1293 !alignment ||
1294 0 != (alignment & (sizeof (void *) - 1))))
1295 return EINVAL;
1296
1297 char *p = (char *) malloc (size + alignment - 1);
1298 if (unlikely (!p))
1299 return ENOMEM;
1300
1301 size_t off = (size_t) p & (alignment - 1);
1302 if (off)
1303 p += alignment - off;
1304
1305 *memptr = (void *) p;
1306
1307 return 0;
1308}
1309#if !defined(posix_memalign) && !defined(HAVE_POSIX_MEMALIGN)
1310#define posix_memalign _hb_memalign
1311#endif
1312
1313
1314
Behdad Esfahbodc57d4542011-04-20 18:50:27 -04001315#endif /* HB_PRIVATE_HH */