blob: 6a8ddaa995be9110674820840f7647487c083187 [file] [log] [blame]
Behdad Esfahbod21ac5672017-10-30 09:48:09 -06001/*
2 * Copyright © 2017 Google, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
Behdad Esfahbod7ce9f392017-10-31 15:34:01 -060027#ifndef HB_DSALGS_HH
28#define HB_DSALGS_HH
Behdad Esfahbod538da742017-10-29 16:38:58 -060029
Behdad Esfahbod21ac5672017-10-30 09:48:09 -060030#include "hb-private.hh"
Behdad Esfahbod538da742017-10-29 16:38:58 -060031
Behdad Esfahbod977679f2017-10-29 17:33:32 -060032
Behdad Esfahbod491d93b2018-07-10 16:03:31 +020033/* Void! For when we need a expression-type of void. */
34typedef const struct _hb_void_t *hb_void_t;
35#define HB_VOID ((const _hb_void_t *) nullptr)
36
37
38/*
39 * Bithacks.
40 */
41
42/* Return the number of 1 bits in v. */
43template <typename T>
44static inline HB_CONST_FUNC unsigned int
45hb_popcount (T v)
46{
47#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
48 if (sizeof (T) <= sizeof (unsigned int))
49 return __builtin_popcount (v);
50
51 if (sizeof (T) <= sizeof (unsigned long))
52 return __builtin_popcountl (v);
53
54 if (sizeof (T) <= sizeof (unsigned long long))
55 return __builtin_popcountll (v);
56#endif
57
58 if (sizeof (T) <= 4)
59 {
60 /* "HACKMEM 169" */
61 uint32_t y;
62 y = (v >> 1) &033333333333;
63 y = v - y - ((y >>1) & 033333333333);
64 return (((y + (y >> 3)) & 030707070707) % 077);
65 }
66
67 if (sizeof (T) == 8)
68 {
69 unsigned int shift = 32;
70 return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
71 }
72
73 if (sizeof (T) == 16)
74 {
75 unsigned int shift = 64;
76 return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
77 }
78
79 assert (0);
80 return 0; /* Shut up stupid compiler. */
81}
82
83/* Returns the number of bits needed to store number */
84template <typename T>
85static inline HB_CONST_FUNC unsigned int
86hb_bit_storage (T v)
87{
88 if (unlikely (!v)) return 0;
89
90#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
91 if (sizeof (T) <= sizeof (unsigned int))
92 return sizeof (unsigned int) * 8 - __builtin_clz (v);
93
94 if (sizeof (T) <= sizeof (unsigned long))
95 return sizeof (unsigned long) * 8 - __builtin_clzl (v);
96
97 if (sizeof (T) <= sizeof (unsigned long long))
98 return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
99#endif
100
101#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
102 if (sizeof (T) <= sizeof (unsigned int))
103 {
104 unsigned long where;
105 _BitScanReverse (&where, v);
106 return 1 + where;
107 }
108# if _WIN64
109 if (sizeof (T) <= 8)
110 {
111 unsigned long where;
112 _BitScanReverse64 (&where, v);
113 return 1 + where;
114 }
115# endif
116#endif
117
118 if (sizeof (T) <= 4)
119 {
120 /* "bithacks" */
121 const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
122 const unsigned int S[] = {1, 2, 4, 8, 16};
123 unsigned int r = 0;
124 for (int i = 4; i >= 0; i--)
125 if (v & b[i])
126 {
127 v >>= S[i];
128 r |= S[i];
129 }
130 return r + 1;
131 }
132 if (sizeof (T) <= 8)
133 {
134 /* "bithacks" */
135 const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
136 const unsigned int S[] = {1, 2, 4, 8, 16, 32};
137 unsigned int r = 0;
138 for (int i = 5; i >= 0; i--)
139 if (v & b[i])
140 {
141 v >>= S[i];
142 r |= S[i];
143 }
144 return r + 1;
145 }
146 if (sizeof (T) == 16)
147 {
148 unsigned int shift = 64;
149 return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
150 hb_bit_storage<uint64_t> ((uint64_t) v);
151 }
152
153 assert (0);
154 return 0; /* Shut up stupid compiler. */
155}
156
157/* Returns the number of zero bits in the least significant side of v */
158template <typename T>
159static inline HB_CONST_FUNC unsigned int
160hb_ctz (T v)
161{
162 if (unlikely (!v)) return 0;
163
164#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
165 if (sizeof (T) <= sizeof (unsigned int))
166 return __builtin_ctz (v);
167
168 if (sizeof (T) <= sizeof (unsigned long))
169 return __builtin_ctzl (v);
170
171 if (sizeof (T) <= sizeof (unsigned long long))
172 return __builtin_ctzll (v);
173#endif
174
175#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
176 if (sizeof (T) <= sizeof (unsigned int))
177 {
178 unsigned long where;
179 _BitScanForward (&where, v);
180 return where;
181 }
182# if _WIN64
183 if (sizeof (T) <= 8)
184 {
185 unsigned long where;
186 _BitScanForward64 (&where, v);
187 return where;
188 }
189# endif
190#endif
191
192 if (sizeof (T) <= 4)
193 {
194 /* "bithacks" */
195 unsigned int c = 32;
196 v &= - (int32_t) v;
197 if (v) c--;
198 if (v & 0x0000FFFF) c -= 16;
199 if (v & 0x00FF00FF) c -= 8;
200 if (v & 0x0F0F0F0F) c -= 4;
201 if (v & 0x33333333) c -= 2;
202 if (v & 0x55555555) c -= 1;
203 return c;
204 }
205 if (sizeof (T) <= 8)
206 {
207 /* "bithacks" */
208 unsigned int c = 64;
209 v &= - (int64_t) (v);
210 if (v) c--;
211 if (v & 0x00000000FFFFFFFFULL) c -= 32;
212 if (v & 0x0000FFFF0000FFFFULL) c -= 16;
213 if (v & 0x00FF00FF00FF00FFULL) c -= 8;
214 if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
215 if (v & 0x3333333333333333ULL) c -= 2;
216 if (v & 0x5555555555555555ULL) c -= 1;
217 return c;
218 }
219 if (sizeof (T) == 16)
220 {
221 unsigned int shift = 64;
222 return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
Behdad Esfahbod718dfd42018-07-10 16:34:31 +0200223 hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
Behdad Esfahbod491d93b2018-07-10 16:03:31 +0200224 }
225
226 assert (0);
227 return 0; /* Shut up stupid compiler. */
228}
229
230
231/*
232 * Tiny stuff.
233 */
234
235#undef MIN
236template <typename Type>
237static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
238
239#undef MAX
240template <typename Type>
241static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
242
243static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
244{ return (a + (b - 1)) / b; }
245
246
247#undef ARRAY_LENGTH
248template <typename Type, unsigned int n>
249static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
250/* A const version, but does not detect erratically being called on pointers. */
251#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
252
253static inline bool
254hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
255{
256 return (size > 0) && (count >= ((unsigned int) -1) / size);
257}
258
259static inline unsigned int
260hb_ceil_to_4 (unsigned int v)
261{
262 return ((v - 1) | 3) + 1;
263}
264
265
266/*
267 * Sort and search.
268 */
269
Behdad Esfahbod977679f2017-10-29 17:33:32 -0600270static inline void *
Behdad Esfahbod7ce9f392017-10-31 15:34:01 -0600271hb_bsearch_r (const void *key, const void *base,
272 size_t nmemb, size_t size,
273 int (*compar)(const void *_key, const void *_item, void *_arg),
274 void *arg)
Behdad Esfahbod977679f2017-10-29 17:33:32 -0600275{
276 int min = 0, max = (int) nmemb - 1;
277 while (min <= max)
278 {
279 int mid = (min + max) / 2;
280 const void *p = (const void *) (((const char *) base) + (mid * size));
281 int c = compar (key, p, arg);
282 if (c < 0)
283 max = mid - 1;
284 else if (c > 0)
285 min = mid + 1;
286 else
287 return (void *) p;
288 }
Ebrahim Byagowi8b0d6422018-04-23 18:37:35 +0430289 return nullptr;
Behdad Esfahbod977679f2017-10-29 17:33:32 -0600290}
291
292
Behdad Esfahbod538da742017-10-29 16:38:58 -0600293/* From https://github.com/noporpoise/sort_r */
Behdad Esfahbod21ac5672017-10-30 09:48:09 -0600294
295/* Isaac Turner 29 April 2014 Public Domain */
296
Behdad Esfahbod538da742017-10-29 16:38:58 -0600297/*
298
299hb_sort_r function to be exported.
300
301Parameters:
302 base is the array to be sorted
303 nel is the number of elements in the array
304 width is the size in bytes of each element of the array
305 compar is the comparison function
306 arg is a pointer to be passed to the comparison function
307
308void hb_sort_r(void *base, size_t nel, size_t width,
309 int (*compar)(const void *_a, const void *_b, void *_arg),
310 void *arg);
Behdad Esfahbod538da742017-10-29 16:38:58 -0600311*/
312
Behdad Esfahbod538da742017-10-29 16:38:58 -0600313
314/* swap a, b iff a>b */
315/* __restrict is same as restrict but better support on old machines */
Behdad Esfahbod0feff4b2017-10-31 14:02:32 -0600316static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
317 int (*compar)(const void *_a, const void *_b,
318 void *_arg),
319 void *arg)
Behdad Esfahbod538da742017-10-29 16:38:58 -0600320{
321 char tmp, *end = a+w;
322 if(compar(a, b, arg) > 0) {
323 for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
324 return 1;
325 }
326 return 0;
327}
328
Behdad Esfahbod538da742017-10-29 16:38:58 -0600329/* Note: quicksort is not stable, equivalent values may be swapped */
Behdad Esfahbod0feff4b2017-10-31 14:02:32 -0600330static inline void sort_r_simple(void *base, size_t nel, size_t w,
331 int (*compar)(const void *_a, const void *_b,
332 void *_arg),
333 void *arg)
Behdad Esfahbod538da742017-10-29 16:38:58 -0600334{
335 char *b = (char *)base, *end = b + nel*w;
336 if(nel < 7) {
337 /* Insertion sort for arbitrarily small inputs */
338 char *pi, *pj;
339 for(pi = b+w; pi < end; pi += w) {
340 for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
341 }
342 }
343 else
344 {
345 /* nel > 6; Quicksort */
346
347 /* Use median of first, middle and last items as pivot */
348 char *x, *y, *xend, ch;
349 char *pl, *pr;
350 char *last = b+w*(nel-1), *tmp;
351 char *l[3];
352 l[0] = b;
353 l[1] = b+w*(nel/2);
354 l[2] = last;
355
356 if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
357 if(compar(l[1],l[2],arg) > 0) {
358 tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
359 if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
360 }
361
362 /* swap l[id], l[2] to put pivot as last element */
363 for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
364 ch = *x; *x = *y; *y = ch;
365 }
366
367 pl = b;
368 pr = last;
369
370 while(pl < pr) {
371 for(; pl < pr; pl += w) {
372 if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
373 pr -= w; /* pivot now at pl */
374 break;
375 }
376 }
377 for(; pl < pr; pr -= w) {
378 if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
379 pl += w; /* pivot now at pr */
380 break;
381 }
382 }
383 }
384
385 sort_r_simple(b, (pl-b)/w, w, compar, arg);
386 sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
387 }
388}
389
Behdad Esfahbod0feff4b2017-10-31 14:02:32 -0600390static inline void hb_sort_r(void *base, size_t nel, size_t width,
391 int (*compar)(const void *_a, const void *_b, void *_arg),
392 void *arg)
393{
394 sort_r_simple(base, nel, width, compar, arg);
395}
Behdad Esfahbod538da742017-10-29 16:38:58 -0600396
Behdad Esfahbod9e53b082018-07-10 14:03:58 +0200397
398template <typename T, typename T2> static inline void
399hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
400{
401 for (unsigned int i = 1; i < len; i++)
402 {
403 unsigned int j = i;
404 while (j && compar (&array[j - 1], &array[i]) > 0)
405 j--;
406 if (i == j)
407 continue;
408 /* Move item i to occupy place for item j, shift what's in between. */
409 {
410 T t = array[i];
411 memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
412 array[j] = t;
413 }
414 if (array2)
415 {
416 T2 t = array2[i];
417 memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
418 array2[j] = t;
419 }
420 }
421}
422
423template <typename T> static inline void
424hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
425{
426 hb_stable_sort (array, len, compar, (int *) nullptr);
427}
428
429static inline hb_bool_t
430hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
431{
432 /* Pain because we don't know whether s is nul-terminated. */
433 char buf[64];
434 len = MIN (ARRAY_LENGTH (buf) - 1, len);
435 strncpy (buf, s, len);
436 buf[len] = '\0';
437
438 char *end;
439 errno = 0;
440 unsigned long v = strtoul (buf, &end, base);
441 if (errno) return false;
442 if (*end) return false;
443 *out = v;
444 return true;
445}
446
447
Behdad Esfahbodd652ef22018-07-10 14:05:00 +0200448#define HB_VECTOR_INIT {0, 0, false, nullptr}
449template <typename Type, unsigned int StaticSize=8>
450struct hb_vector_t
451{
452 unsigned int len;
453 unsigned int allocated;
454 bool successful;
455 Type *arrayZ;
456 Type static_array[StaticSize];
457
458 void init (void)
459 {
460 len = 0;
461 allocated = ARRAY_LENGTH (static_array);
462 successful = true;
463 arrayZ = static_array;
464 }
465
466 inline Type& operator [] (unsigned int i)
467 {
468 if (unlikely (i >= len))
469 return Crap (Type);
470 return arrayZ[i];
471 }
472 inline const Type& operator [] (unsigned int i) const
473 {
474 if (unlikely (i >= len))
475 return Null(Type);
476 return arrayZ[i];
477 }
478
479 inline Type *push (void)
480 {
481 if (unlikely (!resize (len + 1)))
482 return &Crap(Type);
483 return &arrayZ[len - 1];
484 }
485 inline Type *push (const Type& v)
486 {
487 Type *p = push ();
488 *p = v;
489 return p;
490 }
491
492 /* Allocate for size but don't adjust len. */
493 inline bool alloc (unsigned int size)
494 {
495 if (unlikely (!successful))
496 return false;
497
498 if (likely (size <= allocated))
499 return true;
500
501 /* Reallocate */
502
503 unsigned int new_allocated = allocated;
504 while (size >= new_allocated)
505 new_allocated += (new_allocated >> 1) + 8;
506
507 Type *new_array = nullptr;
508
509 if (arrayZ == static_array)
510 {
511 new_array = (Type *) calloc (new_allocated, sizeof (Type));
512 if (new_array)
513 memcpy (new_array, arrayZ, len * sizeof (Type));
514 }
515 else
516 {
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200517 bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
Behdad Esfahbodd652ef22018-07-10 14:05:00 +0200518 if (likely (!overflows))
519 new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
520 }
521
522 if (unlikely (!new_array))
523 {
524 successful = false;
525 return false;
526 }
527
528 arrayZ = new_array;
529 allocated = new_allocated;
530
531 return true;
532 }
533
534 inline bool resize (int size_)
535 {
536 unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
537 if (!alloc (size))
538 return false;
539
540 if (size > len)
541 memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
542
543 len = size;
544 return true;
545 }
546
547 inline void pop (void)
548 {
549 if (!len) return;
550 len--;
551 }
552
553 inline void remove (unsigned int i)
554 {
555 if (unlikely (i >= len))
556 return;
557 memmove (static_cast<void *> (&arrayZ[i]),
558 static_cast<void *> (&arrayZ[i + 1]),
559 (len - i - 1) * sizeof (Type));
560 len--;
561 }
562
563 inline void shrink (int size_)
564 {
565 unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
566 if (size < len)
567 len = size;
568 }
569
570 template <typename T>
571 inline Type *find (T v) {
572 for (unsigned int i = 0; i < len; i++)
573 if (arrayZ[i] == v)
574 return &arrayZ[i];
575 return nullptr;
576 }
577 template <typename T>
578 inline const Type *find (T v) const {
579 for (unsigned int i = 0; i < len; i++)
580 if (arrayZ[i] == v)
581 return &arrayZ[i];
582 return nullptr;
583 }
584
585 inline void qsort (int (*cmp)(const void*, const void*))
586 {
587 ::qsort (arrayZ, len, sizeof (Type), cmp);
588 }
589
590 inline void qsort (void)
591 {
592 ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
593 }
594
595 inline void qsort (unsigned int start, unsigned int end)
596 {
597 ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
598 }
599
600 template <typename T>
601 inline Type *lsearch (const T &x)
602 {
603 for (unsigned int i = 0; i < len; i++)
604 if (0 == this->arrayZ[i].cmp (&x))
605 return &arrayZ[i];
606 return nullptr;
607 }
608
609 template <typename T>
610 inline Type *bsearch (const T &x)
611 {
612 unsigned int i;
613 return bfind (x, &i) ? &arrayZ[i] : nullptr;
614 }
615 template <typename T>
616 inline const Type *bsearch (const T &x) const
617 {
618 unsigned int i;
619 return bfind (x, &i) ? &arrayZ[i] : nullptr;
620 }
621 template <typename T>
622 inline bool bfind (const T &x, unsigned int *i) const
623 {
624 int min = 0, max = (int) this->len - 1;
625 while (min <= max)
626 {
627 int mid = (min + max) / 2;
628 int c = this->arrayZ[mid].cmp (&x);
629 if (c < 0)
630 max = mid - 1;
631 else if (c > 0)
632 min = mid + 1;
633 else
634 {
635 *i = mid;
636 return true;
637 }
638 }
639 if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
640 max++;
641 *i = max;
642 return false;
643 }
644
645 inline void fini (void)
646 {
647 if (arrayZ != static_array)
648 free (arrayZ);
649 arrayZ = nullptr;
650 allocated = len = 0;
651 }
652};
653
Behdad Esfahbodd652ef22018-07-10 14:05:00 +0200654
655#define HB_LOCKABLE_SET_INIT {HB_VECTOR_INIT}
656template <typename item_t, typename lock_t>
657struct hb_lockable_set_t
658{
659 hb_vector_t <item_t, 1> items;
660
661 inline void init (void) { items.init (); }
662
663 template <typename T>
664 inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
665 {
666 l.lock ();
667 item_t *item = items.find (v);
668 if (item) {
669 if (replace) {
670 item_t old = *item;
671 *item = v;
672 l.unlock ();
673 old.fini ();
674 }
675 else {
676 item = nullptr;
677 l.unlock ();
678 }
679 } else {
680 item = items.push (v);
681 l.unlock ();
682 }
683 return item;
684 }
685
686 template <typename T>
687 inline void remove (T v, lock_t &l)
688 {
689 l.lock ();
690 item_t *item = items.find (v);
691 if (item) {
692 item_t old = *item;
693 *item = items[items.len - 1];
694 items.pop ();
695 l.unlock ();
696 old.fini ();
697 } else {
698 l.unlock ();
699 }
700 }
701
702 template <typename T>
703 inline bool find (T v, item_t *i, lock_t &l)
704 {
705 l.lock ();
706 item_t *item = items.find (v);
707 if (item)
708 *i = *item;
709 l.unlock ();
710 return !!item;
711 }
712
713 template <typename T>
714 inline item_t *find_or_insert (T v, lock_t &l)
715 {
716 l.lock ();
717 item_t *item = items.find (v);
718 if (!item) {
719 item = items.push (v);
720 }
721 l.unlock ();
722 return item;
723 }
724
725 inline void fini (lock_t &l)
726 {
727 if (!items.len) {
728 /* No need for locking. */
729 items.fini ();
730 return;
731 }
732 l.lock ();
733 while (items.len) {
734 item_t old = items[items.len - 1];
735 items.pop ();
736 l.unlock ();
737 old.fini ();
738 l.lock ();
739 }
740 items.fini ();
741 l.unlock ();
742 }
743
744};
745
746
Behdad Esfahbodbe7f6642018-07-10 15:23:08 +0200747template <typename Type>
748struct hb_auto_t : Type
749{
750 hb_auto_t (void) { Type::init (); }
751 ~hb_auto_t (void) { Type::fini (); }
752 private: /* Hide */
753 void init (void) {}
754 void fini (void) {}
755};
756
757struct hb_bytes_t
758{
759 inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
760 inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
761
762 inline int cmp (const hb_bytes_t &a) const
763 {
764 if (len != a.len)
765 return (int) a.len - (int) len;
766
767 return memcmp (a.bytes, bytes, len);
768 }
769 static inline int cmp (const void *pa, const void *pb)
770 {
771 hb_bytes_t *a = (hb_bytes_t *) pa;
772 hb_bytes_t *b = (hb_bytes_t *) pb;
773 return b->cmp (*a);
774 }
775
776 const char *bytes;
777 unsigned int len;
778};
779
780
Behdad Esfahbodf4777652018-07-10 15:49:05 +0200781struct HbOpOr
782{
783 static const bool passthru_left = true;
784 static const bool passthru_right = true;
785 template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
786};
787struct HbOpAnd
788{
789 static const bool passthru_left = false;
790 static const bool passthru_right = false;
791 template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
792};
793struct HbOpMinus
794{
795 static const bool passthru_left = true;
796 static const bool passthru_right = false;
797 template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
798};
799struct HbOpXor
800{
801 static const bool passthru_left = true;
802 static const bool passthru_right = true;
803 template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
804};
805
806
807/* Compiler-assisted vectorization. */
808
809/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
810 * using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
811 * Define that to 0 to disable. */
812template <typename elt_t, unsigned int byte_size>
813struct hb_vector_size_t
814{
815 elt_t& operator [] (unsigned int i) { return u.v[i]; }
816 const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
817
818 template <class Op>
819 inline hb_vector_size_t process (const hb_vector_size_t &o) const
820 {
821 hb_vector_size_t r;
822#if HB_VECTOR_SIZE
823 if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
824 for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
825 Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
826 else
827#endif
828 for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
829 Op::process (r.u.v[i], u.v[i], o.u.v[i]);
830 return r;
831 }
832 inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
833 { return process<HbOpOr> (o); }
834 inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
835 { return process<HbOpAnd> (o); }
836 inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
837 { return process<HbOpXor> (o); }
838 inline hb_vector_size_t operator ~ () const
839 {
840 hb_vector_size_t r;
841#if HB_VECTOR_SIZE && 0
842 if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
843 for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
844 r.u.vec[i] = ~u.vec[i];
845 else
846#endif
847 for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
848 r.u.v[i] = ~u.v[i];
849 return r;
850 }
851
852 private:
853 static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
854 union {
855 elt_t v[byte_size / sizeof (elt_t)];
856#if HB_VECTOR_SIZE
857 typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
858 vec_t vec[byte_size / sizeof (vec_t)];
859#endif
860 } u;
861};
862
863
Behdad Esfahbod7ce9f392017-10-31 15:34:01 -0600864#endif /* HB_DSALGS_HH */