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 | /* 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 | } |
362 | |
363 | static inline void * |
364 | hb_bsearch_r (const void *key, const void *base, |
365 | size_t nmemb, size_t size, |
366 | int (*compar)(const void *_key, const void *_item, void *_arg), |
367 | void *arg) |
368 | { |
369 | int min = 0, max = (int) nmemb - 1; |
370 | while (min <= max) |
371 | { |
372 | int mid = ((unsigned int) min + (unsigned int) max) / 2; |
373 | const void *p = (const void *) (((const char *) base) + (mid * size)); |
374 | int c = compar (key, p, arg); |
375 | if (c < 0) |
376 | max = mid - 1; |
377 | else if (c > 0) |
378 | min = mid + 1; |
379 | else |
380 | return (void *) p; |
381 | } |
382 | return nullptr; |
383 | } |
384 | |
385 | |
386 | /* From https://github.com/noporpoise/sort_r |
387 | * With following modifications: |
388 | * |
389 | * 10 November 2018: |
390 | * https://github.com/noporpoise/sort_r/issues/7 |
391 | */ |
392 | |
393 | /* Isaac Turner 29 April 2014 Public Domain */ |
394 | |
395 | /* |
396 | |
397 | hb_sort_r function to be exported. |
398 | |
399 | Parameters: |
400 | base is the array to be sorted |
401 | nel is the number of elements in the array |
402 | width is the size in bytes of each element of the array |
403 | compar is the comparison function |
404 | arg is a pointer to be passed to the comparison function |
405 | |
406 | void hb_sort_r(void *base, size_t nel, size_t width, |
407 | int (*compar)(const void *_a, const void *_b, void *_arg), |
408 | void *arg); |
409 | */ |
410 | |
411 | |
412 | /* swap a, b iff a>b */ |
413 | /* __restrict is same as restrict but better support on old machines */ |
414 | static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w, |
415 | int (*compar)(const void *_a, const void *_b, |
416 | void *_arg), |
417 | void *arg) |
418 | { |
419 | char tmp, *end = a+w; |
420 | if(compar(a, b, arg) > 0) { |
421 | for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; } |
422 | return 1; |
423 | } |
424 | return 0; |
425 | } |
426 | |
427 | /* Note: quicksort is not stable, equivalent values may be swapped */ |
428 | static inline void sort_r_simple(void *base, size_t nel, size_t w, |
429 | int (*compar)(const void *_a, const void *_b, |
430 | void *_arg), |
431 | void *arg) |
432 | { |
433 | char *b = (char *)base, *end = b + nel*w; |
434 | if(nel < 7) { |
435 | /* Insertion sort for arbitrarily small inputs */ |
436 | char *pi, *pj; |
437 | for(pi = b+w; pi < end; pi += w) { |
438 | for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {} |
439 | } |
440 | } |
441 | else |
442 | { |
443 | /* nel > 6; Quicksort */ |
444 | |
445 | /* Use median of first, middle and last items as pivot */ |
446 | char *x, *y, *xend, ch; |
447 | char *pl, *pm, *pr; |
448 | char *last = b+w*(nel-1), *tmp; |
449 | char *l[3]; |
450 | l[0] = b; |
451 | l[1] = b+w*(nel/2); |
452 | l[2] = last; |
453 | |
454 | if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; } |
455 | if(compar(l[1],l[2],arg) > 0) { |
456 | tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */ |
457 | if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; } |
458 | } |
459 | |
460 | /* swap l[id], l[2] to put pivot as last element */ |
461 | for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) { |
462 | ch = *x; *x = *y; *y = ch; |
463 | } |
464 | |
465 | pl = b; |
466 | pr = last; |
467 | |
468 | while(pl < pr) { |
469 | pm = pl+((pr-pl+1)>>1); |
470 | for(; pl < pm; pl += w) { |
471 | if(sort_r_cmpswap(pl, pr, w, compar, arg)) { |
472 | pr -= w; /* pivot now at pl */ |
473 | break; |
474 | } |
475 | } |
476 | pm = pl+((pr-pl)>>1); |
477 | for(; pm < pr; pr -= w) { |
478 | if(sort_r_cmpswap(pl, pr, w, compar, arg)) { |
479 | pl += w; /* pivot now at pr */ |
480 | break; |
481 | } |
482 | } |
483 | } |
484 | |
485 | sort_r_simple(b, (pl-b)/w, w, compar, arg); |
486 | sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg); |
487 | } |
488 | } |
489 | |
490 | static inline void hb_sort_r(void *base, size_t nel, size_t width, |
491 | int (*compar)(const void *_a, const void *_b, void *_arg), |
492 | void *arg) |
493 | { |
494 | sort_r_simple(base, nel, width, compar, arg); |
495 | } |
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 | |
632 | #endif /* HB_DSALGS_HH */ |
633 | |