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