25 */ |
25 */ |
26 |
26 |
27 #ifndef HB_DSALGS_HH |
27 #ifndef HB_DSALGS_HH |
28 #define HB_DSALGS_HH |
28 #define HB_DSALGS_HH |
29 |
29 |
30 #include "hb-private.hh" |
30 #include "hb.hh" |
31 |
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 /* The sizeof() is here to force template instantiation. |
|
316 * I'm sure there are better ways to do this but can't think of |
|
317 * one right now. Declaring a variable won't work as HB_UNUSED |
|
318 * is unusable on some platforms and unused types are less likely |
|
319 * to generate a warning than unused variables. */ |
|
320 static_assert (!hb_is_signed<T>::value, ""); |
|
321 |
|
322 /* The casts below are important as if T is smaller than int, |
|
323 * the subtract results will become a signed int! */ |
|
324 return (T)(u - lo) <= (T)(hi - lo); |
|
325 } |
|
326 template <typename T> static inline bool |
|
327 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) |
|
328 { |
|
329 return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); |
|
330 } |
|
331 template <typename T> static inline bool |
|
332 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) |
|
333 { |
|
334 return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); |
|
335 } |
|
336 |
|
337 |
|
338 /* |
|
339 * Sort and search. |
|
340 */ |
|
341 |
|
342 static inline void * |
|
343 hb_bsearch (const void *key, const void *base, |
|
344 size_t nmemb, size_t size, |
|
345 int (*compar)(const void *_key, const void *_item)) |
|
346 { |
|
347 int min = 0, max = (int) nmemb - 1; |
|
348 while (min <= max) |
|
349 { |
|
350 int mid = (min + max) / 2; |
|
351 const void *p = (const void *) (((const char *) base) + (mid * size)); |
|
352 int c = compar (key, p); |
|
353 if (c < 0) |
|
354 max = mid - 1; |
|
355 else if (c > 0) |
|
356 min = mid + 1; |
|
357 else |
|
358 return (void *) p; |
|
359 } |
|
360 return nullptr; |
|
361 } |
32 |
362 |
33 static inline void * |
363 static inline void * |
34 hb_bsearch_r (const void *key, const void *base, |
364 hb_bsearch_r (const void *key, const void *base, |
35 size_t nmemb, size_t size, |
365 size_t nmemb, size_t size, |
36 int (*compar)(const void *_key, const void *_item, void *_arg), |
366 int (*compar)(const void *_key, const void *_item, void *_arg), |
37 void *arg) |
367 void *arg) |
38 { |
368 { |
39 int min = 0, max = (int) nmemb - 1; |
369 int min = 0, max = (int) nmemb - 1; |
40 while (min <= max) |
370 while (min <= max) |
41 { |
371 { |
42 int mid = (min + max) / 2; |
372 int mid = ((unsigned int) min + (unsigned int) max) / 2; |
43 const void *p = (const void *) (((const char *) base) + (mid * size)); |
373 const void *p = (const void *) (((const char *) base) + (mid * size)); |
44 int c = compar (key, p, arg); |
374 int c = compar (key, p, arg); |
45 if (c < 0) |
375 if (c < 0) |
46 max = mid - 1; |
376 max = mid - 1; |
47 else if (c > 0) |
377 else if (c > 0) |
156 void *arg) |
492 void *arg) |
157 { |
493 { |
158 sort_r_simple(base, nel, width, compar, arg); |
494 sort_r_simple(base, nel, width, compar, arg); |
159 } |
495 } |
160 |
496 |
|
497 |
|
498 template <typename T, typename T2> static inline void |
|
499 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2) |
|
500 { |
|
501 for (unsigned int i = 1; i < len; i++) |
|
502 { |
|
503 unsigned int j = i; |
|
504 while (j && compar (&array[j - 1], &array[i]) > 0) |
|
505 j--; |
|
506 if (i == j) |
|
507 continue; |
|
508 /* Move item i to occupy place for item j, shift what's in between. */ |
|
509 { |
|
510 T t = array[i]; |
|
511 memmove (&array[j + 1], &array[j], (i - j) * sizeof (T)); |
|
512 array[j] = t; |
|
513 } |
|
514 if (array2) |
|
515 { |
|
516 T2 t = array2[i]; |
|
517 memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2)); |
|
518 array2[j] = t; |
|
519 } |
|
520 } |
|
521 } |
|
522 |
|
523 template <typename T> static inline void |
|
524 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) |
|
525 { |
|
526 hb_stable_sort (array, len, compar, (int *) nullptr); |
|
527 } |
|
528 |
|
529 static inline hb_bool_t |
|
530 hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) |
|
531 { |
|
532 /* Pain because we don't know whether s is nul-terminated. */ |
|
533 char buf[64]; |
|
534 len = MIN (ARRAY_LENGTH (buf) - 1, len); |
|
535 strncpy (buf, s, len); |
|
536 buf[len] = '\0'; |
|
537 |
|
538 char *end; |
|
539 errno = 0; |
|
540 unsigned long v = strtoul (buf, &end, base); |
|
541 if (errno) return false; |
|
542 if (*end) return false; |
|
543 *out = v; |
|
544 return true; |
|
545 } |
|
546 |
|
547 |
|
548 struct HbOpOr |
|
549 { |
|
550 static constexpr bool passthru_left = true; |
|
551 static constexpr bool passthru_right = true; |
|
552 template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; } |
|
553 }; |
|
554 struct HbOpAnd |
|
555 { |
|
556 static constexpr bool passthru_left = false; |
|
557 static constexpr bool passthru_right = false; |
|
558 template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; } |
|
559 }; |
|
560 struct HbOpMinus |
|
561 { |
|
562 static constexpr bool passthru_left = true; |
|
563 static constexpr bool passthru_right = false; |
|
564 template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; } |
|
565 }; |
|
566 struct HbOpXor |
|
567 { |
|
568 static constexpr bool passthru_left = true; |
|
569 static constexpr bool passthru_right = true; |
|
570 template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; } |
|
571 }; |
|
572 |
|
573 |
|
574 /* Compiler-assisted vectorization. */ |
|
575 |
|
576 /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), |
|
577 * using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128). |
|
578 * Define that to 0 to disable. */ |
|
579 template <typename elt_t, unsigned int byte_size> |
|
580 struct hb_vector_size_t |
|
581 { |
|
582 elt_t& operator [] (unsigned int i) { return u.v[i]; } |
|
583 const elt_t& operator [] (unsigned int i) const { return u.v[i]; } |
|
584 |
|
585 void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); } |
|
586 |
|
587 template <class Op> |
|
588 hb_vector_size_t process (const hb_vector_size_t &o) const |
|
589 { |
|
590 hb_vector_size_t r; |
|
591 #if HB_VECTOR_SIZE |
|
592 if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) |
|
593 for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) |
|
594 Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]); |
|
595 else |
|
596 #endif |
|
597 for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) |
|
598 Op::process (r.u.v[i], u.v[i], o.u.v[i]); |
|
599 return r; |
|
600 } |
|
601 hb_vector_size_t operator | (const hb_vector_size_t &o) const |
|
602 { return process<HbOpOr> (o); } |
|
603 hb_vector_size_t operator & (const hb_vector_size_t &o) const |
|
604 { return process<HbOpAnd> (o); } |
|
605 hb_vector_size_t operator ^ (const hb_vector_size_t &o) const |
|
606 { return process<HbOpXor> (o); } |
|
607 hb_vector_size_t operator ~ () const |
|
608 { |
|
609 hb_vector_size_t r; |
|
610 #if HB_VECTOR_SIZE && 0 |
|
611 if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) |
|
612 for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) |
|
613 r.u.vec[i] = ~u.vec[i]; |
|
614 else |
|
615 #endif |
|
616 for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) |
|
617 r.u.v[i] = ~u.v[i]; |
|
618 return r; |
|
619 } |
|
620 |
|
621 private: |
|
622 static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, ""); |
|
623 union { |
|
624 elt_t v[byte_size / sizeof (elt_t)]; |
|
625 #if HB_VECTOR_SIZE |
|
626 hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)]; |
|
627 #endif |
|
628 } u; |
|
629 }; |
|
630 |
|
631 |
161 #endif /* HB_DSALGS_HH */ |
632 #endif /* HB_DSALGS_HH */ |