hb-algs.hh (49120B)
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 <functional> 40 #include <new> 41 42 /* 43 * Flags 44 */ 45 46 /* Enable bitwise ops on enums marked as flags_t */ 47 /* To my surprise, looks like the function resolver is happy to silently cast 48 * one enum to another... So this doesn't provide the type-checking that I 49 * originally had in mind... :(. 50 * 51 * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163 52 */ 53 #ifdef _MSC_VER 54 # pragma warning(disable:4200) 55 # pragma warning(disable:4800) 56 #endif 57 #define HB_MARK_AS_FLAG_T(T) \ 58 extern "C++" { \ 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 l, T r) { return T ((unsigned) l ^ (unsigned) r); } \ 62 static inline constexpr unsigned operator ~ (T r) { return (~(unsigned) r); } \ 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 static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \ 66 } \ 67 static_assert (true, "") 68 69 /* Useful for set-operations on small enums. 70 * For example, for testing "x ∈ {x1, x2, x3}" use: 71 * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3))) 72 */ 73 #define FLAG(x) (static_assert_expr ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x))) 74 #define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0) 75 #define FLAG_RANGE(x,y) (static_assert_expr ((x) < (y)) + FLAG(y+1) - FLAG(x)) 76 #define FLAG64(x) (static_assert_expr ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x))) 77 #define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0) 78 79 80 /* 81 * Fixed-endian integers / floats. 82 */ 83 84 85 /* Endian swap, used in Windows related backends */ 86 static inline constexpr uint16_t hb_uint16_swap (uint16_t v) 87 { return (v >> 8) | (v << 8); } 88 static inline constexpr uint32_t hb_uint32_swap (uint32_t v) 89 { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } 90 91 template <typename Type> 92 struct __attribute__((packed)) hb_packed_t { Type v; }; 93 94 #ifndef HB_FAST_NUM_ACCESS 95 96 #if defined(__OPTIMIZE__) && \ 97 defined(__BYTE_ORDER) && \ 98 (__BYTE_ORDER == __BIG_ENDIAN || \ 99 (__BYTE_ORDER == __LITTLE_ENDIAN && \ 100 hb_has_builtin(__builtin_bswap16) && \ 101 hb_has_builtin(__builtin_bswap32) && \ 102 hb_has_builtin(__builtin_bswap64))) 103 #define HB_FAST_NUM_ACCESS 1 104 #else 105 #define HB_FAST_NUM_ACCESS 0 106 #endif 107 108 // https://github.com/harfbuzz/harfbuzz/issues/5456 109 #if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 12) 110 #undef HB_FAST_NUM_ACCESS 111 #define HB_FAST_NUM_ACCESS 0 112 #endif 113 114 #endif 115 116 template <bool BE, typename Type, int Bytes = sizeof (Type)> 117 struct HBInt; 118 template <bool BE, typename Type> 119 struct HBInt<BE, Type, 1> 120 { 121 public: 122 HBInt () = default; 123 constexpr HBInt (Type V) : v {uint8_t (V)} {} 124 constexpr operator Type () const { return v; } 125 private: uint8_t v; 126 }; 127 template <bool BE, typename Type> 128 struct HBInt<BE, Type, 2> 129 { 130 public: 131 HBInt () = default; 132 133 HBInt (Type V) 134 #if HB_FAST_NUM_ACCESS 135 { 136 if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) 137 ((hb_packed_t<uint16_t> *) v)->v = V; 138 else 139 ((hb_packed_t<uint16_t> *) v)->v = __builtin_bswap16 (V); 140 } 141 #else 142 : v {BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V ) & 0xFF), 143 BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V >> 8) & 0xFF)} {} 144 #endif 145 146 constexpr operator Type () const 147 { 148 #if HB_FAST_NUM_ACCESS 149 return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? 150 ((const hb_packed_t<uint16_t> *) v)->v 151 : 152 __builtin_bswap16 (((const hb_packed_t<uint16_t> *) v)->v) 153 ; 154 #else 155 return (BE ? (v[0] << 8) : (v[0] )) 156 + (BE ? (v[1] ) : (v[1] << 8)); 157 #endif 158 } 159 private: uint8_t v[2]; 160 }; 161 template <bool BE, typename Type> 162 struct HBInt<BE, Type, 3> 163 { 164 static_assert (!std::is_signed<Type>::value, ""); 165 public: 166 HBInt () = default; 167 constexpr HBInt (Type V) : v {BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 16) & 0xFF), 168 BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V >> 8) & 0xFF), 169 BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V ) & 0xFF)} {} 170 171 constexpr operator Type () const { return (BE ? (v[0] << 16) : (v[0] )) 172 + (BE ? (v[1] << 8) : (v[1] << 8)) 173 + (BE ? (v[2] ) : (v[2] << 16)); } 174 private: uint8_t v[3]; 175 }; 176 template <bool BE, typename Type> 177 struct HBInt<BE, Type, 4> 178 { 179 template <bool, typename, int> 180 friend struct HBFloat; 181 182 public: 183 HBInt () = default; 184 185 HBInt (Type V) 186 #if HB_FAST_NUM_ACCESS 187 { 188 if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) 189 ((hb_packed_t<uint32_t> *) v)->v = V; 190 else 191 ((hb_packed_t<uint32_t> *) v)->v = __builtin_bswap32 (V); 192 } 193 #else 194 : v {BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V ) & 0xFF), 195 BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 8) & 0xFF), 196 BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V >> 16) & 0xFF), 197 BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V >> 24) & 0xFF)} {} 198 #endif 199 200 constexpr operator Type () const { 201 #if HB_FAST_NUM_ACCESS 202 return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? 203 ((const hb_packed_t<uint32_t> *) v)->v 204 : 205 __builtin_bswap32 (((const hb_packed_t<uint32_t> *) v)->v) 206 ; 207 #else 208 return (BE ? (v[0] << 24) : (v[0] )) 209 + (BE ? (v[1] << 16) : (v[1] << 8)) 210 + (BE ? (v[2] << 8) : (v[2] << 16)) 211 + (BE ? (v[3] ) : (v[3] << 24)); 212 #endif 213 } 214 private: uint8_t v[4]; 215 }; 216 template <bool BE, typename Type> 217 struct HBInt<BE, Type, 8> 218 { 219 template <bool, typename, int> 220 friend struct HBFloat; 221 222 public: 223 HBInt () = default; 224 225 HBInt (Type V) 226 #if HB_FAST_NUM_ACCESS 227 { 228 if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) 229 ((hb_packed_t<uint64_t> *) v)->v = V; 230 else 231 ((hb_packed_t<uint64_t> *) v)->v = __builtin_bswap64 (V); 232 } 233 #else 234 : v {BE ? uint8_t ((V >> 56) & 0xFF) : uint8_t ((V ) & 0xFF), 235 BE ? uint8_t ((V >> 48) & 0xFF) : uint8_t ((V >> 8) & 0xFF), 236 BE ? uint8_t ((V >> 40) & 0xFF) : uint8_t ((V >> 16) & 0xFF), 237 BE ? uint8_t ((V >> 32) & 0xFF) : uint8_t ((V >> 24) & 0xFF), 238 BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V >> 32) & 0xFF), 239 BE ? uint8_t ((V >> 16) & 0xFF) : uint8_t ((V >> 40) & 0xFF), 240 BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V >> 48) & 0xFF), 241 BE ? uint8_t ((V ) & 0xFF) : uint8_t ((V >> 56) & 0xFF)} {} 242 #endif 243 244 constexpr operator Type () const { 245 #if HB_FAST_NUM_ACCESS 246 return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? 247 ((const hb_packed_t<uint64_t> *) v)->v 248 : 249 __builtin_bswap64 (((const hb_packed_t<uint64_t> *) v)->v) 250 ; 251 #else 252 return (BE ? (uint64_t (v[0]) << 56) : (uint64_t (v[0]) )) 253 + (BE ? (uint64_t (v[1]) << 48) : (uint64_t (v[1]) << 8)) 254 + (BE ? (uint64_t (v[2]) << 40) : (uint64_t (v[2]) << 16)) 255 + (BE ? (uint64_t (v[3]) << 32) : (uint64_t (v[3]) << 24)) 256 + (BE ? (uint64_t (v[4]) << 24) : (uint64_t (v[4]) << 32)) 257 + (BE ? (uint64_t (v[5]) << 16) : (uint64_t (v[5]) << 40)) 258 + (BE ? (uint64_t (v[6]) << 8) : (uint64_t (v[6]) << 48)) 259 + (BE ? (uint64_t (v[7]) ) : (uint64_t (v[7]) << 56)); 260 #endif 261 } 262 private: uint8_t v[8]; 263 }; 264 265 /* Floats. */ 266 267 template <bool BE, typename Type, int Bytes> 268 struct HBFloat 269 { 270 using IntType = typename std::conditional<Bytes == 4, uint32_t, uint64_t>::type; 271 272 public: 273 HBFloat () = default; 274 275 HBFloat (Type V) 276 { 277 #if HB_FAST_NUM_ACCESS 278 { 279 if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) 280 { 281 ((hb_packed_t<Type> *) v)->v = V; 282 return; 283 } 284 } 285 #endif 286 287 union { 288 hb_packed_t<Type> f; 289 hb_packed_t<IntType> i; 290 } u = {{V}}; 291 292 const HBInt<BE, IntType> I = u.i.v; 293 for (unsigned i = 0; i < Bytes; i++) 294 v[i] = I.v[i]; 295 } 296 297 /* c++14 constexpr */ operator Type () const 298 { 299 #if HB_FAST_NUM_ACCESS 300 { 301 if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) 302 return ((const hb_packed_t<Type> *) v)->v; 303 } 304 #endif 305 306 HBInt<BE, IntType> I; 307 for (unsigned i = 0; i < Bytes; i++) 308 I.v[i] = v[i]; 309 310 union { 311 hb_packed_t<IntType> i; 312 hb_packed_t<Type> f; 313 } u = {{I}}; 314 315 return u.f.v; 316 } 317 private: uint8_t v[Bytes]; 318 }; 319 320 321 /* We want our rounding towards +infinity. */ 322 static inline double 323 _hb_roundf (double x) { return floor (x + .5); } 324 325 static inline float 326 _hb_roundf (float x) { return floorf (x + .5f); } 327 328 #define roundf(x) _hb_roundf(x) 329 330 static inline void 331 hb_sincos (float rotation, float &s, float &c) 332 { 333 #ifdef HAVE_SINCOSF 334 sincosf (rotation, &s, &c); 335 #else 336 c = cosf (rotation); 337 s = sinf (rotation); 338 #endif 339 } 340 static inline void 341 hb_sincos (double rotation, double &s, double &c) 342 { 343 #ifdef HAVE_SINCOS 344 sincos (rotation, &s, &c); 345 #else 346 c = cos (rotation); 347 s = sin (rotation); 348 #endif 349 } 350 351 352 /* Encodes three unsigned integers in one 64-bit number. If the inputs have more than 21 bits, 353 * values will be truncated / overlap, and might not decode exactly. */ 354 #define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z)) 355 #define HB_CODEPOINT_DECODE3_1(v) ((hb_codepoint_t) ((v) >> 42)) 356 #define HB_CODEPOINT_DECODE3_2(v) ((hb_codepoint_t) ((v) >> 21) & 0x1FFFFFu) 357 #define HB_CODEPOINT_DECODE3_3(v) ((hb_codepoint_t) (v) & 0x1FFFFFu) 358 359 /* Custom encoding used by hb-ucd. */ 360 #define HB_CODEPOINT_ENCODE3_11_7_14(x,y,z) (((uint32_t) ((x) & 0x07FFu) << 21) | (((uint32_t) (y) & 0x007Fu) << 14) | (uint32_t) ((z) & 0x3FFFu)) 361 #define HB_CODEPOINT_DECODE3_11_7_14_1(v) ((hb_codepoint_t) ((v) >> 21)) 362 #define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300) 363 #define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu) 364 365 366 struct 367 { 368 /* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */ 369 template <typename T> constexpr auto 370 operator () (T&& v) const HB_AUTO_RETURN ( std::forward<T> (v) ) 371 } 372 HB_FUNCOBJ (hb_identity); 373 struct 374 { 375 /* Like identity(), but only retains lvalue-references. Rvalues are returned as rvalues. */ 376 template <typename T> constexpr T& 377 operator () (T& v) const { return v; } 378 379 template <typename T> constexpr hb_remove_reference<T> 380 operator () (T&& v) const { return v; } 381 } 382 HB_FUNCOBJ (hb_lidentity); 383 struct 384 { 385 /* Like identity(), but always returns rvalue. */ 386 template <typename T> constexpr hb_remove_reference<T> 387 operator () (T&& v) const { return v; } 388 } 389 HB_FUNCOBJ (hb_ridentity); 390 391 struct 392 { 393 template <typename T> constexpr bool 394 operator () (T&& v) const { return bool (std::forward<T> (v)); } 395 } 396 HB_FUNCOBJ (hb_bool); 397 398 399 /* The MIT License 400 401 Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com) 402 403 Permission is hereby granted, free of charge, to any person 404 obtaining a copy of this software and associated documentation 405 files (the "Software"), to deal in the Software without 406 restriction, including without limitation the rights to use, copy, 407 modify, merge, publish, distribute, sublicense, and/or sell copies 408 of the Software, and to permit persons to whom the Software is 409 furnished to do so, subject to the following conditions: 410 411 The above copyright notice and this permission notice shall be 412 included in all copies or substantial portions of the Software. 413 414 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 415 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 416 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 417 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 418 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 419 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 420 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 421 SOFTWARE. 422 */ 423 424 425 // Compression function for Merkle-Damgard construction. 426 // This function is generated using the framework provided. 427 #define fasthash_mix(h) ( \ 428 (void) ((h) ^= (h) >> 23), \ 429 (void) ((h) *= 0x2127599bf4325c37ULL), \ 430 (h) ^= (h) >> 47) 431 432 static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) 433 { 434 struct __attribute__((packed)) packed_uint64_t { uint64_t v; }; 435 const uint64_t m = 0x880355f21e6d1965ULL; 436 const packed_uint64_t *pos = (const packed_uint64_t *)buf; 437 const packed_uint64_t *end = pos + (len / 8); 438 const unsigned char *pos2; 439 uint64_t h = seed ^ (len * m); 440 uint64_t v; 441 442 #ifndef HB_OPTIMIZE_SIZE 443 if (((uintptr_t) pos & 7) == 0) 444 { 445 while (pos != end) 446 { 447 #pragma GCC diagnostic push 448 #pragma GCC diagnostic ignored "-Wcast-align" 449 v = * (const uint64_t *) (pos++); 450 #pragma GCC diagnostic pop 451 h ^= fasthash_mix(v); 452 h *= m; 453 } 454 } 455 else 456 #endif 457 { 458 while (pos != end) 459 { 460 v = pos++->v; 461 h ^= fasthash_mix(v); 462 h *= m; 463 } 464 } 465 466 pos2 = (const unsigned char*)pos; 467 v = 0; 468 469 switch (len & 7) { 470 case 7: v ^= (uint64_t)pos2[6] << 48; HB_FALLTHROUGH; 471 case 6: v ^= (uint64_t)pos2[5] << 40; HB_FALLTHROUGH; 472 case 5: v ^= (uint64_t)pos2[4] << 32; HB_FALLTHROUGH; 473 case 4: v ^= (uint64_t)pos2[3] << 24; HB_FALLTHROUGH; 474 case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH; 475 case 2: v ^= (uint64_t)pos2[1] << 8; HB_FALLTHROUGH; 476 case 1: v ^= (uint64_t)pos2[0]; 477 h ^= fasthash_mix(v); 478 h *= m; 479 } 480 481 return fasthash_mix(h); 482 } 483 484 static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed) 485 { 486 // the following trick converts the 64-bit hashcode to Fermat 487 // residue, which shall retain information from both the higher 488 // and lower parts of hashcode. 489 uint64_t h = fasthash64(buf, len, seed); 490 return h - (h >> 32); 491 } 492 493 struct 494 { 495 private: 496 497 template <typename T> constexpr auto 498 impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) 499 500 // Horrible: std:hash() of integers seems to be identity in gcc / clang?! 501 // https://github.com/harfbuzz/harfbuzz/pull/4228 502 // 503 // For performance characteristics see: 504 // https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537 505 template <typename T, 506 hb_enable_if (std::is_integral<T>::value && sizeof (T) <= sizeof (uint32_t))> constexpr auto 507 impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) v * 2654435761u /* Knuh's multiplicative hash */) 508 template <typename T, 509 hb_enable_if (std::is_integral<T>::value && sizeof (T) > sizeof (uint32_t))> constexpr auto 510 impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */) 511 512 template <typename T, 513 hb_enable_if (std::is_floating_point<T>::value)> constexpr auto 514 impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, fasthash32 (std::addressof (v), sizeof (T), 0xf437ffe6)) 515 516 template <typename T> constexpr auto 517 impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v))) 518 519 public: 520 521 template <typename T> constexpr auto 522 operator () (const T& v) const HB_RETURN (uint32_t, impl (v, hb_prioritize)) 523 } 524 HB_FUNCOBJ (hb_hash); 525 526 527 struct 528 { 529 private: 530 531 /* Pointer-to-member-function. */ 532 template <typename Appl, typename T, typename ...Ts> auto 533 impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN 534 ((hb_deref (std::forward<T> (v)).*std::forward<Appl> (a)) (std::forward<Ts> (ds)...)) 535 536 /* Pointer-to-member. */ 537 template <typename Appl, typename T> auto 538 impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN 539 ((hb_deref (std::forward<T> (v))).*std::forward<Appl> (a)) 540 541 /* Operator(). */ 542 template <typename Appl, typename ...Ts> auto 543 impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN 544 (hb_deref (std::forward<Appl> (a)) (std::forward<Ts> (ds)...)) 545 546 public: 547 548 template <typename Appl, typename ...Ts> auto 549 operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN 550 ( 551 impl (std::forward<Appl> (a), 552 hb_prioritize, 553 std::forward<Ts> (ds)...) 554 ) 555 } 556 HB_FUNCOBJ (hb_invoke); 557 558 template <unsigned Pos, typename Appl, typename V> 559 struct hb_partial_t 560 { 561 hb_partial_t (Appl a, V v) : a (a), v (v) {} 562 563 static_assert (Pos > 0, ""); 564 565 template <typename ...Ts, 566 unsigned P = Pos, 567 hb_enable_if (P == 1)> auto 568 operator () (Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl), 569 hb_declval (V), 570 hb_declval (Ts)...)) 571 { 572 return hb_invoke (std::forward<Appl> (a), 573 std::forward<V> (v), 574 std::forward<Ts> (ds)...); 575 } 576 template <typename T0, typename ...Ts, 577 unsigned P = Pos, 578 hb_enable_if (P == 2)> auto 579 operator () (T0&& d0, Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl), 580 hb_declval (T0), 581 hb_declval (V), 582 hb_declval (Ts)...)) 583 { 584 return hb_invoke (std::forward<Appl> (a), 585 std::forward<T0> (d0), 586 std::forward<V> (v), 587 std::forward<Ts> (ds)...); 588 } 589 590 private: 591 hb_reference_wrapper<Appl> a; 592 V v; 593 }; 594 template <unsigned Pos=1, typename Appl, typename V> 595 auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN 596 (( hb_partial_t<Pos, Appl, V> (a, v) )) 597 598 /* The following, HB_PARTIALIZE, macro uses a particular corner-case 599 * of C++11 that is not particularly well-supported by all compilers. 600 * What's happening is that it's using "this" in a trailing return-type 601 * via decltype(). Broken compilers deduce the type of "this" pointer 602 * in that context differently from what it resolves to in the body 603 * of the function. 604 * 605 * One probable cause of this is that at the time of trailing return 606 * type declaration, "this" points to an incomplete type, whereas in 607 * the function body the type is complete. That doesn't justify the 608 * error in any way, but is probably what's happening. 609 * 610 * In the case of MSVC, we get around this by using C++14 "decltype(auto)" 611 * which deduces the type from the actual return statement. For gcc 4.8 612 * we use "+this" instead of "this" which produces an rvalue that seems 613 * to be deduced as the same type with this particular compiler, and seem 614 * to be fine as default code path as well. 615 */ 616 #ifdef _MSC_VER 617 /* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \ 618 #define HB_PARTIALIZE(Pos) \ 619 template <typename _T> \ 620 decltype(auto) operator () (_T&& _v) const \ 621 { return hb_partial<Pos> (this, std::forward<_T> (_v)); } \ 622 static_assert (true, "") 623 #else 624 /* https://github.com/harfbuzz/harfbuzz/issues/1724 */ 625 #define HB_PARTIALIZE(Pos) \ 626 template <typename _T> \ 627 auto operator () (_T&& _v) const HB_AUTO_RETURN \ 628 (hb_partial<Pos> (+this, std::forward<_T> (_v))) \ 629 static_assert (true, "") 630 #endif 631 632 633 struct 634 { 635 private: 636 637 template <typename Pred, typename Val> auto 638 impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN 639 ( 640 hb_deref (std::forward<Pred> (p)).has (std::forward<Val> (v)) 641 ) 642 643 template <typename Pred, typename Val> auto 644 impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN 645 ( 646 hb_invoke (std::forward<Pred> (p), 647 std::forward<Val> (v)) 648 ) 649 650 public: 651 652 template <typename Pred, typename Val> auto 653 operator () (Pred&& p, Val &&v) const HB_RETURN (bool, 654 impl (std::forward<Pred> (p), 655 std::forward<Val> (v), 656 hb_prioritize) 657 ) 658 } 659 HB_FUNCOBJ (hb_has); 660 661 struct 662 { 663 private: 664 665 template <typename Pred, typename Val> auto 666 impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN 667 ( 668 hb_has (std::forward<Pred> (p), 669 std::forward<Val> (v)) 670 ) 671 672 template <typename Pred, typename Val> auto 673 impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN 674 ( 675 std::forward<Pred> (p) == std::forward<Val> (v) 676 ) 677 678 public: 679 680 template <typename Pred, typename Val> auto 681 operator () (Pred&& p, Val &&v) const HB_RETURN (bool, 682 impl (std::forward<Pred> (p), 683 std::forward<Val> (v), 684 hb_prioritize) 685 ) 686 } 687 HB_FUNCOBJ (hb_match); 688 689 struct 690 { 691 private: 692 693 template <typename Proj, typename Val> auto 694 impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN 695 ( 696 hb_deref (std::forward<Proj> (f)).get (std::forward<Val> (v)) 697 ) 698 699 template <typename Proj, typename Val> auto 700 impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN 701 ( 702 hb_invoke (std::forward<Proj> (f), 703 std::forward<Val> (v)) 704 ) 705 706 template <typename Proj, typename Val> auto 707 impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN 708 ( 709 std::forward<Proj> (f)[std::forward<Val> (v)] 710 ) 711 712 public: 713 714 template <typename Proj, typename Val> auto 715 operator () (Proj&& f, Val &&v) const HB_AUTO_RETURN 716 ( 717 impl (std::forward<Proj> (f), 718 std::forward<Val> (v), 719 hb_prioritize) 720 ) 721 } 722 HB_FUNCOBJ (hb_get); 723 724 struct 725 { 726 private: 727 728 template <typename T1, typename T2> auto 729 impl (T1&& v1, T2 &&v2, hb_priority<3>) const HB_AUTO_RETURN 730 ( 731 std::forward<T2> (v2).cmp (std::forward<T1> (v1)) == 0 732 ) 733 734 template <typename T1, typename T2> auto 735 impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN 736 ( 737 std::forward<T1> (v1).cmp (std::forward<T2> (v2)) == 0 738 ) 739 740 template <typename T1, typename T2> auto 741 impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN 742 ( 743 std::forward<T1> (v1) == std::forward<T2> (v2) 744 ) 745 746 template <typename T1, typename T2> auto 747 impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN 748 ( 749 std::forward<T2> (v2) == std::forward<T1> (v1) 750 ) 751 752 public: 753 754 template <typename T1, typename T2> auto 755 operator () (T1&& v1, T2 &&v2) const HB_AUTO_RETURN 756 ( 757 impl (std::forward<T1> (v1), 758 std::forward<T2> (v2), 759 hb_prioritize) 760 ) 761 } 762 HB_FUNCOBJ (hb_equal); 763 764 struct 765 { 766 template <typename T> void 767 operator () (T& a, T& b) const 768 { 769 using std::swap; // allow ADL 770 swap (a, b); 771 } 772 } 773 HB_FUNCOBJ (hb_swap); 774 775 776 template <typename T1, typename T2> 777 struct hb_pair_t 778 { 779 typedef T1 first_t; 780 typedef T2 second_t; 781 typedef hb_pair_t<T1, T2> pair_t; 782 783 template <typename U1 = T1, typename U2 = T2, 784 hb_enable_if (std::is_default_constructible<U1>::value && 785 std::is_default_constructible<U2>::value)> 786 hb_pair_t () : first (), second () {} 787 hb_pair_t (T1 a, T2 b) : first (std::forward<T1> (a)), second (std::forward<T2> (b)) {} 788 789 template <typename Q1, typename Q2, 790 hb_enable_if (hb_is_convertible (T1, Q1) && 791 hb_is_convertible (T2, Q2))> 792 operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); } 793 794 hb_pair_t<T1, T2> reverse () const 795 { return hb_pair_t<T1, T2> (second, first); } 796 797 bool operator == (const pair_t& o) const { return first == o.first && second == o.second; } 798 bool operator != (const pair_t& o) const { return !(*this == o); } 799 bool operator < (const pair_t& o) const { return first < o.first || (first == o.first && second < o.second); } 800 bool operator >= (const pair_t& o) const { return !(*this < o); } 801 bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); } 802 bool operator <= (const pair_t& o) const { return !(*this > o); } 803 804 static int cmp (const void *pa, const void *pb) 805 { 806 pair_t *a = (pair_t *) pa; 807 pair_t *b = (pair_t *) pb; 808 809 if (a->first < b->first) return -1; 810 if (a->first > b->first) return +1; 811 if (a->second < b->second) return -1; 812 if (a->second > b->second) return +1; 813 return 0; 814 } 815 816 friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept 817 { 818 hb_swap (a.first, b.first); 819 hb_swap (a.second, b.second); 820 } 821 822 823 T1 first; 824 T2 second; 825 }; 826 template <typename T1, typename T2> static inline hb_pair_t<T1, T2> 827 hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); } 828 829 typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t; 830 831 struct 832 { 833 template <typename Pair> constexpr typename Pair::first_t 834 operator () (const Pair& pair) const { return pair.first; } 835 } 836 HB_FUNCOBJ (hb_first); 837 838 struct 839 { 840 template <typename Pair> constexpr typename Pair::second_t 841 operator () (const Pair& pair) const { return pair.second; } 842 } 843 HB_FUNCOBJ (hb_second); 844 845 /* Note. In min/max impl, we can use hb_type_identity<T> for second argument. 846 * However, that would silently convert between different-signedness integers. 847 * Instead we accept two different types, such that compiler can err if 848 * comparing integers of different signedness. */ 849 struct 850 { 851 template <typename T, typename T2> constexpr auto 852 operator () (T&& a, T2&& b) const HB_AUTO_RETURN 853 (a <= b ? a : b) 854 } 855 HB_FUNCOBJ (hb_min); 856 struct 857 { 858 template <typename T, typename T2> constexpr auto 859 operator () (T&& a, T2&& b) const HB_AUTO_RETURN 860 (a >= b ? a : b) 861 } 862 HB_FUNCOBJ (hb_max); 863 struct 864 { 865 template <typename T, typename T2, typename T3> constexpr auto 866 operator () (T&& x, T2&& min, T3&& max) const HB_AUTO_RETURN 867 (hb_min (hb_max (std::forward<T> (x), std::forward<T2> (min)), std::forward<T3> (max))) 868 } 869 HB_FUNCOBJ (hb_clamp); 870 871 /* 872 * Bithacks. 873 */ 874 875 /* Return the number of 1 bits in a uint8_t; faster than hb_popcount() */ 876 static inline unsigned 877 hb_popcount8 (uint8_t v) 878 { 879 static const uint8_t popcount4[16] = { 880 0, 1, 1, 2, 1, 2, 2, 3, 881 1, 2, 2, 3, 2, 3, 3, 4 882 }; 883 return popcount4[v & 0xF] + popcount4[v >> 4]; 884 } 885 886 /* Return the number of 1 bits in v. */ 887 template <typename T> 888 static inline unsigned int 889 hb_popcount (T v) 890 { 891 #if hb_has_builtin(__builtin_popcount) 892 if (sizeof (T) <= sizeof (unsigned int)) 893 return __builtin_popcount (v); 894 #endif 895 896 #if hb_has_builtin(__builtin_popcountl) 897 if (sizeof (T) <= sizeof (unsigned long)) 898 return __builtin_popcountl (v); 899 #endif 900 901 #if hb_has_builtin(__builtin_popcountll) 902 if (sizeof (T) <= sizeof (unsigned long long)) 903 return __builtin_popcountll (v); 904 #endif 905 906 if (sizeof (T) <= 4) 907 { 908 /* "HACKMEM 169" */ 909 uint32_t y; 910 y = (v >> 1) &033333333333; 911 y = v - y - ((y >>1) & 033333333333); 912 return (((y + (y >> 3)) & 030707070707) % 077); 913 } 914 915 if (sizeof (T) == 8) 916 { 917 uint64_t y = (uint64_t) v; 918 y -= ((y >> 1) & 0x5555555555555555ull); 919 y = (y & 0x3333333333333333ull) + (y >> 2 & 0x3333333333333333ull); 920 return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0full) * 0x101010101010101ull >> 56; 921 } 922 923 if (sizeof (T) == 16) 924 { 925 unsigned int shift = 64; 926 return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift)); 927 } 928 929 assert (0); 930 return 0; /* Shut up stupid compiler. */ 931 } 932 933 /* Returns the number of bits needed to store number */ 934 template <typename T> 935 static inline unsigned int 936 hb_bit_storage (T v) 937 { 938 if (unlikely (!v)) return 0; 939 940 #if hb_has_builtin(__builtin_clz) 941 if (sizeof (T) <= sizeof (unsigned int)) 942 return sizeof (unsigned int) * 8 - __builtin_clz (v); 943 #endif 944 945 #if hb_has_builtin(__builtin_clzl) 946 if (sizeof (T) <= sizeof (unsigned long)) 947 return sizeof (unsigned long) * 8 - __builtin_clzl (v); 948 #endif 949 950 #if hb_has_builtin(__builtin_clzll) 951 if (sizeof (T) <= sizeof (unsigned long long)) 952 return sizeof (unsigned long long) * 8 - __builtin_clzll (v); 953 #endif 954 955 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4)) 956 if (sizeof (T) <= sizeof (unsigned int)) 957 { 958 unsigned long where; 959 _BitScanReverse (&where, v); 960 return 1 + where; 961 } 962 # if defined(_WIN64) 963 if (sizeof (T) <= 8) 964 { 965 unsigned long where; 966 _BitScanReverse64 (&where, v); 967 return 1 + where; 968 } 969 # endif 970 #endif 971 972 if (sizeof (T) <= 4) 973 { 974 /* "bithacks" */ 975 const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; 976 const unsigned int S[] = {1, 2, 4, 8, 16}; 977 unsigned int r = 0; 978 for (int i = 4; i >= 0; i--) 979 if (v & b[i]) 980 { 981 v >>= S[i]; 982 r |= S[i]; 983 } 984 return r + 1; 985 } 986 if (sizeof (T) <= 8) 987 { 988 /* "bithacks" */ 989 const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL}; 990 const unsigned int S[] = {1, 2, 4, 8, 16, 32}; 991 unsigned int r = 0; 992 for (int i = 5; i >= 0; i--) 993 if (v & b[i]) 994 { 995 v >>= S[i]; 996 r |= S[i]; 997 } 998 return r + 1; 999 } 1000 if (sizeof (T) == 16) 1001 { 1002 unsigned int shift = 64; 1003 return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift : 1004 hb_bit_storage<uint64_t> ((uint64_t) v); 1005 } 1006 1007 assert (0); 1008 return 0; /* Shut up stupid compiler. */ 1009 } 1010 1011 /* Returns the number of zero bits in the least significant side of v */ 1012 template <typename T> 1013 static inline unsigned int 1014 hb_ctz (T v) 1015 { 1016 if (unlikely (!v)) return 8 * sizeof (T); 1017 1018 #if hb_has_builtin(__builtin_ctz) 1019 if (sizeof (T) <= sizeof (unsigned int)) 1020 return __builtin_ctz (v); 1021 #endif 1022 1023 #if hb_has_builtin(__builtin_ctzl) 1024 if (sizeof (T) <= sizeof (unsigned long)) 1025 return __builtin_ctzl (v); 1026 #endif 1027 1028 #if hb_has_builtin(__builtin_ctzll) 1029 if (sizeof (T) <= sizeof (unsigned long long)) 1030 return __builtin_ctzll (v); 1031 #endif 1032 1033 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4)) 1034 if (sizeof (T) <= sizeof (unsigned int)) 1035 { 1036 unsigned long where; 1037 _BitScanForward (&where, v); 1038 return where; 1039 } 1040 # if defined(_WIN64) 1041 if (sizeof (T) <= 8) 1042 { 1043 unsigned long where; 1044 _BitScanForward64 (&where, v); 1045 return where; 1046 } 1047 # endif 1048 #endif 1049 1050 if (sizeof (T) <= 4) 1051 { 1052 /* "bithacks" */ 1053 unsigned int c = 32; 1054 v &= - (int32_t) v; 1055 if (v) c--; 1056 if (v & 0x0000FFFF) c -= 16; 1057 if (v & 0x00FF00FF) c -= 8; 1058 if (v & 0x0F0F0F0F) c -= 4; 1059 if (v & 0x33333333) c -= 2; 1060 if (v & 0x55555555) c -= 1; 1061 return c; 1062 } 1063 if (sizeof (T) <= 8) 1064 { 1065 /* "bithacks" */ 1066 unsigned int c = 64; 1067 v &= - (int64_t) (v); 1068 if (v) c--; 1069 if (v & 0x00000000FFFFFFFFULL) c -= 32; 1070 if (v & 0x0000FFFF0000FFFFULL) c -= 16; 1071 if (v & 0x00FF00FF00FF00FFULL) c -= 8; 1072 if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4; 1073 if (v & 0x3333333333333333ULL) c -= 2; 1074 if (v & 0x5555555555555555ULL) c -= 1; 1075 return c; 1076 } 1077 if (sizeof (T) == 16) 1078 { 1079 unsigned int shift = 64; 1080 return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) : 1081 hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift; 1082 } 1083 1084 assert (0); 1085 return 0; /* Shut up stupid compiler. */ 1086 } 1087 1088 1089 /* 1090 * Tiny stuff. 1091 */ 1092 1093 /* ASCII tag/character handling */ 1094 static inline bool ISALPHA (unsigned char c) 1095 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } 1096 static inline bool ISALNUM (unsigned char c) 1097 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } 1098 static inline bool ISSPACE (unsigned char c) 1099 { return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } 1100 static inline unsigned char TOUPPER (unsigned char c) 1101 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } 1102 static inline unsigned char TOLOWER (unsigned char c) 1103 { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } 1104 static inline bool ISHEX (unsigned char c) 1105 { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } 1106 static inline unsigned char TOHEX (uint8_t c) 1107 { return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; } 1108 static inline uint8_t FROMHEX (unsigned char c) 1109 { return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; } 1110 1111 static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b) 1112 { return (a + (b - 1)) / b; } 1113 1114 1115 #undef ARRAY_LENGTH 1116 template <typename Type, unsigned int n> 1117 static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; } 1118 /* A const version, but does not detect erratically being called on pointers. */ 1119 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0]))) 1120 1121 1122 static inline void * 1123 hb_memcpy (void *__restrict dst, const void *__restrict src, size_t len) 1124 { 1125 /* It's illegal to pass 0 as size to memcpy. */ 1126 if (unlikely (!len)) return dst; 1127 return memcpy (dst, src, len); 1128 } 1129 1130 static inline int 1131 hb_memcmp (const void *a, const void *b, unsigned int len) 1132 { 1133 /* It's illegal to pass NULL to memcmp(), even if len is zero. 1134 * So, wrap it. 1135 * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ 1136 if (unlikely (!len)) return 0; 1137 return memcmp (a, b, len); 1138 } 1139 1140 static inline void * 1141 hb_memset (void *s, int c, unsigned int n) 1142 { 1143 /* It's illegal to pass NULL to memset(), even if n is zero. */ 1144 if (unlikely (!n)) return s; 1145 return memset (s, c, n); 1146 } 1147 1148 static inline unsigned int 1149 hb_ceil_to_4 (unsigned int v) 1150 { 1151 return ((v - 1) | 3) + 1; 1152 } 1153 1154 template <typename T> static inline bool 1155 hb_in_range (T u, T lo, T hi) 1156 { 1157 static_assert (!std::is_signed<T>::value, ""); 1158 1159 /* The casts below are important as if T is smaller than int, 1160 * the subtract results will become a signed int! */ 1161 return (T)(u - lo) <= (T)(hi - lo); 1162 } 1163 template <typename T> static inline bool 1164 hb_in_ranges (T u, T lo1, T hi1) 1165 { 1166 return hb_in_range (u, lo1, hi1); 1167 } 1168 template <typename T, typename ...Ts> static inline bool 1169 hb_in_ranges (T u, T lo1, T hi1, Ts... ds) 1170 { 1171 return hb_in_range<T> (u, lo1, hi1) || hb_in_ranges<T> (u, ds...); 1172 } 1173 1174 1175 /* 1176 * Overflow checking. 1177 */ 1178 1179 static inline bool 1180 hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr) 1181 { 1182 #if hb_has_builtin(__builtin_mul_overflow) 1183 unsigned stack_result; 1184 if (!result) 1185 result = &stack_result; 1186 return __builtin_mul_overflow (count, size, result); 1187 #endif 1188 1189 if (result) 1190 *result = count * size; 1191 return (size > 0) && (count >= ((unsigned int) -1) / size); 1192 } 1193 1194 1195 /* 1196 * Sort and search. 1197 */ 1198 1199 template <typename K, typename V, typename ...Ts> 1200 static int 1201 _hb_cmp_method (const void *pkey, const void *pval, Ts... ds) 1202 { 1203 const K& key = * (const K*) pkey; 1204 const V& val = * (const V*) pval; 1205 1206 return val.cmp (key, ds...); 1207 } 1208 1209 template <typename K, typename V> 1210 static int 1211 _hb_cmp_operator (const void *pkey, const void *pval) 1212 { 1213 const K& key = * (const K*) pkey; 1214 const V& val = * (const V*) pval; 1215 1216 if (key < val) return -1; 1217 if (key > val) return 1; 1218 return 0; 1219 } 1220 1221 template <typename V, typename K, typename ...Ts> 1222 HB_HOT 1223 static inline bool 1224 hb_bsearch_impl (unsigned *pos, /* Out */ 1225 const K& key, 1226 V* base, size_t nmemb, size_t stride, 1227 int (*compar)(const void *_key, const void *_item, Ts... _ds), 1228 Ts... ds) 1229 { 1230 /* This is our *only* bsearch implementation. */ 1231 1232 int min = 0, max = (int) nmemb - 1; 1233 while (min <= max) 1234 { 1235 int mid = ((unsigned int) min + (unsigned int) max) / 2; 1236 #pragma GCC diagnostic push 1237 #pragma GCC diagnostic ignored "-Wcast-align" 1238 V* p = (V*) (((const char *) base) + (mid * stride)); 1239 #pragma GCC diagnostic pop 1240 int c = compar ((const void *) std::addressof (key), (const void *) p, ds...); 1241 if (c < 0) 1242 max = mid - 1; 1243 else if (c > 0) 1244 min = mid + 1; 1245 else 1246 { 1247 *pos = mid; 1248 return true; 1249 } 1250 } 1251 *pos = min; 1252 return false; 1253 } 1254 1255 template <typename V, typename K> 1256 static inline V* 1257 hb_bsearch (const K& key, V* base, 1258 size_t nmemb, size_t stride = sizeof (V), 1259 int (*compar)(const void *_key, const void *_item) = _hb_cmp_method<K, V>) 1260 { 1261 unsigned pos; 1262 #pragma GCC diagnostic push 1263 #pragma GCC diagnostic ignored "-Wcast-align" 1264 return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar) ? 1265 (V*) (((const char *) base) + (pos * stride)) : nullptr; 1266 #pragma GCC diagnostic pop 1267 } 1268 template <typename V, typename K, typename ...Ts> 1269 static inline V* 1270 hb_bsearch (const K& key, V* base, 1271 size_t nmemb, size_t stride, 1272 int (*compar)(const void *_key, const void *_item, Ts... _ds), 1273 Ts... ds) 1274 { 1275 unsigned pos; 1276 #pragma GCC diagnostic push 1277 #pragma GCC diagnostic ignored "-Wcast-align" 1278 return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar, ds...) ? 1279 (V*) (((const char *) base) + (pos * stride)) : nullptr; 1280 #pragma GCC diagnostic pop 1281 } 1282 1283 1284 /* From https://github.com/noporpoise/sort_r 1285 Feb 5, 2019 (c8c65c1e) 1286 Modified to support optional argument using templates */ 1287 1288 /* Isaac Turner 29 April 2014 Public Domain */ 1289 1290 /* 1291 hb_qsort function to be exported. 1292 Parameters: 1293 base is the array to be sorted 1294 nel is the number of elements in the array 1295 width is the size in bytes of each element of the array 1296 compar is the comparison function 1297 arg (optional) is a pointer to be passed to the comparison function 1298 1299 void hb_qsort(void *base, size_t nel, size_t width, 1300 int (*compar)(const void *_a, const void *_b, [void *_arg]), 1301 [void *arg]); 1302 */ 1303 1304 #define SORT_R_SWAP(a,b,tmp) ((void) ((tmp) = (a)), (void) ((a) = (b)), (b) = (tmp)) 1305 1306 /* swap a and b */ 1307 /* a and b must not be equal! */ 1308 static inline void sort_r_swap(char *__restrict a, char *__restrict b, 1309 size_t w) 1310 { 1311 char tmp, *end = a+w; 1312 for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); } 1313 } 1314 1315 /* swap a, b iff a>b */ 1316 /* a and b must not be equal! */ 1317 /* __restrict is same as restrict but better support on old machines */ 1318 template <typename ...Ts> 1319 static inline int sort_r_cmpswap(char *__restrict a, 1320 char *__restrict b, size_t w, 1321 int (*compar)(const void *_a, 1322 const void *_b, 1323 Ts... _ds), 1324 Ts... ds) 1325 { 1326 if(compar(a, b, ds...) > 0) { 1327 sort_r_swap(a, b, w); 1328 return 1; 1329 } 1330 return 0; 1331 } 1332 1333 /* 1334 Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr, 1335 with the smallest swap so that the blocks are in the opposite order. Blocks may 1336 be internally re-ordered e.g. 1337 12345ab -> ab34512 1338 123abc -> abc123 1339 12abcde -> deabc12 1340 */ 1341 static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb) 1342 { 1343 if(na > 0 && nb > 0) { 1344 if(na > nb) { sort_r_swap(ptr, ptr+na, nb); } 1345 else { sort_r_swap(ptr, ptr+nb, na); } 1346 } 1347 } 1348 1349 /* Implement recursive quicksort ourselves */ 1350 /* Note: quicksort is not stable, equivalent values may be swapped */ 1351 template <typename ...Ts> 1352 static inline void sort_r_simple(void *base, size_t nel, size_t w, 1353 int (*compar)(const void *_a, 1354 const void *_b, 1355 Ts... _ds), 1356 Ts... ds) 1357 { 1358 char *b = (char *)base, *end = b + nel*w; 1359 1360 /* for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));} 1361 printf("\n"); */ 1362 1363 if(nel < 10) { 1364 /* Insertion sort for arbitrarily small inputs */ 1365 char *pi, *pj; 1366 for(pi = b+w; pi < end; pi += w) { 1367 for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {} 1368 } 1369 } 1370 else 1371 { 1372 /* nel > 9; Quicksort */ 1373 1374 int cmp; 1375 char *pl, *ple, *pr, *pre, *pivot; 1376 char *last = b+w*(nel-1), *tmp; 1377 1378 /* 1379 Use median of second, middle and second-last items as pivot. 1380 First and last may have been swapped with pivot and therefore be extreme 1381 */ 1382 char *l[3]; 1383 l[0] = b + w; 1384 l[1] = b+w*(nel/2); 1385 l[2] = last - w; 1386 1387 /* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */ 1388 1389 if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } 1390 if(compar(l[1],l[2],ds...) > 0) { 1391 SORT_R_SWAP(l[1], l[2], tmp); 1392 if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } 1393 } 1394 1395 /* swap mid value (l[1]), and last element to put pivot as last element */ 1396 if(l[1] != last) { sort_r_swap(l[1], last, w); } 1397 1398 /* 1399 pl is the next item on the left to be compared to the pivot 1400 pr is the last item on the right that was compared to the pivot 1401 ple is the left position to put the next item that equals the pivot 1402 ple is the last right position where we put an item that equals the pivot 1403 v- end (beyond the array) 1404 EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE. 1405 ^- b ^- ple ^- pl ^- pr ^- pre ^- last (where the pivot is) 1406 Pivot comparison key: 1407 E = equal, L = less than, u = unknown, G = greater than, E = equal 1408 */ 1409 pivot = last; 1410 ple = pl = b; 1411 pre = pr = last; 1412 1413 /* 1414 Strategy: 1415 Loop into the list from the left and right at the same time to find: 1416 - an item on the left that is greater than the pivot 1417 - an item on the right that is less than the pivot 1418 Once found, they are swapped and the loop continues. 1419 Meanwhile items that are equal to the pivot are moved to the edges of the 1420 array. 1421 */ 1422 while(pl < pr) { 1423 /* Move left hand items which are equal to the pivot to the far left. 1424 break when we find an item that is greater than the pivot */ 1425 for(; pl < pr; pl += w) { 1426 cmp = compar(pl, pivot, ds...); 1427 if(cmp > 0) { break; } 1428 else if(cmp == 0) { 1429 if(ple < pl) { sort_r_swap(ple, pl, w); } 1430 ple += w; 1431 } 1432 } 1433 /* break if last batch of left hand items were equal to pivot */ 1434 if(pl >= pr) { break; } 1435 /* Move right hand items which are equal to the pivot to the far right. 1436 break when we find an item that is less than the pivot */ 1437 for(; pl < pr; ) { 1438 pr -= w; /* Move right pointer onto an unprocessed item */ 1439 cmp = compar(pr, pivot, ds...); 1440 if(cmp == 0) { 1441 pre -= w; 1442 if(pr < pre) { sort_r_swap(pr, pre, w); } 1443 } 1444 else if(cmp < 0) { 1445 if(pl < pr) { sort_r_swap(pl, pr, w); } 1446 pl += w; 1447 break; 1448 } 1449 } 1450 } 1451 1452 pl = pr; /* pr may have gone below pl */ 1453 1454 /* 1455 Now we need to go from: EEELLLGGGGEEEE 1456 to: LLLEEEEEEEGGGG 1457 Pivot comparison key: 1458 E = equal, L = less than, u = unknown, G = greater than, E = equal 1459 */ 1460 sort_r_swap_blocks(b, ple-b, pl-ple); 1461 sort_r_swap_blocks(pr, pre-pr, end-pre); 1462 1463 /*for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));} 1464 printf("\n");*/ 1465 1466 sort_r_simple(b, (pl-ple)/w, w, compar, ds...); 1467 sort_r_simple(end-(pre-pr), (pre-pr)/w, w, compar, ds...); 1468 } 1469 } 1470 1471 static inline void 1472 hb_qsort (void *base, size_t nel, size_t width, 1473 int (*compar)(const void *_a, const void *_b)) 1474 { 1475 #if defined(__OPTIMIZE_SIZE__) && !defined(HB_USE_INTERNAL_QSORT) 1476 qsort (base, nel, width, compar); 1477 #else 1478 sort_r_simple (base, nel, width, compar); 1479 #endif 1480 } 1481 1482 static inline void 1483 hb_qsort (void *base, size_t nel, size_t width, 1484 int (*compar)(const void *_a, const void *_b, void *_arg), 1485 void *arg) 1486 { 1487 #ifdef HAVE_GNU_QSORT_R 1488 qsort_r (base, nel, width, compar, arg); 1489 #else 1490 sort_r_simple (base, nel, width, compar, arg); 1491 #endif 1492 } 1493 1494 1495 template <typename T, typename T2, typename T3 = int> static inline void 1496 hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2 = nullptr) 1497 { 1498 static_assert (hb_is_trivially_copy_assignable (T), ""); 1499 static_assert (hb_is_trivially_copy_assignable (T3), ""); 1500 1501 for (unsigned int i = 1; i < len; i++) 1502 { 1503 unsigned int j = i; 1504 while (j && compar (&array[j - 1], &array[i]) > 0) 1505 j--; 1506 if (i == j) 1507 continue; 1508 /* Move item i to occupy place for item j, shift what's in between. */ 1509 { 1510 T t = array[i]; 1511 memmove (&array[j + 1], &array[j], (i - j) * sizeof (T)); 1512 array[j] = t; 1513 } 1514 if (array2) 1515 { 1516 T3 t = array2[i]; 1517 memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3)); 1518 array2[j] = t; 1519 } 1520 } 1521 } 1522 1523 static inline hb_bool_t 1524 hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) 1525 { 1526 unsigned int v; 1527 const char *p = s; 1528 const char *end = p + len; 1529 if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, base))) 1530 return false; 1531 1532 *out = v; 1533 return true; 1534 } 1535 1536 1537 /* Operators. */ 1538 1539 struct 1540 { HB_PARTIALIZE(2); 1541 template <typename T> constexpr auto 1542 operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b) 1543 } 1544 HB_FUNCOBJ (hb_bitwise_and); 1545 struct 1546 { HB_PARTIALIZE(2); 1547 template <typename T> constexpr auto 1548 operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b) 1549 } 1550 HB_FUNCOBJ (hb_bitwise_or); 1551 struct 1552 { HB_PARTIALIZE(2); 1553 template <typename T> constexpr auto 1554 operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b) 1555 } 1556 HB_FUNCOBJ (hb_bitwise_xor); 1557 struct 1558 { HB_PARTIALIZE(2); 1559 template <typename T> constexpr auto 1560 operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a & b) 1561 } 1562 HB_FUNCOBJ (hb_bitwise_lt); 1563 struct 1564 { HB_PARTIALIZE(2); 1565 template <typename T> constexpr auto 1566 operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b) 1567 } 1568 HB_FUNCOBJ (hb_bitwise_gt); // aka sub 1569 struct 1570 { HB_PARTIALIZE(2); 1571 template <typename T> constexpr auto 1572 operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a | b) 1573 } 1574 HB_FUNCOBJ (hb_bitwise_le); 1575 struct 1576 { HB_PARTIALIZE(2); 1577 template <typename T> constexpr auto 1578 operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | ~b) 1579 } 1580 HB_FUNCOBJ (hb_bitwise_ge); 1581 struct 1582 { 1583 template <typename T> constexpr auto 1584 operator () (const T &a) const HB_AUTO_RETURN (~a) 1585 } 1586 HB_FUNCOBJ (hb_bitwise_neg); 1587 1588 struct 1589 { HB_PARTIALIZE(2); 1590 template <typename T, typename T2> constexpr auto 1591 operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b) 1592 } 1593 HB_FUNCOBJ (hb_add); 1594 struct 1595 { HB_PARTIALIZE(2); 1596 template <typename T, typename T2> constexpr auto 1597 operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b) 1598 } 1599 HB_FUNCOBJ (hb_sub); 1600 struct 1601 { HB_PARTIALIZE(2); 1602 template <typename T, typename T2> constexpr auto 1603 operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (b - a) 1604 } 1605 HB_FUNCOBJ (hb_rsub); 1606 struct 1607 { HB_PARTIALIZE(2); 1608 template <typename T, typename T2> constexpr auto 1609 operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b) 1610 } 1611 HB_FUNCOBJ (hb_mul); 1612 struct 1613 { HB_PARTIALIZE(2); 1614 template <typename T, typename T2> constexpr auto 1615 operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b) 1616 } 1617 HB_FUNCOBJ (hb_div); 1618 struct 1619 { HB_PARTIALIZE(2); 1620 template <typename T, typename T2> constexpr auto 1621 operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b) 1622 } 1623 HB_FUNCOBJ (hb_mod); 1624 struct 1625 { 1626 template <typename T> constexpr auto 1627 operator () (const T &a) const HB_AUTO_RETURN (+a) 1628 } 1629 HB_FUNCOBJ (hb_pos); 1630 struct 1631 { 1632 template <typename T> constexpr auto 1633 operator () (const T &a) const HB_AUTO_RETURN (-a) 1634 } 1635 HB_FUNCOBJ (hb_neg); 1636 struct 1637 { 1638 template <typename T> constexpr auto 1639 operator () (T &a) const HB_AUTO_RETURN (++a) 1640 } 1641 HB_FUNCOBJ (hb_inc); 1642 struct 1643 { 1644 template <typename T> constexpr auto 1645 operator () (T &a) const HB_AUTO_RETURN (--a) 1646 } 1647 HB_FUNCOBJ (hb_dec); 1648 1649 1650 /* Adapted from kurbo implementation with extra parameters added, 1651 * and finding for a particular range instead of 0. 1652 * 1653 * For documentation and implementation see: 1654 * 1655 * [ITP method]: https://en.wikipedia.org/wiki/ITP_Method 1656 * [An Enhancement of the Bisection Method Average Performance Preserving Minmax Optimality]: https://dl.acm.org/doi/10.1145/3423597 1657 * https://docs.rs/kurbo/0.8.1/kurbo/common/fn.solve_itp.html 1658 * https://github.com/linebender/kurbo/blob/fd839c25ea0c98576c7ce5789305822675a89938/src/common.rs#L162-L248 1659 */ 1660 template <typename func_t> 1661 double solve_itp (func_t f, 1662 double a, double b, 1663 double epsilon, 1664 double min_y, double max_y, 1665 double &ya, double &yb, double &y) 1666 { 1667 unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0)); 1668 const unsigned n0 = 1; // Hardwired 1669 const double k1 = 0.2 / (b - a); // Hardwired. 1670 unsigned nmax = n0 + n1_2; 1671 double scaled_epsilon = epsilon * double (1llu << nmax); 1672 double _2_epsilon = 2.0 * epsilon; 1673 while (b - a > _2_epsilon) 1674 { 1675 double x1_2 = 0.5 * (a + b); 1676 double r = scaled_epsilon - 0.5 * (b - a); 1677 double xf = (yb * a - ya * b) / (yb - ya); 1678 double sigma = x1_2 - xf; 1679 double b_a = b - a; 1680 // This has k2 = 2 hardwired for efficiency. 1681 double b_a_k2 = b_a * b_a; 1682 double delta = k1 * b_a_k2; 1683 int sigma_sign = sigma >= 0 ? +1 : -1; 1684 double xt = delta <= fabs (x1_2 - xf) ? xf + delta * sigma_sign : x1_2; 1685 double xitp = fabs (xt - x1_2) <= r ? xt : x1_2 - r * sigma_sign; 1686 double yitp = f (xitp); 1687 if (yitp > max_y) 1688 { 1689 b = xitp; 1690 yb = yitp; 1691 } 1692 else if (yitp < min_y) 1693 { 1694 a = xitp; 1695 ya = yitp; 1696 } 1697 else 1698 { 1699 y = yitp; 1700 return xitp; 1701 } 1702 scaled_epsilon *= 0.5; 1703 } 1704 return 0.5 * (a + b); 1705 } 1706 1707 1708 #endif /* HB_ALGS_HH */