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
hb_popcount(T v)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
hb_bit_storage(T v)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
hb_ctz(T v)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 #pragma GCC diagnostic push
237 #pragma GCC diagnostic ignored "-Wcast-align"
238 template <typename T>
hb_addressof(T & arg)239 static inline T* hb_addressof (T& arg)
240 {
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 }
246 #pragma GCC diagnostic pop
247
248 /* ASCII tag/character handling */
ISALPHA(unsigned char c)249 static inline bool ISALPHA (unsigned char c)
250 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
ISALNUM(unsigned char c)251 static inline bool ISALNUM (unsigned char c)
252 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
ISSPACE(unsigned char c)253 static inline bool ISSPACE (unsigned char c)
254 { return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
TOUPPER(unsigned char c)255 static inline unsigned char TOUPPER (unsigned char c)
256 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
TOLOWER(unsigned char 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>
MIN(const Type & a,const Type & b)262 static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
263
264 #undef MAX
265 template <typename Type>
MAX(const Type & a,const Type & b)266 static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
267
DIV_CEIL(const unsigned int a,unsigned int b)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>
ARRAY_LENGTH(const Type (&)[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
hb_memcmp(const void * a,const void * b,unsigned int len)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
hb_unsigned_mul_overflows(unsigned int count,unsigned int size)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
hb_ceil_to_4(unsigned int v)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
hb_in_range(T u,T lo,T hi)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
hb_in_ranges(T u,T lo1,T hi1,T lo2,T hi2)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
hb_in_ranges(T u,T lo1,T hi1,T lo2,T hi2,T lo3,T hi3)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 *
hb_bsearch(const void * key,const void * base,size_t nmemb,size_t size,int (* compar)(const void * _key,const void * _item))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 *
hb_bsearch_r(const void * key,const void * base,size_t nmemb,size_t size,int (* compar)(const void * _key,const void * _item,void * _arg),void * arg)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 */
sort_r_cmpswap(char * __restrict a,char * __restrict b,size_t w,int (* compar)(const void * _a,const void * _b,void * _arg),void * arg)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 */
sort_r_simple(void * base,size_t nel,size_t w,int (* compar)(const void * _a,const void * _b,void * _arg),void * arg)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
hb_sort_r(void * base,size_t nel,size_t width,int (* compar)(const void * _a,const void * _b,void * _arg),void * arg)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
hb_stable_sort(T * array,unsigned int len,int (* compar)(const T *,const T *),T2 * array2)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
hb_stable_sort(T * array,unsigned int len,int (* compar)(const T *,const T *))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
hb_codepoint_parse(const char * s,unsigned int len,int base,hb_codepoint_t * out)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;
processHbOpOr552 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;
processHbOpAnd558 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;
processHbOpMinus564 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;
processHbOpXor570 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 {
operator []hb_vector_size_t582 elt_t& operator [] (unsigned int i) { return u.v[i]; }
operator []hb_vector_size_t583 const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
584
clearhb_vector_size_t585 void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
586
587 template <class Op>
processhb_vector_size_t588 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 }
operator |hb_vector_size_t601 hb_vector_size_t operator | (const hb_vector_size_t &o) const
602 { return process<HbOpOr> (o); }
operator &hb_vector_size_t603 hb_vector_size_t operator & (const hb_vector_size_t &o) const
604 { return process<HbOpAnd> (o); }
operator ^hb_vector_size_t605 hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
606 { return process<HbOpXor> (o); }
operator ~hb_vector_size_t607 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