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