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