1 /*
2  * Copyright © 2017  Google, Inc.
3  * Copyright © 2019  Facebook, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Google Author(s): Behdad Esfahbod
26  * Facebook Author(s): Behdad Esfahbod
27  */
28 
29 #ifndef HB_ALGS_HH
30 #define HB_ALGS_HH
31 
32 #include "hb.hh"
33 #include "hb-meta.hh"
34 #include "hb-null.hh"
35 #include "hb-number.hh"
36 
37 
38 /*
39  * Flags
40  */
41 
42 /* Enable bitwise ops on enums marked as flags_t */
43 /* To my surprise, looks like the function resolver is happy to silently cast
44  * one enum to another...  So this doesn't provide the type-checking that I
45  * originally had in mind... :(.
46  *
47  * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
48  */
49 #ifdef _MSC_VER
50 # pragma warning(disable:4200)
51 # pragma warning(disable:4800)
52 #endif
53 #define HB_MARK_AS_FLAG_T(T) \
54         extern "C++" { \
55           static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
56           static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
57           static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
58           static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \
59           static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
60           static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
61           static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
62         } \
63         static_assert (true, "")
64 
65 /* Useful for set-operations on small enums.
66  * For example, for testing "x ∈ {x1, x2, x3}" use:
67  * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
68  */
69 #define FLAG(x) (static_assert_expr ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
70 #define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
71 #define FLAG_RANGE(x,y) (static_assert_expr ((x) < (y)) + FLAG(y+1) - FLAG(x))
72 #define FLAG64(x) (static_assert_expr ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
73 #define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
74 
75 
76 /*
77  * Big-endian integers.
78  */
79 
80 /* Endian swap, used in Windows related backends */
hb_uint16_swap(uint16_t v)81 static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
82 { return (v >> 8) | (v << 8); }
hb_uint32_swap(uint32_t v)83 static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
84 { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
85 
86 template <typename Type, int Bytes = sizeof (Type)>
87 struct BEInt;
88 template <typename Type>
89 struct BEInt<Type, 1>
90 {
91   public:
92   BEInt () = default;
BEIntBEInt93   constexpr BEInt (Type V) : v {uint8_t (V)} {}
operator TypeBEInt94   constexpr operator Type () const { return v; }
95   private: uint8_t v;
96 };
97 template <typename Type>
98 struct BEInt<Type, 2>
99 {
100   public:
101   BEInt () = default;
BEIntBEInt102   constexpr BEInt (Type V) : v {uint8_t ((V >>  8) & 0xFF),
103                                 uint8_t ((V      ) & 0xFF)} {}
104 
105   struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
operator TypeBEInt106   constexpr operator Type () const
107   {
108 #if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
109     defined(__BYTE_ORDER) && \
110     (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
111     /* Spoon-feed the compiler a big-endian integer with alignment 1.
112      * https://github.com/harfbuzz/harfbuzz/pull/1398 */
113 #if __BYTE_ORDER == __LITTLE_ENDIAN
114     return __builtin_bswap16 (((packed_uint16_t *) this)->v);
115 #else /* __BYTE_ORDER == __BIG_ENDIAN */
116     return ((packed_uint16_t *) this)->v;
117 #endif
118 #else
119     return (v[0] <<  8)
120          + (v[1]      );
121 #endif
122   }
123   private: uint8_t v[2];
124 };
125 template <typename Type>
126 struct BEInt<Type, 3>
127 {
128   static_assert (!hb_is_signed (Type), "");
129   public:
130   BEInt () = default;
BEIntBEInt131   constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF),
132                                 uint8_t ((V >>  8) & 0xFF),
133                                 uint8_t ((V      ) & 0xFF)} {}
134 
operator TypeBEInt135   constexpr operator Type () const { return (v[0] << 16)
136                                           + (v[1] <<  8)
137                                           + (v[2]      ); }
138   private: uint8_t v[3];
139 };
140 template <typename Type>
141 struct BEInt<Type, 4>
142 {
143   public:
144   BEInt () = default;
BEIntBEInt145   constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
146                                 uint8_t ((V >> 16) & 0xFF),
147                                 uint8_t ((V >>  8) & 0xFF),
148                                 uint8_t ((V      ) & 0xFF)} {}
operator TypeBEInt149   constexpr operator Type () const { return (v[0] << 24)
150                                           + (v[1] << 16)
151                                           + (v[2] <<  8)
152                                           + (v[3]      ); }
153   private: uint8_t v[4];
154 };
155 
156 /* Floats. */
157 
158 /* We want our rounding towards +infinity. */
159 static inline float
_hb_roundf(float x)160 _hb_roundf (float x) { return floorf (x + .5f); }
161 #define roundf(x) _hb_roundf(x)
162 
163 
164 /* Encodes three unsigned integers in one 64-bit number.  If the inputs have more than 21 bits,
165  * values will be truncated / overlap, and might not decode exactly. */
166 #define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
167 #define HB_CODEPOINT_DECODE3_1(v) ((hb_codepoint_t) ((v) >> 42))
168 #define HB_CODEPOINT_DECODE3_2(v) ((hb_codepoint_t) ((v) >> 21) & 0x1FFFFFu)
169 #define HB_CODEPOINT_DECODE3_3(v) ((hb_codepoint_t) (v) & 0x1FFFFFu)
170 
171 /* Custom encoding used by hb-ucd. */
172 #define HB_CODEPOINT_ENCODE3_11_7_14(x,y,z) (((uint32_t) ((x) & 0x07FFu) << 21) | (((uint32_t) (y) & 0x007Fu) << 14) | (uint32_t) ((z) & 0x3FFFu))
173 #define HB_CODEPOINT_DECODE3_11_7_14_1(v) ((hb_codepoint_t) ((v) >> 21))
174 #define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
175 #define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
176 
177 
178 struct
179 {
180   /* Note.  This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
181   template <typename T> constexpr auto
182   operator () (T&& v) const HB_AUTO_RETURN ( hb_forward<T> (v) )
183 }
184 HB_FUNCOBJ (hb_identity);
185 struct
186 {
187   /* Like identity(), but only retains lvalue-references.  Rvalues are returned as rvalues. */
188   template <typename T> constexpr T&
operator ()__anonbe566b7e0208189   operator () (T& v) const { return v; }
190 
191   template <typename T> constexpr hb_remove_reference<T>
operator ()__anonbe566b7e0208192   operator () (T&& v) const { return v; }
193 }
194 HB_FUNCOBJ (hb_lidentity);
195 struct
196 {
197   /* Like identity(), but always returns rvalue. */
198   template <typename T> constexpr hb_remove_reference<T>
operator ()__anonbe566b7e0308199   operator () (T&& v) const { return v; }
200 }
201 HB_FUNCOBJ (hb_ridentity);
202 
203 struct
204 {
205   template <typename T> constexpr bool
operator ()__anonbe566b7e0408206   operator () (T&& v) const { return bool (hb_forward<T> (v)); }
207 }
208 HB_FUNCOBJ (hb_bool);
209 
210 struct
211 {
212   private:
213 
214   template <typename T> constexpr auto
215   impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
216 
217   template <typename T,
218             hb_enable_if (hb_is_integral (T))> constexpr auto
219   impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
220   (
221     /* Knuth's multiplicative method: */
222     (uint32_t) v * 2654435761u
223   )
224 
225   public:
226 
227   template <typename T> constexpr auto
228   operator () (const T& v) const HB_RETURN (uint32_t, impl (v, hb_prioritize))
229 }
230 HB_FUNCOBJ (hb_hash);
231 
232 
233 struct
234 {
235   private:
236 
237   /* Pointer-to-member-function. */
238   template <typename Appl, typename T, typename ...Ts> auto
239   impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN
240   ((hb_deref (hb_forward<T> (v)).*hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
241 
242   /* Pointer-to-member. */
243   template <typename Appl, typename T> auto
244   impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN
245   ((hb_deref (hb_forward<T> (v))).*hb_forward<Appl> (a))
246 
247   /* Operator(). */
248   template <typename Appl, typename ...Ts> auto
249   impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN
250   (hb_deref (hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
251 
252   public:
253 
254   template <typename Appl, typename ...Ts> auto
255   operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN
256   (
257     impl (hb_forward<Appl> (a),
258           hb_prioritize,
259           hb_forward<Ts> (ds)...)
260   )
261 }
262 HB_FUNCOBJ (hb_invoke);
263 
264 template <unsigned Pos, typename Appl, typename V>
265 struct hb_partial_t
266 {
hb_partial_thb_partial_t267   hb_partial_t (Appl a, V v) : a (a), v (v) {}
268 
269   static_assert (Pos > 0, "");
270 
271   template <typename ...Ts,
272             unsigned P = Pos,
273             hb_enable_if (P == 1)> auto
operator ()hb_partial_t274   operator () (Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
275                                                    hb_declval (V),
276                                                    hb_declval (Ts)...))
277   {
278     return hb_invoke (hb_forward<Appl> (a),
279                       hb_forward<V> (v),
280                       hb_forward<Ts> (ds)...);
281   }
282   template <typename T0, typename ...Ts,
283             unsigned P = Pos,
284             hb_enable_if (P == 2)> auto
operator ()hb_partial_t285   operator () (T0&& d0, Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
286                                                             hb_declval (T0),
287                                                             hb_declval (V),
288                                                             hb_declval (Ts)...))
289   {
290     return hb_invoke (hb_forward<Appl> (a),
291                       hb_forward<T0> (d0),
292                       hb_forward<V> (v),
293                       hb_forward<Ts> (ds)...);
294   }
295 
296   private:
297   hb_reference_wrapper<Appl> a;
298   V v;
299 };
300 template <unsigned Pos=1, typename Appl, typename V>
301 auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN
302 (( hb_partial_t<Pos, Appl, V> (a, v) ))
303 
304 /* The following, HB_PARTIALIZE, macro uses a particular corner-case
305  * of C++11 that is not particularly well-supported by all compilers.
306  * What's happening is that it's using "this" in a trailing return-type
307  * via decltype().  Broken compilers deduce the type of "this" pointer
308  * in that context differently from what it resolves to in the body
309  * of the function.
310  *
311  * One probable cause of this is that at the time of trailing return
312  * type declaration, "this" points to an incomplete type, whereas in
313  * the function body the type is complete.  That doesn't justify the
314  * error in any way, but is probably what's happening.
315  *
316  * In the case of MSVC, we get around this by using C++14 "decltype(auto)"
317  * which deduces the type from the actual return statement.  For gcc 4.8
318  * we use "+this" instead of "this" which produces an rvalue that seems
319  * to be deduced as the same type with this particular compiler, and seem
320  * to be fine as default code path as well.
321  */
322 #ifdef _MSC_VER
323 /* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \
324 #define HB_PARTIALIZE(Pos) \
325   template <typename _T> \
326   decltype(auto) operator () (_T&& _v) const \
327   { return hb_partial<Pos> (this, hb_forward<_T> (_v)); } \
328   static_assert (true, "")
329 #else
330 /* https://github.com/harfbuzz/harfbuzz/issues/1724 */
331 #define HB_PARTIALIZE(Pos) \
332   template <typename _T> \
333   auto operator () (_T&& _v) const HB_AUTO_RETURN \
334   (hb_partial<Pos> (+this, hb_forward<_T> (_v))) \
335   static_assert (true, "")
336 #endif
337 
338 
339 struct
340 {
341   private:
342 
343   template <typename Pred, typename Val> auto
344   impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
345   (
346     hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v))
347   )
348 
349   template <typename Pred, typename Val> auto
350   impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
351   (
352     hb_invoke (hb_forward<Pred> (p),
353                hb_forward<Val> (v))
354   )
355 
356   public:
357 
358   template <typename Pred, typename Val> auto
359   operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
360     impl (hb_forward<Pred> (p),
361           hb_forward<Val> (v),
362           hb_prioritize)
363   )
364 }
365 HB_FUNCOBJ (hb_has);
366 
367 struct
368 {
369   private:
370 
371   template <typename Pred, typename Val> auto
372   impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
373   (
374     hb_has (hb_forward<Pred> (p),
375             hb_forward<Val> (v))
376   )
377 
378   template <typename Pred, typename Val> auto
379   impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
380   (
381     hb_forward<Pred> (p) == hb_forward<Val> (v)
382   )
383 
384   public:
385 
386   template <typename Pred, typename Val> auto
387   operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
388     impl (hb_forward<Pred> (p),
389           hb_forward<Val> (v),
390           hb_prioritize)
391   )
392 }
393 HB_FUNCOBJ (hb_match);
394 
395 struct
396 {
397   private:
398 
399   template <typename Proj, typename Val> auto
400   impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
401   (
402     hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v))
403   )
404 
405   template <typename Proj, typename Val> auto
406   impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
407   (
408     hb_invoke (hb_forward<Proj> (f),
409                hb_forward<Val> (v))
410   )
411 
412   template <typename Proj, typename Val> auto
413   impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
414   (
415     hb_forward<Proj> (f)[hb_forward<Val> (v)]
416   )
417 
418   public:
419 
420   template <typename Proj, typename Val> auto
421   operator () (Proj&& f, Val &&v) const HB_AUTO_RETURN
422   (
423     impl (hb_forward<Proj> (f),
424           hb_forward<Val> (v),
425           hb_prioritize)
426   )
427 }
428 HB_FUNCOBJ (hb_get);
429 
430 struct
431 {
432   private:
433 
434   template <typename T1, typename T2> auto
435   impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN
436   (
437     hb_forward<T2> (v2).cmp (hb_forward<T1> (v1)) == 0
438   )
439 
440   template <typename T1, typename T2> auto
441   impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN
442   (
443     hb_forward<T1> (v1).cmp (hb_forward<T2> (v2)) == 0
444   )
445 
446   template <typename T1, typename T2> auto
447   impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN
448   (
449     hb_forward<T1> (v1) == hb_forward<T2> (v2)
450   )
451 
452   public:
453 
454   template <typename T1, typename T2> auto
455   operator () (T1&& v1, T2 &&v2) const HB_AUTO_RETURN
456   (
457     impl (hb_forward<T1> (v1),
458           hb_forward<T2> (v2),
459           hb_prioritize)
460   )
461 }
462 HB_FUNCOBJ (hb_equal);
463 
464 
465 template <typename T1, typename T2>
466 struct hb_pair_t
467 {
468   typedef T1 first_t;
469   typedef T2 second_t;
470   typedef hb_pair_t<T1, T2> pair_t;
471 
hb_pair_thb_pair_t472   hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
473 
474   template <typename Q1, typename Q2,
475             hb_enable_if (hb_is_convertible (T1, Q1) &&
476                           hb_is_convertible (T2, T2))>
operator hb_pair_t<Q1,Q2>hb_pair_t477   operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
478 
reversehb_pair_t479   hb_pair_t<T1, T2> reverse () const
480   { return hb_pair_t<T1, T2> (second, first); }
481 
operator ==hb_pair_t482   bool operator == (const pair_t& o) const { return first == o.first && second == o.second; }
operator !=hb_pair_t483   bool operator != (const pair_t& o) const { return !(*this == o); }
operator <hb_pair_t484   bool operator < (const pair_t& o) const { return first < o.first || (first == o.first && second < o.second); }
operator >=hb_pair_t485   bool operator >= (const pair_t& o) const { return !(*this < o); }
operator >hb_pair_t486   bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
operator <=hb_pair_t487   bool operator <= (const pair_t& o) const { return !(*this > o); }
488 
489   T1 first;
490   T2 second;
491 };
492 #define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
493 template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
hb_pair(T1 && a,T2 && b)494 hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
495 
496 struct
497 {
498   template <typename Pair> constexpr typename Pair::first_t
operator ()__anonbe566b7e0b08499   operator () (const Pair& pair) const { return pair.first; }
500 }
501 HB_FUNCOBJ (hb_first);
502 
503 struct
504 {
505   template <typename Pair> constexpr typename Pair::second_t
operator ()__anonbe566b7e0c08506   operator () (const Pair& pair) const { return pair.second; }
507 }
508 HB_FUNCOBJ (hb_second);
509 
510 /* Note.  In min/max impl, we can use hb_type_identity<T> for second argument.
511  * However, that would silently convert between different-signedness integers.
512  * Instead we accept two different types, such that compiler can err if
513  * comparing integers of different signedness. */
514 struct
515 {
516   template <typename T, typename T2> constexpr auto
517   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
518   (a <= b ? hb_forward<T> (a) : hb_forward<T2> (b))
519 }
520 HB_FUNCOBJ (hb_min);
521 struct
522 {
523   template <typename T, typename T2> constexpr auto
524   operator () (T&& a, T2&& b) const HB_AUTO_RETURN
525   (a >= b ? hb_forward<T> (a) : hb_forward<T2> (b))
526 }
527 HB_FUNCOBJ (hb_max);
528 struct
529 {
530   template <typename T, typename T2, typename T3> constexpr auto
531   operator () (T&& x, T2&& min, T3&& max) const HB_AUTO_RETURN
532   (hb_min (hb_max (hb_forward<T> (x), hb_forward<T2> (min)), hb_forward<T3> (max)))
533 }
534 HB_FUNCOBJ (hb_clamp);
535 
536 
537 /*
538  * Bithacks.
539  */
540 
541 /* Return the number of 1 bits in v. */
542 template <typename T>
543 static inline unsigned int
hb_popcount(T v)544 hb_popcount (T v)
545 {
546 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
547   if (sizeof (T) <= sizeof (unsigned int))
548     return __builtin_popcount (v);
549 
550   if (sizeof (T) <= sizeof (unsigned long))
551     return __builtin_popcountl (v);
552 
553   if (sizeof (T) <= sizeof (unsigned long long))
554     return __builtin_popcountll (v);
555 #endif
556 
557   if (sizeof (T) <= 4)
558   {
559     /* "HACKMEM 169" */
560     uint32_t y;
561     y = (v >> 1) &033333333333;
562     y = v - y - ((y >>1) & 033333333333);
563     return (((y + (y >> 3)) & 030707070707) % 077);
564   }
565 
566   if (sizeof (T) == 8)
567   {
568     unsigned int shift = 32;
569     return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
570   }
571 
572   if (sizeof (T) == 16)
573   {
574     unsigned int shift = 64;
575     return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
576   }
577 
578   assert (0);
579   return 0; /* Shut up stupid compiler. */
580 }
581 
582 /* Returns the number of bits needed to store number */
583 template <typename T>
584 static inline unsigned int
hb_bit_storage(T v)585 hb_bit_storage (T v)
586 {
587   if (unlikely (!v)) return 0;
588 
589 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
590   if (sizeof (T) <= sizeof (unsigned int))
591     return sizeof (unsigned int) * 8 - __builtin_clz (v);
592 
593   if (sizeof (T) <= sizeof (unsigned long))
594     return sizeof (unsigned long) * 8 - __builtin_clzl (v);
595 
596   if (sizeof (T) <= sizeof (unsigned long long))
597     return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
598 #endif
599 
600 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
601   if (sizeof (T) <= sizeof (unsigned int))
602   {
603     unsigned long where;
604     _BitScanReverse (&where, v);
605     return 1 + where;
606   }
607 # if defined(_WIN64)
608   if (sizeof (T) <= 8)
609   {
610     unsigned long where;
611     _BitScanReverse64 (&where, v);
612     return 1 + where;
613   }
614 # endif
615 #endif
616 
617   if (sizeof (T) <= 4)
618   {
619     /* "bithacks" */
620     const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
621     const unsigned int S[] = {1, 2, 4, 8, 16};
622     unsigned int r = 0;
623     for (int i = 4; i >= 0; i--)
624       if (v & b[i])
625       {
626         v >>= S[i];
627         r |= S[i];
628       }
629     return r + 1;
630   }
631   if (sizeof (T) <= 8)
632   {
633     /* "bithacks" */
634     const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
635     const unsigned int S[] = {1, 2, 4, 8, 16, 32};
636     unsigned int r = 0;
637     for (int i = 5; i >= 0; i--)
638       if (v & b[i])
639       {
640         v >>= S[i];
641         r |= S[i];
642       }
643     return r + 1;
644   }
645   if (sizeof (T) == 16)
646   {
647     unsigned int shift = 64;
648     return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
649                           hb_bit_storage<uint64_t> ((uint64_t) v);
650   }
651 
652   assert (0);
653   return 0; /* Shut up stupid compiler. */
654 }
655 
656 /* Returns the number of zero bits in the least significant side of v */
657 template <typename T>
658 static inline unsigned int
hb_ctz(T v)659 hb_ctz (T v)
660 {
661   if (unlikely (!v)) return 8 * sizeof (T);
662 
663 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
664   if (sizeof (T) <= sizeof (unsigned int))
665     return __builtin_ctz (v);
666 
667   if (sizeof (T) <= sizeof (unsigned long))
668     return __builtin_ctzl (v);
669 
670   if (sizeof (T) <= sizeof (unsigned long long))
671     return __builtin_ctzll (v);
672 #endif
673 
674 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
675   if (sizeof (T) <= sizeof (unsigned int))
676   {
677     unsigned long where;
678     _BitScanForward (&where, v);
679     return where;
680   }
681 # if defined(_WIN64)
682   if (sizeof (T) <= 8)
683   {
684     unsigned long where;
685     _BitScanForward64 (&where, v);
686     return where;
687   }
688 # endif
689 #endif
690 
691   if (sizeof (T) <= 4)
692   {
693     /* "bithacks" */
694     unsigned int c = 32;
695     v &= - (int32_t) v;
696     if (v) c--;
697     if (v & 0x0000FFFF) c -= 16;
698     if (v & 0x00FF00FF) c -= 8;
699     if (v & 0x0F0F0F0F) c -= 4;
700     if (v & 0x33333333) c -= 2;
701     if (v & 0x55555555) c -= 1;
702     return c;
703   }
704   if (sizeof (T) <= 8)
705   {
706     /* "bithacks" */
707     unsigned int c = 64;
708     v &= - (int64_t) (v);
709     if (v) c--;
710     if (v & 0x00000000FFFFFFFFULL) c -= 32;
711     if (v & 0x0000FFFF0000FFFFULL) c -= 16;
712     if (v & 0x00FF00FF00FF00FFULL) c -= 8;
713     if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
714     if (v & 0x3333333333333333ULL) c -= 2;
715     if (v & 0x5555555555555555ULL) c -= 1;
716     return c;
717   }
718   if (sizeof (T) == 16)
719   {
720     unsigned int shift = 64;
721     return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
722                           hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
723   }
724 
725   assert (0);
726   return 0; /* Shut up stupid compiler. */
727 }
728 
729 
730 /*
731  * Tiny stuff.
732  */
733 
734 /* ASCII tag/character handling */
ISALPHA(unsigned char c)735 static inline bool ISALPHA (unsigned char c)
736 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
ISALNUM(unsigned char c)737 static inline bool ISALNUM (unsigned char c)
738 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
ISSPACE(unsigned char c)739 static inline bool ISSPACE (unsigned char c)
740 { return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
TOUPPER(unsigned char c)741 static inline unsigned char TOUPPER (unsigned char c)
742 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
TOLOWER(unsigned char c)743 static inline unsigned char TOLOWER (unsigned char c)
744 { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
ISHEX(unsigned char c)745 static inline bool ISHEX (unsigned char c)
746 { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
TOHEX(uint8_t c)747 static inline unsigned char TOHEX (uint8_t c)
748 { return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; }
FROMHEX(unsigned char c)749 static inline uint8_t FROMHEX (unsigned char c)
750 { return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; }
751 
DIV_CEIL(const unsigned int a,unsigned int b)752 static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
753 { return (a + (b - 1)) / b; }
754 
755 
756 #undef  ARRAY_LENGTH
757 template <typename Type, unsigned int n>
ARRAY_LENGTH(const Type (&)[n])758 static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
759 /* A const version, but does not detect erratically being called on pointers. */
760 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
761 
762 
763 static inline int
hb_memcmp(const void * a,const void * b,unsigned int len)764 hb_memcmp (const void *a, const void *b, unsigned int len)
765 {
766   /* It's illegal to pass NULL to memcmp(), even if len is zero.
767    * So, wrap it.
768    * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
769   if (unlikely (!len)) return 0;
770   return memcmp (a, b, len);
771 }
772 
773 static inline void *
hb_memset(void * s,int c,unsigned int n)774 hb_memset (void *s, int c, unsigned int n)
775 {
776   /* It's illegal to pass NULL to memset(), even if n is zero. */
777   if (unlikely (!n)) return 0;
778   return memset (s, c, n);
779 }
780 
781 static inline unsigned int
hb_ceil_to_4(unsigned int v)782 hb_ceil_to_4 (unsigned int v)
783 {
784   return ((v - 1) | 3) + 1;
785 }
786 
787 template <typename T> static inline bool
hb_in_range(T u,T lo,T hi)788 hb_in_range (T u, T lo, T hi)
789 {
790   static_assert (!hb_is_signed<T>::value, "");
791 
792   /* The casts below are important as if T is smaller than int,
793    * the subtract results will become a signed int! */
794   return (T)(u - lo) <= (T)(hi - lo);
795 }
796 template <typename T> static inline bool
hb_in_ranges(T u,T lo1,T hi1,T lo2,T hi2)797 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
798 {
799   return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
800 }
801 template <typename T> static inline bool
hb_in_ranges(T u,T lo1,T hi1,T lo2,T hi2,T lo3,T hi3)802 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
803 {
804   return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
805 }
806 
807 
808 /*
809  * Overflow checking.
810  */
811 
812 /* Consider __builtin_mul_overflow use here also */
813 static inline bool
hb_unsigned_mul_overflows(unsigned int count,unsigned int size)814 hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
815 {
816   return (size > 0) && (count >= ((unsigned int) -1) / size);
817 }
818 
819 
820 /*
821  * Sort and search.
822  */
823 
824 template <typename K, typename V, typename ...Ts>
825 static int
_hb_cmp_method(const void * pkey,const void * pval,Ts...ds)826 _hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
827 {
828   const K& key = * (const K*) pkey;
829   const V& val = * (const V*) pval;
830 
831   return val.cmp (key, ds...);
832 }
833 
834 template <typename V, typename K, typename ...Ts>
835 static inline bool
hb_bsearch_impl(unsigned * pos,const K & key,V * base,size_t nmemb,size_t stride,int (* compar)(const void * _key,const void * _item,Ts..._ds),Ts...ds)836 hb_bsearch_impl (unsigned *pos, /* Out */
837                  const K& key,
838                  V* base, size_t nmemb, size_t stride,
839                  int (*compar)(const void *_key, const void *_item, Ts... _ds),
840                  Ts... ds)
841 {
842   /* This is our *only* bsearch implementation. */
843 
844   int min = 0, max = (int) nmemb - 1;
845   while (min <= max)
846   {
847     int mid = ((unsigned int) min + (unsigned int) max) / 2;
848 #pragma GCC diagnostic push
849 #pragma GCC diagnostic ignored "-Wcast-align"
850     V* p = (V*) (((const char *) base) + (mid * stride));
851 #pragma GCC diagnostic pop
852     int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...);
853     if (c < 0)
854       max = mid - 1;
855     else if (c > 0)
856       min = mid + 1;
857     else
858     {
859       *pos = mid;
860       return true;
861     }
862   }
863   *pos = min;
864   return false;
865 }
866 
867 template <typename V, typename K>
868 static inline V*
869 hb_bsearch (const K& key, V* base,
870             size_t nmemb, size_t stride = sizeof (V),
871             int (*compar)(const void *_key, const void *_item) = _hb_cmp_method<K, V>)
872 {
873   unsigned pos;
874 #pragma GCC diagnostic push
875 #pragma GCC diagnostic ignored "-Wcast-align"
876   return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar) ?
877          (V*) (((const char *) base) + (pos * stride)) : nullptr;
878 #pragma GCC diagnostic pop
879 }
880 template <typename V, typename K, typename ...Ts>
881 static inline V*
hb_bsearch(const K & key,V * base,size_t nmemb,size_t stride,int (* compar)(const void * _key,const void * _item,Ts..._ds),Ts...ds)882 hb_bsearch (const K& key, V* base,
883             size_t nmemb, size_t stride,
884             int (*compar)(const void *_key, const void *_item, Ts... _ds),
885             Ts... ds)
886 {
887   unsigned pos;
888 #pragma GCC diagnostic push
889 #pragma GCC diagnostic ignored "-Wcast-align"
890   return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar, ds...) ?
891          (V*) (((const char *) base) + (pos * stride)) : nullptr;
892 #pragma GCC diagnostic pop
893 }
894 
895 
896 /* From https://github.com/noporpoise/sort_r
897    Feb 5, 2019 (c8c65c1e)
898    Modified to support optional argument using templates */
899 
900 /* Isaac Turner 29 April 2014 Public Domain */
901 
902 /*
903 hb_qsort function to be exported.
904 Parameters:
905   base is the array to be sorted
906   nel is the number of elements in the array
907   width is the size in bytes of each element of the array
908   compar is the comparison function
909   arg (optional) is a pointer to be passed to the comparison function
910 
911 void hb_qsort(void *base, size_t nel, size_t width,
912               int (*compar)(const void *_a, const void *_b, [void *_arg]),
913               [void *arg]);
914 */
915 
916 #define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
917 
918 /* swap a and b */
919 /* a and b must not be equal! */
sort_r_swap(char * __restrict a,char * __restrict b,size_t w)920 static inline void sort_r_swap(char *__restrict a, char *__restrict b,
921                                size_t w)
922 {
923   char tmp, *end = a+w;
924   for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); }
925 }
926 
927 /* swap a, b iff a>b */
928 /* a and b must not be equal! */
929 /* __restrict is same as restrict but better support on old machines */
930 template <typename ...Ts>
sort_r_cmpswap(char * __restrict a,char * __restrict b,size_t w,int (* compar)(const void * _a,const void * _b,Ts..._ds),Ts...ds)931 static inline int sort_r_cmpswap(char *__restrict a,
932                                  char *__restrict b, size_t w,
933                                  int (*compar)(const void *_a,
934                                                const void *_b,
935                                                Ts... _ds),
936                                  Ts... ds)
937 {
938   if(compar(a, b, ds...) > 0) {
939     sort_r_swap(a, b, w);
940     return 1;
941   }
942   return 0;
943 }
944 
945 /*
946 Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr,
947 with the smallest swap so that the blocks are in the opposite order. Blocks may
948 be internally re-ordered e.g.
949   12345ab  ->   ab34512
950   123abc   ->   abc123
951   12abcde  ->   deabc12
952 */
sort_r_swap_blocks(char * ptr,size_t na,size_t nb)953 static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb)
954 {
955   if(na > 0 && nb > 0) {
956     if(na > nb) { sort_r_swap(ptr, ptr+na, nb); }
957     else { sort_r_swap(ptr, ptr+nb, na); }
958   }
959 }
960 
961 /* Implement recursive quicksort ourselves */
962 /* Note: quicksort is not stable, equivalent values may be swapped */
963 template <typename ...Ts>
sort_r_simple(void * base,size_t nel,size_t w,int (* compar)(const void * _a,const void * _b,Ts..._ds),Ts...ds)964 static inline void sort_r_simple(void *base, size_t nel, size_t w,
965                                  int (*compar)(const void *_a,
966                                                const void *_b,
967                                                Ts... _ds),
968                                  Ts... ds)
969 {
970   char *b = (char *)base, *end = b + nel*w;
971 
972   /* for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
973   printf("\n"); */
974 
975   if(nel < 10) {
976     /* Insertion sort for arbitrarily small inputs */
977     char *pi, *pj;
978     for(pi = b+w; pi < end; pi += w) {
979       for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {}
980     }
981   }
982   else
983   {
984     /* nel > 9; Quicksort */
985 
986     int cmp;
987     char *pl, *ple, *pr, *pre, *pivot;
988     char *last = b+w*(nel-1), *tmp;
989 
990     /*
991     Use median of second, middle and second-last items as pivot.
992     First and last may have been swapped with pivot and therefore be extreme
993     */
994     char *l[3];
995     l[0] = b + w;
996     l[1] = b+w*(nel/2);
997     l[2] = last - w;
998 
999     /* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */
1000 
1001     if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
1002     if(compar(l[1],l[2],ds...) > 0) {
1003       SORT_R_SWAP(l[1], l[2], tmp);
1004       if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
1005     }
1006 
1007     /* swap mid value (l[1]), and last element to put pivot as last element */
1008     if(l[1] != last) { sort_r_swap(l[1], last, w); }
1009 
1010     /*
1011     pl is the next item on the left to be compared to the pivot
1012     pr is the last item on the right that was compared to the pivot
1013     ple is the left position to put the next item that equals the pivot
1014     ple is the last right position where we put an item that equals the pivot
1015                                            v- end (beyond the array)
1016       EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE.
1017       ^- b  ^- ple  ^- pl   ^- pr  ^- pre ^- last (where the pivot is)
1018     Pivot comparison key:
1019       E = equal, L = less than, u = unknown, G = greater than, E = equal
1020     */
1021     pivot = last;
1022     ple = pl = b;
1023     pre = pr = last;
1024 
1025     /*
1026     Strategy:
1027     Loop into the list from the left and right at the same time to find:
1028     - an item on the left that is greater than the pivot
1029     - an item on the right that is less than the pivot
1030     Once found, they are swapped and the loop continues.
1031     Meanwhile items that are equal to the pivot are moved to the edges of the
1032     array.
1033     */
1034     while(pl < pr) {
1035       /* Move left hand items which are equal to the pivot to the far left.
1036          break when we find an item that is greater than the pivot */
1037       for(; pl < pr; pl += w) {
1038         cmp = compar(pl, pivot, ds...);
1039         if(cmp > 0) { break; }
1040         else if(cmp == 0) {
1041           if(ple < pl) { sort_r_swap(ple, pl, w); }
1042           ple += w;
1043         }
1044       }
1045       /* break if last batch of left hand items were equal to pivot */
1046       if(pl >= pr) { break; }
1047       /* Move right hand items which are equal to the pivot to the far right.
1048          break when we find an item that is less than the pivot */
1049       for(; pl < pr; ) {
1050         pr -= w; /* Move right pointer onto an unprocessed item */
1051         cmp = compar(pr, pivot, ds...);
1052         if(cmp == 0) {
1053           pre -= w;
1054           if(pr < pre) { sort_r_swap(pr, pre, w); }
1055         }
1056         else if(cmp < 0) {
1057           if(pl < pr) { sort_r_swap(pl, pr, w); }
1058           pl += w;
1059           break;
1060         }
1061       }
1062     }
1063 
1064     pl = pr; /* pr may have gone below pl */
1065 
1066     /*
1067     Now we need to go from: EEELLLGGGGEEEE
1068                         to: LLLEEEEEEEGGGG
1069     Pivot comparison key:
1070       E = equal, L = less than, u = unknown, G = greater than, E = equal
1071     */
1072     sort_r_swap_blocks(b, ple-b, pl-ple);
1073     sort_r_swap_blocks(pr, pre-pr, end-pre);
1074 
1075     /*for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
1076     printf("\n");*/
1077 
1078     sort_r_simple(b, (pl-ple)/w, w, compar, ds...);
1079     sort_r_simple(end-(pre-pr), (pre-pr)/w, w, compar, ds...);
1080   }
1081 }
1082 
1083 static inline void
hb_qsort(void * base,size_t nel,size_t width,int (* compar)(const void * _a,const void * _b))1084 hb_qsort (void *base, size_t nel, size_t width,
1085           int (*compar)(const void *_a, const void *_b))
1086 {
1087 #if defined(__OPTIMIZE_SIZE__) && !defined(HB_USE_INTERNAL_QSORT)
1088   qsort (base, nel, width, compar);
1089 #else
1090   sort_r_simple (base, nel, width, compar);
1091 #endif
1092 }
1093 
1094 static inline void
hb_qsort(void * base,size_t nel,size_t width,int (* compar)(const void * _a,const void * _b,void * _arg),void * arg)1095 hb_qsort (void *base, size_t nel, size_t width,
1096           int (*compar)(const void *_a, const void *_b, void *_arg),
1097           void *arg)
1098 {
1099 #ifdef HAVE_GNU_QSORT_R
1100   qsort_r (base, nel, width, compar, arg);
1101 #else
1102   sort_r_simple (base, nel, width, compar, arg);
1103 #endif
1104 }
1105 
1106 
1107 template <typename T, typename T2, typename T3> static inline void
hb_stable_sort(T * array,unsigned int len,int (* compar)(const T2 *,const T2 *),T3 * array2)1108 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
1109 {
1110   for (unsigned int i = 1; i < len; i++)
1111   {
1112     unsigned int j = i;
1113     while (j && compar (&array[j - 1], &array[i]) > 0)
1114       j--;
1115     if (i == j)
1116       continue;
1117     /* Move item i to occupy place for item j, shift what's in between. */
1118     {
1119       T t = array[i];
1120       memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
1121       array[j] = t;
1122     }
1123     if (array2)
1124     {
1125       T3 t = array2[i];
1126       memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3));
1127       array2[j] = t;
1128     }
1129   }
1130 }
1131 
1132 template <typename T> static inline void
hb_stable_sort(T * array,unsigned int len,int (* compar)(const T *,const T *))1133 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
1134 {
1135   hb_stable_sort (array, len, compar, (int *) nullptr);
1136 }
1137 
1138 static inline hb_bool_t
hb_codepoint_parse(const char * s,unsigned int len,int base,hb_codepoint_t * out)1139 hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
1140 {
1141   unsigned int v;
1142   const char *p = s;
1143   const char *end = p + len;
1144   if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, base)))
1145     return false;
1146 
1147   *out = v;
1148   return true;
1149 }
1150 
1151 
1152 /* Operators. */
1153 
1154 struct hb_bitwise_and
1155 { HB_PARTIALIZE(2);
1156   template <typename T> constexpr auto
1157   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
1158 }
1159 HB_FUNCOBJ (hb_bitwise_and);
1160 struct hb_bitwise_or
1161 { HB_PARTIALIZE(2);
1162   template <typename T> constexpr auto
1163   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
1164 }
1165 HB_FUNCOBJ (hb_bitwise_or);
1166 struct hb_bitwise_xor
1167 { HB_PARTIALIZE(2);
1168   template <typename T> constexpr auto
1169   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
1170 }
1171 HB_FUNCOBJ (hb_bitwise_xor);
1172 struct hb_bitwise_sub
1173 { HB_PARTIALIZE(2);
1174   template <typename T> constexpr auto
1175   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
1176 }
1177 HB_FUNCOBJ (hb_bitwise_sub);
1178 struct
1179 {
1180   template <typename T> constexpr auto
1181   operator () (const T &a) const HB_AUTO_RETURN (~a)
1182 }
1183 HB_FUNCOBJ (hb_bitwise_neg);
1184 
1185 struct
1186 { HB_PARTIALIZE(2);
1187   template <typename T, typename T2> constexpr auto
1188   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b)
1189 }
1190 HB_FUNCOBJ (hb_add);
1191 struct
1192 { HB_PARTIALIZE(2);
1193   template <typename T, typename T2> constexpr auto
1194   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b)
1195 }
1196 HB_FUNCOBJ (hb_sub);
1197 struct
1198 { HB_PARTIALIZE(2);
1199   template <typename T, typename T2> constexpr auto
1200   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
1201 }
1202 HB_FUNCOBJ (hb_mul);
1203 struct
1204 { HB_PARTIALIZE(2);
1205   template <typename T, typename T2> constexpr auto
1206   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b)
1207 }
1208 HB_FUNCOBJ (hb_div);
1209 struct
1210 { HB_PARTIALIZE(2);
1211   template <typename T, typename T2> constexpr auto
1212   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b)
1213 }
1214 HB_FUNCOBJ (hb_mod);
1215 struct
1216 {
1217   template <typename T> constexpr auto
1218   operator () (const T &a) const HB_AUTO_RETURN (+a)
1219 }
1220 HB_FUNCOBJ (hb_pos);
1221 struct
1222 {
1223   template <typename T> constexpr auto
1224   operator () (const T &a) const HB_AUTO_RETURN (-a)
1225 }
1226 HB_FUNCOBJ (hb_neg);
1227 struct
1228 {
1229   template <typename T> constexpr auto
1230   operator () (T &a) const HB_AUTO_RETURN (++a)
1231 }
1232 HB_FUNCOBJ (hb_inc);
1233 struct
1234 {
1235   template <typename T> constexpr auto
1236   operator () (T &a) const HB_AUTO_RETURN (--a)
1237 }
1238 HB_FUNCOBJ (hb_dec);
1239 
1240 
1241 /* Compiler-assisted vectorization. */
1242 
1243 /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
1244  * basically a fixed-size bitset. */
1245 template <typename elt_t, unsigned int byte_size>
1246 struct hb_vector_size_t
1247 {
operator []hb_vector_size_t1248   elt_t& operator [] (unsigned int i) { return v[i]; }
operator []hb_vector_size_t1249   const elt_t& operator [] (unsigned int i) const { return v[i]; }
1250 
clearhb_vector_size_t1251   void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
1252 
1253   template <typename Op>
processhb_vector_size_t1254   hb_vector_size_t process (const Op& op) const
1255   {
1256     hb_vector_size_t r;
1257     for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
1258       r.v[i] = op (v[i]);
1259     return r;
1260   }
1261   template <typename Op>
processhb_vector_size_t1262   hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
1263   {
1264     hb_vector_size_t r;
1265     for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
1266       r.v[i] = op (v[i], o.v[i]);
1267     return r;
1268   }
operator |hb_vector_size_t1269   hb_vector_size_t operator | (const hb_vector_size_t &o) const
1270   { return process (hb_bitwise_or, o); }
operator &hb_vector_size_t1271   hb_vector_size_t operator & (const hb_vector_size_t &o) const
1272   { return process (hb_bitwise_and, o); }
operator ^hb_vector_size_t1273   hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
1274   { return process (hb_bitwise_xor, o); }
operator ~hb_vector_size_t1275   hb_vector_size_t operator ~ () const
1276   { return process (hb_bitwise_neg); }
1277 
1278   private:
1279   static_assert (0 == byte_size % sizeof (elt_t), "");
1280   elt_t v[byte_size / sizeof (elt_t)];
1281 };
1282 
1283 
1284 #endif /* HB_ALGS_HH */
1285