blob: aa2ea9496b4357d1e8271048c5bb227eb5d0f7d9 [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 Esfahbodbc200452010-04-29 01:40:26 -040057
58/* Essentials */
59
60#ifndef NULL
61# define NULL ((void *) 0)
62#endif
63
64#undef FALSE
65#define FALSE 0
66
67#undef TRUE
68#define TRUE 1
Behdad Esfahboddf660282009-08-01 20:46:02 -040069
Behdad Esfahboda794ebf2009-08-06 12:32:35 -040070
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040071/* Basics */
72
Behdad Esfahbod153142d2011-04-27 01:49:03 -040073
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040074#undef MIN
Behdad Esfahbod153142d2011-04-27 01:49:03 -040075template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040076
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -050077#undef MAX
Behdad Esfahbod153142d2011-04-27 01:49:03 -040078template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
79
Behdad Esfahbod8a3511a2009-11-04 19:45:39 -050080
Behdad Esfahbod45917532009-11-04 18:15:59 -050081#undef ARRAY_LENGTH
82#define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -040083
Behdad Esfahbod35a73832009-08-01 19:30:31 -040084#define HB_STMT_START do
85#define HB_STMT_END while (0)
Behdad Esfahbod5b3f7702006-12-28 06:42:37 -050086
Behdad Esfahbod303fe622008-01-23 00:20:48 -050087#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
88#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
89#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
90
Behdad Esfahboddcb70262011-04-21 16:34:22 -040091#define ASSERT_STATIC_EXPR(_cond) ((void) sizeof (char[(_cond) ? 1 : -1]))
Behdad Esfahbod4ec30ae2011-06-28 14:13:38 -040092#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
Behdad Esfahboddcb70262011-04-21 16:34:22 -040093
Behdad Esfahbodbc200452010-04-29 01:40:26 -040094
Behdad Esfahbod6fd53642011-04-11 11:47:14 -040095/* Lets assert int types. Saves trouble down the road. */
96
97ASSERT_STATIC (sizeof (int8_t) == 1);
98ASSERT_STATIC (sizeof (uint8_t) == 1);
99ASSERT_STATIC (sizeof (int16_t) == 2);
100ASSERT_STATIC (sizeof (uint16_t) == 2);
101ASSERT_STATIC (sizeof (int32_t) == 4);
102ASSERT_STATIC (sizeof (uint32_t) == 4);
103ASSERT_STATIC (sizeof (int64_t) == 8);
104ASSERT_STATIC (sizeof (uint64_t) == 8);
105
Behdad Esfahbodb13640d2011-04-11 12:29:31 -0400106ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
107ASSERT_STATIC (sizeof (hb_position_t) == 4);
108ASSERT_STATIC (sizeof (hb_mask_t) == 4);
Behdad Esfahbodae9eeaf2011-04-11 11:49:08 -0400109ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
Behdad Esfahbod6fd53642011-04-11 11:47:14 -0400110
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400111/* Misc */
112
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400113
Behdad Esfahboddf660282009-08-01 20:46:02 -0400114#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
Behdad Esfahbod494d28a2010-05-10 23:50:07 -0400115#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400116#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
117#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
Behdad Esfahboddf660282009-08-01 20:46:02 -0400118#else
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400119#define likely(expr) (expr)
120#define unlikely(expr) (expr)
Behdad Esfahboddf660282009-08-01 20:46:02 -0400121#endif
122
123#ifndef __GNUC__
124#undef __attribute__
125#define __attribute__(x)
126#endif
127
128#if __GNUC__ >= 3
Behdad Esfahbod33d13fd2010-04-29 13:56:44 -0400129#define HB_PURE_FUNC __attribute__((pure))
130#define HB_CONST_FUNC __attribute__((const))
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400131#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
Behdad Esfahboddf660282009-08-01 20:46:02 -0400132#else
Behdad Esfahbod33d13fd2010-04-29 13:56:44 -0400133#define HB_PURE_FUNC
134#define HB_CONST_FUNC
Behdad Esfahbod44b4f502011-08-04 00:52:20 -0400135#define HB_PRINTF_FUNC(format_idx, arg_idx)
Behdad Esfahboddf660282009-08-01 20:46:02 -0400136#endif
Behdad Esfahbodbc7830e2010-02-17 15:14:57 -0500137#if __GNUC__ >= 4
Behdad Esfahbod33d13fd2010-04-29 13:56:44 -0400138#define HB_UNUSED __attribute__((unused))
Behdad Esfahbodbc7830e2010-02-17 15:14:57 -0500139#else
Behdad Esfahbod33d13fd2010-04-29 13:56:44 -0400140#define HB_UNUSED
Behdad Esfahbodbc7830e2010-02-17 15:14:57 -0500141#endif
Behdad Esfahboddf660282009-08-01 20:46:02 -0400142
Behdad Esfahbodeee85982010-05-12 23:22:55 -0400143#ifndef HB_INTERNAL
Behdad Esfahbodf60271c2011-08-02 09:56:30 -0400144# ifndef __MINGW32__
145# define HB_INTERNAL __attribute__((__visibility__("hidden")))
146# else
147# define HB_INTERNAL
148# endif
Behdad Esfahbodeee85982010-05-12 23:22:55 -0400149#endif
150
Behdad Esfahboddf660282009-08-01 20:46:02 -0400151
152#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
153#define snprintf _snprintf
154#endif
155
156#ifdef _MSC_VER
157#undef inline
158#define inline __inline
159#endif
160
161#ifdef __STRICT_ANSI__
162#undef inline
163#define inline __inline__
164#endif
165
166
Behdad Esfahbod7d3a1262010-04-29 13:54:01 -0400167#if __GNUC__ >= 3
168#define HB_FUNC __PRETTY_FUNCTION__
169#elif defined(_MSC_VER)
170#define HB_FUNC __FUNCSIG__
171#else
172#define HB_FUNC __func__
173#endif
174
175
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100176/* Return the number of 1 bits in mask. */
Behdad Esfahbod97e7f8f2010-05-11 00:11:36 -0400177static inline HB_CONST_FUNC unsigned int
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400178_hb_popcount32 (uint32_t mask)
179{
180#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100181 return __builtin_popcount (mask);
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400182#else
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100183 /* "HACKMEM 169" */
184 register uint32_t y;
185 y = (mask >> 1) &033333333333;
186 y = mask - y - ((y >>1) & 033333333333);
187 return (((y + (y >> 3)) & 030707070707) % 077);
Behdad Esfahbodc7d457a2009-05-21 12:46:29 -0400188#endif
189}
190
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100191/* Returns the number of bits needed to store number */
192static inline HB_CONST_FUNC unsigned int
193_hb_bit_storage (unsigned int number)
194{
195#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100196 return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
Behdad Esfahbod9b602332010-05-20 15:31:12 +0100197#else
198 register unsigned int n_bits = 0;
199 while (number) {
200 n_bits++;
201 number >>= 1;
202 }
203 return n_bits;
204#endif
205}
Behdad Esfahboddf660282009-08-01 20:46:02 -0400206
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100207/* Returns the number of zero bits in the least significant side of number */
208static inline HB_CONST_FUNC unsigned int
209_hb_ctz (unsigned int number)
210{
211#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
212 return likely (number) ? __builtin_ctz (number) : 0;
213#else
214 register unsigned int n_bits = 0;
215 if (unlikely (!number)) return 0;
216 while (!(number & 1)) {
217 n_bits++;
218 number >>= 1;
219 }
220 return n_bits;
221#endif
222}
223
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400224static inline bool
225_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
226{
227 return (size > 0) && (count >= ((unsigned int) -1) / size);
228}
229
230
Behdad Esfahbod8f08c322010-10-08 19:43:48 -0400231/* Type of bsearch() / qsort() compare function */
232typedef int (*hb_compare_func_t) (const void *, const void *);
233
234
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400235
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400236
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400237/* arrays and maps */
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400238
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400239
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400240template <typename Type, unsigned int StaticSize>
Behdad Esfahbodb214ec32011-05-05 13:24:07 -0400241struct hb_prealloced_array_t {
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400242
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400243 unsigned int len;
244 unsigned int allocated;
245 Type *array;
246 Type static_array[StaticSize];
247
Behdad Esfahbodefde8112011-08-23 00:04:57 +0200248 hb_prealloced_array_t (void) { memset (this, 0, sizeof (*this)); }
249
Behdad Esfahbod265ac612011-05-05 14:38:16 -0400250 inline Type& operator [] (unsigned int i) { return array[i]; }
251 inline const Type& operator [] (unsigned int i) const { return array[i]; }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400252
253 inline Type *push (void)
254 {
255 if (!array) {
256 array = static_array;
257 allocated = ARRAY_LENGTH (static_array);
258 }
259 if (likely (len < allocated))
260 return &array[len++];
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400261
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400262 /* Need to reallocate */
263 unsigned int new_allocated = allocated + (allocated >> 1) + 8;
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400264 Type *new_array = NULL;
265
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400266 if (array == static_array) {
267 new_array = (Type *) calloc (new_allocated, sizeof (Type));
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400268 if (new_array)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400269 memcpy (new_array, array, len * sizeof (Type));
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400270 } else {
Behdad Esfahbod080a0eb2011-04-28 16:01:01 -0400271 bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400272 if (likely (!overflows)) {
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400273 new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400274 }
275 }
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400276
277 if (unlikely (!new_array))
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400278 return NULL;
Behdad Esfahbod5a503032011-05-02 19:54:29 -0400279
280 array = new_array;
281 allocated = new_allocated;
282 return &array[len++];
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400283 }
284
285 inline void pop (void)
286 {
287 len--;
288 /* TODO: shrink array if needed */
289 }
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400290
291 inline void shrink (unsigned int l)
292 {
293 if (l < len)
294 len = l;
295 /* TODO: shrink array if needed */
296 }
297
Behdad Esfahbod68435692011-05-05 14:12:37 -0400298 template <typename T>
299 inline Type *find (T v) {
300 for (unsigned int i = 0; i < len; i++)
301 if (array[i] == v)
302 return &array[i];
303 return NULL;
304 }
305 template <typename T>
306 inline const Type *find (T v) const {
307 for (unsigned int i = 0; i < len; i++)
308 if (array[i] == v)
309 return &array[i];
310 return NULL;
311 }
312
Behdad Esfahbod44b0a4d2011-05-05 13:42:19 -0400313 inline void sort (void)
314 {
315 qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
316 }
Behdad Esfahbod68435692011-05-05 14:12:37 -0400317
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400318 inline void sort (unsigned int start, unsigned int end)
319 {
320 qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
321 }
322
Behdad Esfahbod68435692011-05-05 14:12:37 -0400323 template <typename T>
324 inline Type *bsearch (T *key)
325 {
326 return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
327 }
328 template <typename T>
329 inline const Type *bsearch (T *key) const
330 {
331 return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
332 }
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400333
334 inline void finish (void)
335 {
336 if (array != static_array)
337 free (array);
338 array = NULL;
339 allocated = len = 0;
340 }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400341};
342
343template <typename Type>
Behdad Esfahbodb214ec32011-05-05 13:24:07 -0400344struct hb_array_t : hb_prealloced_array_t<Type, 2> {};
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400345
346
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400347template <typename item_t, typename lock_t>
348struct hb_lockable_set_t
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400349{
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400350 hb_array_t <item_t> items;
351
Behdad Esfahbod478a4252011-05-05 12:39:51 -0400352 template <typename T>
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200353 inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400354 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400355 l.lock ();
Behdad Esfahbod68435692011-05-05 14:12:37 -0400356 item_t *item = items.find (v);
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400357 if (item) {
Behdad Esfahbod33ccc772011-08-09 00:43:24 +0200358 if (replace) {
359 item_t old = *item;
360 *item = v;
361 l.unlock ();
362 old.finish ();
363 }
364 else {
365 item = NULL;
366 l.unlock ();
367 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400368 } else {
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400369 item = items.push ();
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400370 if (likely (item))
371 *item = v;
372 l.unlock ();
373 }
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400374 return item;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400375 }
376
Behdad Esfahbod811482b2011-05-05 13:21:04 -0400377 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400378 inline void remove (T v, lock_t &l)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400379 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400380 l.lock ();
Behdad Esfahbod68435692011-05-05 14:12:37 -0400381 item_t *item = items.find (v);
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400382 if (item) {
383 item_t old = *item;
384 *item = items[items.len - 1];
385 items.pop ();
386 l.unlock ();
387 old.finish ();
388 } else {
389 l.unlock ();
390 }
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400391 }
392
Behdad Esfahbod478a4252011-05-05 12:39:51 -0400393 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400394 inline bool find (T v, item_t *i, lock_t &l)
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400395 {
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400396 l.lock ();
397 item_t *item = items.find (v);
398 if (item)
399 *i = *item;
400 l.unlock ();
401 return !!item;
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400402 }
403
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400404 template <typename T>
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400405 inline item_t *find_or_insert (T v, lock_t &l)
406 {
407 l.lock ();
408 item_t *item = items.find (v);
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400409 if (!item) {
410 item = items.push ();
411 if (likely (item))
412 *item = v;
413 }
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400414 l.unlock ();
Behdad Esfahbodb45f32e2011-05-05 15:00:43 -0400415 return item;
416 }
417
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400418 inline void finish (lock_t &l)
419 {
420 l.lock ();
421 while (items.len) {
422 item_t old = items[items.len - 1];
423 items.pop ();
424 l.unlock ();
425 old.finish ();
426 l.lock ();
427 }
Behdad Esfahbod6a7ac792011-05-11 14:19:18 -0400428 items.finish ();
Behdad Esfahbod45bfa992011-05-10 19:12:49 -0400429 l.unlock ();
430 }
431
432};
433
Behdad Esfahbod852e08e2011-04-27 21:45:51 -0400434
Behdad Esfahboda9f24c82011-04-21 17:18:22 -0400435
436
Behdad Esfahbodf60f2162010-04-21 02:12:45 -0400437/* Big-endian handling */
438
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400439static inline uint16_t hb_be_uint16 (const uint16_t v)
440{
441 const uint8_t *V = (const uint8_t *) &v;
442 return (uint16_t) (V[0] << 8) + V[1];
443}
Behdad Esfahbodf60f2162010-04-21 02:12:45 -0400444
Behdad Esfahbode74616b2012-04-15 14:12:13 -0400445/* Note, of the following macros, uint16_get is the one called many many times.
446 * If there is any optimizations to be done, it's in that macro. However, I
447 * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
448 * results in a single ror instruction, does NOT speed this up. In fact, it
449 * resulted in a minor slowdown. At any rate, note that v may not be correctly
450 * aligned, so I think the current implementation is optimal.
451 */
452
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400453#define hb_be_uint16_put(v,V) HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
Behdad Esfahbod7a52f282010-04-21 02:14:44 -0400454#define hb_be_uint16_get(v) (uint16_t) ((v[0] << 8) + v[1])
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400455#define hb_be_uint16_eq(a,b) (a[0] == b[0] && a[1] == b[1])
Behdad Esfahbodf60f2162010-04-21 02:12:45 -0400456
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400457#define hb_be_uint32_put(v,V) HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END
Behdad Esfahbod7a52f282010-04-21 02:14:44 -0400458#define hb_be_uint32_get(v) (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400459#define hb_be_uint32_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
Behdad Esfahbodf60f2162010-04-21 02:12:45 -0400460
461
Behdad Esfahbod41880962011-04-11 14:58:28 -0400462/* ASCII tag/character handling */
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400463
Behdad Esfahbod153142d2011-04-27 01:49:03 -0400464static inline unsigned char ISALPHA (unsigned char c)
465{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
466static inline unsigned char ISALNUM (unsigned char c)
467{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
468static inline unsigned char TOUPPER (unsigned char c)
469{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
470static inline unsigned char TOLOWER (unsigned char c)
471{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400472
Behdad Esfahbod41880962011-04-11 14:58:28 -0400473#define HB_TAG_CHAR4(s) (HB_TAG(((const char *) s)[0], \
474 ((const char *) s)[1], \
475 ((const char *) s)[2], \
476 ((const char *) s)[3]))
477
Behdad Esfahboddb5227c2011-04-11 13:16:08 -0400478
Behdad Esfahbod831886a2011-05-11 21:27:52 -0400479/* C++ helpers */
480
481/* Makes class uncopyable. Use in private: section. */
482#define NO_COPY(T) \
483 T (const T &o); \
Behdad Esfahbod970e0922011-06-14 14:35:44 -0400484 T &operator = (const T &o)
Behdad Esfahbod831886a2011-05-11 21:27:52 -0400485
486
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400487/* Debug */
488
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400489
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400490#ifndef HB_DEBUG
491#define HB_DEBUG 0
492#endif
493
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400494static inline bool
495_hb_debug (unsigned int level,
496 unsigned int max_level)
497{
498 return level < max_level;
499}
500
501#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
Behdad Esfahbod43ff2032011-07-25 17:35:24 -0400502#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))
503
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200504template <int max_level> inline void
Behdad Esfahbod20810972012-05-10 23:06:58 +0200505_hb_debug_msg_va (const char *what,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200506 const void *obj,
507 const char *func,
508 bool indented,
509 unsigned int level,
510 int level_dir,
511 const char *message,
512 va_list ap)
Behdad Esfahbod20810972012-05-10 23:06:58 +0200513{
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200514 if (!_hb_debug (level, max_level))
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200515 return;
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200516
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200517 fprintf (stderr, "%-10s", what ? what : "");
518
519 if (obj)
Behdad Esfahbod5ccfe8e2012-05-11 02:19:41 +0200520 fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200521 else
522 fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
523
Behdad Esfahbodd7bba012012-05-11 02:46:26 +0200524 if (indented) {
525 static const char bars[] = "││││││││││││││││││││││││││││││││││││││││";
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200526 fprintf (stderr, "%2d %s├%s",
527 level,
528 bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), 3 * level),
529 level_dir ? (level_dir > 0 ? "╮" : "╯") : "╴");
Behdad Esfahbodd7bba012012-05-11 02:46:26 +0200530 } else
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200531 fprintf (stderr, " ├╴");
532
Behdad Esfahbod85f73fa2012-05-11 02:40:42 +0200533 if (func) {
534 /* If there's a class name, just write that. */
535 const char *dotdot = strstr (func, "::");
Behdad Esfahbodd7bba012012-05-11 02:46:26 +0200536 const char *space = strchr (func, ' ');
537 if (space && dotdot && space < dotdot)
538 func = space + 1;
Behdad Esfahbod85f73fa2012-05-11 02:40:42 +0200539 unsigned int func_len = dotdot ? dotdot - func : strlen (func);
Behdad Esfahbodd7bba012012-05-11 02:46:26 +0200540 fprintf (stderr, "%.*s: ", func_len, func);
Behdad Esfahbod85f73fa2012-05-11 02:40:42 +0200541 }
Behdad Esfahbod6eec6f42012-05-11 00:50:38 +0200542
543 if (message)
544 vfprintf (stderr, message, ap);
545
546 fprintf (stderr, "\n");
Behdad Esfahbod20810972012-05-10 23:06:58 +0200547}
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200548template <> inline void
Behdad Esfahbod20810972012-05-10 23:06:58 +0200549_hb_debug_msg_va<0> (const char *what,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200550 const void *obj,
551 const char *func,
552 bool indented,
553 unsigned int level,
554 int level_dir,
555 const char *message,
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200556 va_list ap) {}
Behdad Esfahbod20810972012-05-10 23:06:58 +0200557
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200558template <int max_level> inline void
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400559_hb_debug_msg (const char *what,
560 const void *obj,
561 const char *func,
562 bool indented,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200563 unsigned int level,
564 int level_dir,
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400565 const char *message,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200566 ...) HB_PRINTF_FUNC(7, 8);
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200567template <int max_level> inline void
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400568_hb_debug_msg (const char *what,
569 const void *obj,
570 const char *func,
571 bool indented,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200572 unsigned int level,
573 int level_dir,
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400574 const char *message,
575 ...)
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400576{
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400577 va_list ap;
578 va_start (ap, message);
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200579 _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400580 va_end (ap);
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400581}
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200582template <> inline void
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400583_hb_debug_msg<0> (const char *what,
584 const void *obj,
585 const char *func,
586 bool indented,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200587 unsigned int level,
588 int level_dir,
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400589 const char *message,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200590 ...) HB_PRINTF_FUNC(7, 8);
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200591template <> inline void
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400592_hb_debug_msg<0> (const char *what,
593 const void *obj,
594 const char *func,
595 bool indented,
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200596 unsigned int level,
597 int level_dir,
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400598 const char *message,
Behdad Esfahbod829e8142012-05-11 00:52:16 +0200599 ...) {}
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400600
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200601#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, TRUE, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
602#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, FALSE, 0, 0, __VA_ARGS__)
603#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 -0400604
605
606/*
607 * Trace
608 */
609
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200610template <int max_level>
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400611struct hb_auto_trace_t {
612 explicit inline hb_auto_trace_t (unsigned int *plevel_,
613 const char *what,
614 const void *obj,
615 const char *func,
Behdad Esfahbod20810972012-05-10 23:06:58 +0200616 const char *message,
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200617 ...) : plevel(plevel_), returned (false)
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400618 {
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200619 if (plevel) ++*plevel;
Behdad Esfahbod20810972012-05-10 23:06:58 +0200620
621 va_list ap;
622 va_start (ap, message);
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200623 _hb_debug_msg_va<max_level> (what, obj, func, TRUE, plevel ? *plevel : 0, +1, message, ap);
Behdad Esfahbod20810972012-05-10 23:06:58 +0200624 va_end (ap);
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400625 }
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200626 inline ~hb_auto_trace_t (void)
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200627 {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200628 if (unlikely (!returned)) {
629 fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN. This is a bug, please report. Level was %d.\n", plevel ? *plevel : -1);
630 _hb_debug_msg<max_level> (NULL, NULL, NULL, TRUE, plevel ? *plevel : 1, -1, " ");
631 return;
632 }
Behdad Esfahbod1e088302012-05-11 00:16:40 +0200633
634 if (plevel) --*plevel;
635 }
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400636
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200637 inline bool ret (bool v)
638 {
639 if (unlikely (returned)) {
640 fprintf (stderr, "OUCH, double calls to TRACE_RETURN. This is a bug, please report.\n");
641 return v;
642 }
643
644 _hb_debug_msg<max_level> (NULL, NULL, NULL, TRUE, plevel ? *plevel : 1, -1, "return %s", v ? "true" : "false");
645 if (plevel) --*plevel;
646 plevel = NULL;
647 returned = true;
648 return v;
649 }
650
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400651 private:
652 unsigned int *plevel;
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200653 bool returned;
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400654};
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200655template <> /* Optimize when tracing is disabled */
656struct hb_auto_trace_t<0> {
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400657 explicit inline hb_auto_trace_t (unsigned int *plevel_,
658 const char *what,
659 const void *obj,
660 const char *func,
Behdad Esfahbod20810972012-05-10 23:06:58 +0200661 const char *message,
662 ...) {}
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200663
664 template <typename T>
665 inline T ret (T v) { return v; }
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400666};
667
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200668#define TRACE_RETURN(RET) trace.ret (RET)
Behdad Esfahbodcc06c242011-07-25 20:25:44 -0400669
670/* Misc */
Behdad Esfahbodbc200452010-04-29 01:40:26 -0400671
Behdad Esfahbodf60f2162010-04-21 02:12:45 -0400672
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -0400673/* Pre-mature optimization:
674 * Checks for lo <= u <= hi but with an optimization if lo and hi
675 * are only different in a contiguous set of lower-most bits.
676 */
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -0400677template <typename T> inline bool
678hb_in_range (T u, T lo, T hi)
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -0400679{
680 if ( ((lo^hi) & lo) == 0 &&
681 ((lo^hi) & hi) == (lo^hi) &&
682 ((lo^hi) & ((lo^hi) + 1)) == 0 )
683 return (u & ~(lo^hi)) == lo;
684 else
685 return lo <= u && u <= hi;
686}
687
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -0400688
Behdad Esfahbod45d6f292011-07-30 14:44:30 -0400689/* Useful for set-operations on small enums.
690 * For example, for testing "x ∈ {x1, x2, x3}" use:
691 * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
692 */
Behdad Esfahbod7b08b0a2011-07-20 23:59:07 -0400693#define FLAG(x) (1<<(x))
694
Behdad Esfahbod8f0b64f2011-07-29 17:02:48 -0400695
Behdad Esfahbod45d6f292011-07-30 14:44:30 -0400696template <typename T> inline void
697hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
698{
699 if (unlikely (!len))
700 return;
701
702 unsigned int k = len - 1;
703 do {
704 unsigned int new_k = 0;
705
706 for (unsigned int j = 0; j < k; j++)
707 if (compar (&array[j], &array[j+1]) > 0) {
708 T t;
709 t = array[j];
710 array[j] = array[j + 1];
711 array[j + 1] = t;
712
713 new_k = j;
714 }
715 k = new_k;
716 } while (k);
717}
718
719
Behdad Esfahbod45d6f292011-07-30 14:44:30 -0400720
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400721
Behdad Esfahbodc57d4542011-04-20 18:50:27 -0400722#endif /* HB_PRIVATE_HH */