Imported Upstream version 2.4.0
[platform/upstream/harfbuzz.git] / src / hb-dsalgs.hh
1 /*
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
27 #ifndef HB_DSALGS_HH
28 #define HB_DSALGS_HH
29
30 #include "hb.hh"
31 #include "hb-null.hh"
32
33
34 /* Void! For when we need a expression-type of void. */
35 typedef const struct _hb_void_t *hb_void_t;
36 #define HB_VOID ((const _hb_void_t *) nullptr)
37
38
39 /*
40  * Bithacks.
41  */
42
43 /* Return the number of 1 bits in v. */
44 template <typename T>
45 static inline HB_CONST_FUNC unsigned int
46 hb_popcount (T v)
47 {
48 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
49   if (sizeof (T) <= sizeof (unsigned int))
50     return __builtin_popcount (v);
51
52   if (sizeof (T) <= sizeof (unsigned long))
53     return __builtin_popcountl (v);
54
55   if (sizeof (T) <= sizeof (unsigned long long))
56     return __builtin_popcountll (v);
57 #endif
58
59   if (sizeof (T) <= 4)
60   {
61     /* "HACKMEM 169" */
62     uint32_t y;
63     y = (v >> 1) &033333333333;
64     y = v - y - ((y >>1) & 033333333333);
65     return (((y + (y >> 3)) & 030707070707) % 077);
66   }
67
68   if (sizeof (T) == 8)
69   {
70     unsigned int shift = 32;
71     return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
72   }
73
74   if (sizeof (T) == 16)
75   {
76     unsigned int shift = 64;
77     return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
78   }
79
80   assert (0);
81   return 0; /* Shut up stupid compiler. */
82 }
83
84 /* Returns the number of bits needed to store number */
85 template <typename T>
86 static inline HB_CONST_FUNC unsigned int
87 hb_bit_storage (T v)
88 {
89   if (unlikely (!v)) return 0;
90
91 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
92   if (sizeof (T) <= sizeof (unsigned int))
93     return sizeof (unsigned int) * 8 - __builtin_clz (v);
94
95   if (sizeof (T) <= sizeof (unsigned long))
96     return sizeof (unsigned long) * 8 - __builtin_clzl (v);
97
98   if (sizeof (T) <= sizeof (unsigned long long))
99     return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
100 #endif
101
102 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
103   if (sizeof (T) <= sizeof (unsigned int))
104   {
105     unsigned long where;
106     _BitScanReverse (&where, v);
107     return 1 + where;
108   }
109 # if defined(_WIN64)
110   if (sizeof (T) <= 8)
111   {
112     unsigned long where;
113     _BitScanReverse64 (&where, v);
114     return 1 + where;
115   }
116 # endif
117 #endif
118
119   if (sizeof (T) <= 4)
120   {
121     /* "bithacks" */
122     const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
123     const unsigned int S[] = {1, 2, 4, 8, 16};
124     unsigned int r = 0;
125     for (int i = 4; i >= 0; i--)
126       if (v & b[i])
127       {
128         v >>= S[i];
129         r |= S[i];
130       }
131     return r + 1;
132   }
133   if (sizeof (T) <= 8)
134   {
135     /* "bithacks" */
136     const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
137     const unsigned int S[] = {1, 2, 4, 8, 16, 32};
138     unsigned int r = 0;
139     for (int i = 5; i >= 0; i--)
140       if (v & b[i])
141       {
142         v >>= S[i];
143         r |= S[i];
144       }
145     return r + 1;
146   }
147   if (sizeof (T) == 16)
148   {
149     unsigned int shift = 64;
150     return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
151                           hb_bit_storage<uint64_t> ((uint64_t) v);
152   }
153
154   assert (0);
155   return 0; /* Shut up stupid compiler. */
156 }
157
158 /* Returns the number of zero bits in the least significant side of v */
159 template <typename T>
160 static inline HB_CONST_FUNC unsigned int
161 hb_ctz (T v)
162 {
163   if (unlikely (!v)) return 0;
164
165 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
166   if (sizeof (T) <= sizeof (unsigned int))
167     return __builtin_ctz (v);
168
169   if (sizeof (T) <= sizeof (unsigned long))
170     return __builtin_ctzl (v);
171
172   if (sizeof (T) <= sizeof (unsigned long long))
173     return __builtin_ctzll (v);
174 #endif
175
176 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
177   if (sizeof (T) <= sizeof (unsigned int))
178   {
179     unsigned long where;
180     _BitScanForward (&where, v);
181     return where;
182   }
183 # if defined(_WIN64)
184   if (sizeof (T) <= 8)
185   {
186     unsigned long where;
187     _BitScanForward64 (&where, v);
188     return where;
189   }
190 # endif
191 #endif
192
193   if (sizeof (T) <= 4)
194   {
195     /* "bithacks" */
196     unsigned int c = 32;
197     v &= - (int32_t) v;
198     if (v) c--;
199     if (v & 0x0000FFFF) c -= 16;
200     if (v & 0x00FF00FF) c -= 8;
201     if (v & 0x0F0F0F0F) c -= 4;
202     if (v & 0x33333333) c -= 2;
203     if (v & 0x55555555) c -= 1;
204     return c;
205   }
206   if (sizeof (T) <= 8)
207   {
208     /* "bithacks" */
209     unsigned int c = 64;
210     v &= - (int64_t) (v);
211     if (v) c--;
212     if (v & 0x00000000FFFFFFFFULL) c -= 32;
213     if (v & 0x0000FFFF0000FFFFULL) c -= 16;
214     if (v & 0x00FF00FF00FF00FFULL) c -= 8;
215     if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
216     if (v & 0x3333333333333333ULL) c -= 2;
217     if (v & 0x5555555555555555ULL) c -= 1;
218     return c;
219   }
220   if (sizeof (T) == 16)
221   {
222     unsigned int shift = 64;
223     return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
224                           hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
225   }
226
227   assert (0);
228   return 0; /* Shut up stupid compiler. */
229 }
230
231
232 /*
233  * Tiny stuff.
234  */
235
236 template <typename T>
237 static inline T* hb_addressof (T& arg)
238 {
239 #pragma GCC diagnostic push
240 #pragma GCC diagnostic ignored "-Wcast-align"
241   /* https://en.cppreference.com/w/cpp/memory/addressof */
242   return reinterpret_cast<T*>(
243            &const_cast<char&>(
244               reinterpret_cast<const volatile char&>(arg)));
245 #pragma GCC diagnostic pop
246 }
247
248 /* ASCII tag/character handling */
249 static inline bool ISALPHA (unsigned char c)
250 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
251 static inline bool ISALNUM (unsigned char c)
252 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
253 static inline bool ISSPACE (unsigned char c)
254 { return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
255 static inline unsigned char TOUPPER (unsigned char c)
256 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
257 static inline unsigned char TOLOWER (unsigned char c)
258 { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
259
260 #undef MIN
261 template <typename Type>
262 static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
263
264 #undef MAX
265 template <typename Type>
266 static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
267
268 static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
269 { return (a + (b - 1)) / b; }
270
271
272 #undef  ARRAY_LENGTH
273 template <typename Type, unsigned int n>
274 static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
275 /* A const version, but does not detect erratically being called on pointers. */
276 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
277
278
279 static inline int
280 hb_memcmp (const void *a, const void *b, unsigned int len)
281 {
282   /* It's illegal to pass NULL to memcmp(), even if len is zero.
283    * So, wrap it.
284    * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
285   if (!len) return 0;
286   return memcmp (a, b, len);
287 }
288
289 static inline bool
290 hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
291 {
292   return (size > 0) && (count >= ((unsigned int) -1) / size);
293 }
294
295 static inline unsigned int
296 hb_ceil_to_4 (unsigned int v)
297 {
298   return ((v - 1) | 3) + 1;
299 }
300
301 template <typename T> struct hb_is_signed;
302 /* https://github.com/harfbuzz/harfbuzz/issues/1535 */
303 template <> struct hb_is_signed<int8_t> { enum { value = true }; };
304 template <> struct hb_is_signed<int16_t> { enum { value = true }; };
305 template <> struct hb_is_signed<int32_t> { enum { value = true }; };
306 template <> struct hb_is_signed<int64_t> { enum { value = true }; };
307 template <> struct hb_is_signed<uint8_t> { enum { value = false }; };
308 template <> struct hb_is_signed<uint16_t> { enum { value = false }; };
309 template <> struct hb_is_signed<uint32_t> { enum { value = false }; };
310 template <> struct hb_is_signed<uint64_t> { enum { value = false }; };
311
312 template <typename T> static inline bool
313 hb_in_range (T u, T lo, T hi)
314 {
315   static_assert (!hb_is_signed<T>::value, "");
316
317   /* The casts below are important as if T is smaller than int,
318    * the subtract results will become a signed int! */
319   return (T)(u - lo) <= (T)(hi - lo);
320 }
321 template <typename T> static inline bool
322 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
323 {
324   return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
325 }
326 template <typename T> static inline bool
327 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
328 {
329   return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
330 }
331
332
333 /*
334  * Sort and search.
335  */
336
337 static inline void *
338 hb_bsearch (const void *key, const void *base,
339             size_t nmemb, size_t size,
340             int (*compar)(const void *_key, const void *_item))
341 {
342   int min = 0, max = (int) nmemb - 1;
343   while (min <= max)
344   {
345     int mid = (min + max) / 2;
346     const void *p = (const void *) (((const char *) base) + (mid * size));
347     int c = compar (key, p);
348     if (c < 0)
349       max = mid - 1;
350     else if (c > 0)
351       min = mid + 1;
352     else
353       return (void *) p;
354   }
355   return nullptr;
356 }
357
358 static inline void *
359 hb_bsearch_r (const void *key, const void *base,
360               size_t nmemb, size_t size,
361               int (*compar)(const void *_key, const void *_item, void *_arg),
362               void *arg)
363 {
364   int min = 0, max = (int) nmemb - 1;
365   while (min <= max)
366   {
367     int mid = ((unsigned int) min + (unsigned int) max) / 2;
368     const void *p = (const void *) (((const char *) base) + (mid * size));
369     int c = compar (key, p, arg);
370     if (c < 0)
371       max = mid - 1;
372     else if (c > 0)
373       min = mid + 1;
374     else
375       return (void *) p;
376   }
377   return nullptr;
378 }
379
380
381 /* From https://github.com/noporpoise/sort_r
382  * With following modifications:
383  *
384  * 10 November 2018:
385  * https://github.com/noporpoise/sort_r/issues/7
386  */
387
388 /* Isaac Turner 29 April 2014 Public Domain */
389
390 /*
391
392 hb_sort_r function to be exported.
393
394 Parameters:
395   base is the array to be sorted
396   nel is the number of elements in the array
397   width is the size in bytes of each element of the array
398   compar is the comparison function
399   arg is a pointer to be passed to the comparison function
400
401 void hb_sort_r(void *base, size_t nel, size_t width,
402                int (*compar)(const void *_a, const void *_b, void *_arg),
403                void *arg);
404 */
405
406
407 /* swap a, b iff a>b */
408 /* __restrict is same as restrict but better support on old machines */
409 static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
410                           int (*compar)(const void *_a, const void *_b,
411                                         void *_arg),
412                           void *arg)
413 {
414   char tmp, *end = a+w;
415   if(compar(a, b, arg) > 0) {
416     for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
417     return 1;
418   }
419   return 0;
420 }
421
422 /* Note: quicksort is not stable, equivalent values may be swapped */
423 static inline void sort_r_simple(void *base, size_t nel, size_t w,
424                                  int (*compar)(const void *_a, const void *_b,
425                                                void *_arg),
426                                  void *arg)
427 {
428   char *b = (char *)base, *end = b + nel*w;
429   if(nel < 7) {
430     /* Insertion sort for arbitrarily small inputs */
431     char *pi, *pj;
432     for(pi = b+w; pi < end; pi += w) {
433       for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
434     }
435   }
436   else
437   {
438     /* nel > 6; Quicksort */
439
440     /* Use median of first, middle and last items as pivot */
441     char *x, *y, *xend, ch;
442     char *pl, *pm, *pr;
443     char *last = b+w*(nel-1), *tmp;
444     char *l[3];
445     l[0] = b;
446     l[1] = b+w*(nel/2);
447     l[2] = last;
448
449     if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
450     if(compar(l[1],l[2],arg) > 0) {
451       tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
452       if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
453     }
454
455     /* swap l[id], l[2] to put pivot as last element */
456     for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
457       ch = *x; *x = *y; *y = ch;
458     }
459
460     pl = b;
461     pr = last;
462
463     while(pl < pr) {
464       pm = pl+((pr-pl+1)>>1);
465       for(; pl < pm; pl += w) {
466         if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
467           pr -= w; /* pivot now at pl */
468           break;
469         }
470       }
471       pm = pl+((pr-pl)>>1);
472       for(; pm < pr; pr -= w) {
473         if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
474           pl += w; /* pivot now at pr */
475           break;
476         }
477       }
478     }
479
480     sort_r_simple(b, (pl-b)/w, w, compar, arg);
481     sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
482   }
483 }
484
485 static inline void hb_sort_r(void *base, size_t nel, size_t width,
486                              int (*compar)(const void *_a, const void *_b, void *_arg),
487                              void *arg)
488 {
489     sort_r_simple(base, nel, width, compar, arg);
490 }
491
492
493 template <typename T, typename T2> static inline void
494 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
495 {
496   for (unsigned int i = 1; i < len; i++)
497   {
498     unsigned int j = i;
499     while (j && compar (&array[j - 1], &array[i]) > 0)
500       j--;
501     if (i == j)
502       continue;
503     /* Move item i to occupy place for item j, shift what's in between. */
504     {
505       T t = array[i];
506       memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
507       array[j] = t;
508     }
509     if (array2)
510     {
511       T2 t = array2[i];
512       memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
513       array2[j] = t;
514     }
515   }
516 }
517
518 template <typename T> static inline void
519 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
520 {
521   hb_stable_sort (array, len, compar, (int *) nullptr);
522 }
523
524 static inline hb_bool_t
525 hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
526 {
527   /* Pain because we don't know whether s is nul-terminated. */
528   char buf[64];
529   len = MIN (ARRAY_LENGTH (buf) - 1, len);
530   strncpy (buf, s, len);
531   buf[len] = '\0';
532
533   char *end;
534   errno = 0;
535   unsigned long v = strtoul (buf, &end, base);
536   if (errno) return false;
537   if (*end) return false;
538   *out = v;
539   return true;
540 }
541
542
543 struct HbOpOr
544 {
545   static constexpr bool passthru_left = true;
546   static constexpr bool passthru_right = true;
547   template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
548 };
549 struct HbOpAnd
550 {
551   static constexpr bool passthru_left = false;
552   static constexpr bool passthru_right = false;
553   template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
554 };
555 struct HbOpMinus
556 {
557   static constexpr bool passthru_left = true;
558   static constexpr bool passthru_right = false;
559   template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
560 };
561 struct HbOpXor
562 {
563   static constexpr bool passthru_left = true;
564   static constexpr bool passthru_right = true;
565   template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
566 };
567
568
569 /* Compiler-assisted vectorization. */
570
571 /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
572  * using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
573  * Define that to 0 to disable. */
574 template <typename elt_t, unsigned int byte_size>
575 struct hb_vector_size_t
576 {
577   elt_t& operator [] (unsigned int i) { return u.v[i]; }
578   const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
579
580   void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
581
582   template <class Op>
583   hb_vector_size_t process (const hb_vector_size_t &o) const
584   {
585     hb_vector_size_t r;
586 #if HB_VECTOR_SIZE
587     if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
588       for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
589         Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
590     else
591 #endif
592       for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
593         Op::process (r.u.v[i], u.v[i], o.u.v[i]);
594     return r;
595   }
596   hb_vector_size_t operator | (const hb_vector_size_t &o) const
597   { return process<HbOpOr> (o); }
598   hb_vector_size_t operator & (const hb_vector_size_t &o) const
599   { return process<HbOpAnd> (o); }
600   hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
601   { return process<HbOpXor> (o); }
602   hb_vector_size_t operator ~ () const
603   {
604     hb_vector_size_t r;
605 #if HB_VECTOR_SIZE && 0
606     if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
607       for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
608         r.u.vec[i] = ~u.vec[i];
609     else
610 #endif
611     for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
612       r.u.v[i] = ~u.v[i];
613     return r;
614   }
615
616   private:
617   static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
618   union {
619     elt_t v[byte_size / sizeof (elt_t)];
620 #if HB_VECTOR_SIZE
621     hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)];
622 #endif
623   } u;
624 };
625
626
627 #endif /* HB_DSALGS_HH */