1 /* 2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 3 * Copyright © 2012 Google, 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 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #ifndef HB_OPEN_TYPE_HH 30 #define HB_OPEN_TYPE_HH 31 32 #include "hb.hh" 33 #include "hb-blob.hh" 34 #include "hb-face.hh" 35 #include "hb-machinery.hh" 36 #include "hb-meta.hh" 37 #include "hb-subset.hh" 38 39 40 namespace OT { 41 42 43 /* 44 * 45 * The OpenType Font File: Data Types 46 */ 47 48 49 /* "The following data types are used in the OpenType font file. 50 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ 51 52 /* 53 * Int types 54 */ 55 56 /* Integer types in big-endian order and no alignment requirement */ 57 template <typename Type, 58 unsigned int Size = sizeof (Type)> 59 struct IntType 60 { 61 typedef Type type; 62 63 IntType () = default; IntTypeOT::IntType64 explicit constexpr IntType (Type V) : v {V} {} operator =OT::IntType65 IntType& operator = (Type i) { v = i; return *this; } 66 /* For reason we define cast out operator for signed/unsigned, instead of Type, see: 67 * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */ operator typename std::conditional<std::is_signed<Type>::value,signed,unsigned>::typeOT::IntType68 operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () const { return v; } 69 operator ==OT::IntType70 bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } operator !=OT::IntType71 bool operator != (const IntType &o) const { return !(*this == o); } 72 operator +=OT::IntType73 IntType& operator += (unsigned count) { *this = *this + count; return *this; } operator -=OT::IntType74 IntType& operator -= (unsigned count) { *this = *this - count; return *this; } operator ++OT::IntType75 IntType& operator ++ () { *this += 1; return *this; } operator --OT::IntType76 IntType& operator -- () { *this -= 1; return *this; } operator ++OT::IntType77 IntType operator ++ (int) { IntType c (*this); ++*this; return c; } operator --OT::IntType78 IntType operator -- (int) { IntType c (*this); --*this; return c; } 79 cmpOT::IntType80 HB_INTERNAL static int cmp (const IntType *a, const IntType *b) 81 { return b->cmp (*a); } cmpOT::IntType82 HB_INTERNAL static int cmp (const void *a, const void *b) 83 { 84 IntType *pa = (IntType *) a; 85 IntType *pb = (IntType *) b; 86 87 return pb->cmp (*pa); 88 } 89 template <typename Type2, 90 hb_enable_if (std::is_integral<Type2>::value && 91 sizeof (Type2) < sizeof (int) && 92 sizeof (Type) < sizeof (int))> cmpOT::IntType93 int cmp (Type2 a) const 94 { 95 Type b = v; 96 return (int) a - (int) b; 97 } 98 template <typename Type2, 99 hb_enable_if (hb_is_convertible (Type2, Type))> cmpOT::IntType100 int cmp (Type2 a) const 101 { 102 Type b = v; 103 return a < b ? -1 : a == b ? 0 : +1; 104 } sanitizeOT::IntType105 bool sanitize (hb_sanitize_context_t *c) const 106 { 107 TRACE_SANITIZE (this); 108 return_trace (c->check_struct (this)); 109 } 110 protected: 111 BEInt<Type, Size> v; 112 public: 113 DEFINE_SIZE_STATIC (Size); 114 }; 115 116 typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */ 117 typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */ 118 typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */ 119 typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */ 120 typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */ 121 typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */ 122 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. 123 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ 124 typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ 125 126 /* 15-bit unsigned number; top bit used for extension. */ 127 struct HBUINT15 : HBUINT16 128 { 129 /* TODO Flesh out; actually mask top bit. */ operator =OT::HBUINT15130 HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; } 131 public: 132 DEFINE_SIZE_STATIC (2); 133 }; 134 135 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ 136 typedef HBINT16 FWORD; 137 138 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */ 139 typedef HBINT32 FWORD32; 140 141 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ 142 typedef HBUINT16 UFWORD; 143 144 template <typename Type, unsigned fraction_bits> 145 struct HBFixed : Type 146 { 147 static constexpr float shift = (float) (1 << fraction_bits); 148 static_assert (Type::static_size * 8 > fraction_bits, ""); 149 150 operator signed () const = delete; 151 operator unsigned () const = delete; to_intOT::HBFixed152 typename Type::type to_int () const { return Type::v; } set_intOT::HBFixed153 void set_int (typename Type::type i ) { Type::v = i; } to_floatOT::HBFixed154 float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; } set_floatOT::HBFixed155 void set_float (float f) { Type::v = roundf (f * shift); } 156 public: 157 DEFINE_SIZE_STATIC (Type::static_size); 158 }; 159 160 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ 161 using F2DOT14 = HBFixed<HBINT16, 14>; 162 using F4DOT12 = HBFixed<HBINT16, 12>; 163 using F6DOT10 = HBFixed<HBINT16, 10>; 164 165 /* 32-bit signed fixed-point number (16.16). */ 166 using F16DOT16 = HBFixed<HBINT32, 16>; 167 168 /* Date represented in number of seconds since 12:00 midnight, January 1, 169 * 1904. The value is represented as a signed 64-bit integer. */ 170 struct LONGDATETIME 171 { sanitizeOT::LONGDATETIME172 bool sanitize (hb_sanitize_context_t *c) const 173 { 174 TRACE_SANITIZE (this); 175 return_trace (c->check_struct (this)); 176 } 177 protected: 178 HBINT32 major; 179 HBUINT32 minor; 180 public: 181 DEFINE_SIZE_STATIC (8); 182 }; 183 184 /* Array of four uint8s (length = 32 bits) used to identify a script, language 185 * system, feature, or baseline */ 186 struct Tag : HBUINT32 187 { operator =OT::Tag188 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } 189 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ operator const char*OT::Tag190 operator const char* () const { return reinterpret_cast<const char *> (this); } operator char*OT::Tag191 operator char* () { return reinterpret_cast<char *> (this); } 192 public: 193 DEFINE_SIZE_STATIC (4); 194 }; 195 196 /* Glyph index number, same as uint16 (length = 16 bits) */ 197 struct HBGlyphID16 : HBUINT16 198 { operator =OT::HBGlyphID16199 HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 200 }; 201 struct HBGlyphID24 : HBUINT24 202 { operator =OT::HBGlyphID24203 HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; } 204 }; 205 206 /* Script/language-system/feature index */ 207 struct Index : HBUINT16 { 208 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; operator =OT::Index209 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } 210 }; 211 DECLARE_NULL_NAMESPACE_BYTES (OT, Index); 212 213 typedef Index NameID; 214 215 struct VarIdx : HBUINT32 { 216 static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; 217 static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, ""); addOT::VarIdx218 static uint32_t add (uint32_t i, unsigned short v) 219 { 220 if (i == NO_VARIATION) return i; 221 return i + v; 222 } operator =OT::VarIdx223 VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 224 }; 225 DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); 226 227 /* Offset, Null offset = 0 */ 228 template <typename Type, bool has_null=true> 229 struct Offset : Type 230 { operator =OT::Offset231 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; } 232 233 typedef Type type; 234 is_nullOT::Offset235 bool is_null () const { return has_null && 0 == *this; } 236 237 public: 238 DEFINE_SIZE_STATIC (sizeof (Type)); 239 }; 240 241 typedef Offset<HBUINT16> Offset16; 242 typedef Offset<HBUINT24> Offset24; 243 typedef Offset<HBUINT32> Offset32; 244 245 246 /* CheckSum */ 247 struct CheckSum : HBUINT32 248 { operator =OT::CheckSum249 CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } 250 251 /* This is reference implementation from the spec. */ CalcTableChecksumOT::CheckSum252 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) 253 { 254 uint32_t Sum = 0L; 255 assert (0 == (Length & 3)); 256 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size; 257 258 while (Table < EndPtr) 259 Sum += *Table++; 260 return Sum; 261 } 262 263 /* Note: data should be 4byte aligned and have 4byte padding at the end. */ set_for_dataOT::CheckSum264 void set_for_data (const void *data, unsigned int length) 265 { *this = CalcTableChecksum ((const HBUINT32 *) data, length); } 266 267 public: 268 DEFINE_SIZE_STATIC (4); 269 }; 270 271 272 /* 273 * Version Numbers 274 */ 275 276 template <typename FixedType=HBUINT16> 277 struct FixedVersion 278 { to_intOT::FixedVersion279 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; } 280 sanitizeOT::FixedVersion281 bool sanitize (hb_sanitize_context_t *c) const 282 { 283 TRACE_SANITIZE (this); 284 return_trace (c->check_struct (this)); 285 } 286 287 FixedType major; 288 FixedType minor; 289 public: 290 DEFINE_SIZE_STATIC (2 * sizeof (FixedType)); 291 }; 292 293 294 /* 295 * Template subclasses of Offset that do the dereferencing. 296 * Use: (base+offset) 297 */ 298 299 template <typename Type, bool has_null> 300 struct _hb_has_null 301 { get_nullOT::_hb_has_null302 static const Type *get_null () { return nullptr; } get_crapOT::_hb_has_null303 static Type *get_crap () { return nullptr; } 304 }; 305 template <typename Type> 306 struct _hb_has_null<Type, true> 307 { get_nullOT::_hb_has_null308 static const Type *get_null () { return &Null (Type); } get_crapOT::_hb_has_null309 static Type *get_crap () { return &Crap (Type); } 310 }; 311 312 template <typename Type, typename OffsetType, bool has_null=true> 313 struct OffsetTo : Offset<OffsetType, has_null> 314 { 315 using target_t = Type; 316 317 // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time. 318 static_assert (has_null == false || 319 (hb_has_null_size (Type) || !hb_has_min_size (Type)), ""); 320 321 HB_DELETE_COPY_ASSIGN (OffsetTo); 322 OffsetTo () = default; 323 operator =OT::OffsetTo324 OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; } 325 operator ()OT::OffsetTo326 const Type& operator () (const void *base) const 327 { 328 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null (); 329 return StructAtOffset<const Type> (base, *this); 330 } operator ()OT::OffsetTo331 Type& operator () (void *base) const 332 { 333 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap (); 334 return StructAtOffset<Type> (base, *this); 335 } 336 337 template <typename Base, 338 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const Base & base,const OffsetTo & offset)339 friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } 340 template <typename Base, 341 hb_enable_if (hb_is_convertible (const Base, const void *))> operator +(const OffsetTo & offset,const Base & base)342 friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } 343 template <typename Base, 344 hb_enable_if (hb_is_convertible (Base, void *))> operator +(Base && base,OffsetTo & offset)345 friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } 346 template <typename Base, 347 hb_enable_if (hb_is_convertible (Base, void *))> operator +(OffsetTo & offset,Base && base)348 friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } 349 350 351 template <typename ...Ts> serialize_subsetOT::OffsetTo352 bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, 353 const void *src_base, Ts&&... ds) 354 { 355 *this = 0; 356 if (src.is_null ()) 357 return false; 358 359 auto *s = c->serializer; 360 361 s->push (); 362 363 bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...); 364 365 if (ret || !has_null) 366 s->add_link (*this, s->pop_pack ()); 367 else 368 s->pop_discard (); 369 370 return ret; 371 } 372 373 374 template <typename ...Ts> serialize_serializeOT::OffsetTo375 bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds) 376 { 377 *this = 0; 378 379 Type* obj = c->push<Type> (); 380 bool ret = obj->serialize (c, std::forward<Ts> (ds)...); 381 382 if (ret) 383 c->add_link (*this, c->pop_pack ()); 384 else 385 c->pop_discard (); 386 387 return ret; 388 } 389 390 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ 391 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 392 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... 393 */ 394 template <typename ...Ts> serialize_copyOT::OffsetTo395 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 396 const void *src_base, unsigned dst_bias, 397 hb_serialize_context_t::whence_t whence, 398 Ts&&... ds) 399 { 400 *this = 0; 401 if (src.is_null ()) 402 return false; 403 404 c->push (); 405 406 bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...); 407 408 c->add_link (*this, c->pop_pack (), whence, dst_bias); 409 410 return ret; 411 } 412 serialize_copyOT::OffsetTo413 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, 414 const void *src_base, unsigned dst_bias = 0) 415 { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } 416 sanitize_shallowOT::OffsetTo417 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const 418 { 419 TRACE_SANITIZE (this); 420 if (unlikely (!c->check_struct (this))) return_trace (false); 421 //if (unlikely (this->is_null ())) return_trace (true); 422 if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); 423 return_trace (true); 424 } 425 426 template <typename ...Ts> 427 #ifndef HB_OPTIMIZE_SIZE 428 HB_ALWAYS_INLINE 429 #endif sanitizeOT::OffsetTo430 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 431 { 432 TRACE_SANITIZE (this); 433 return_trace (sanitize_shallow (c, base) && 434 (this->is_null () || 435 c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) || 436 neuter (c))); 437 } 438 439 /* Set the offset to Null */ neuterOT::OffsetTo440 bool neuter (hb_sanitize_context_t *c) const 441 { 442 if (!has_null) return false; 443 return c->try_set (this, 0); 444 } 445 DEFINE_SIZE_STATIC (sizeof (OffsetType)); 446 }; 447 /* Partial specializations. */ 448 template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>; 449 template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>; 450 template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>; 451 452 template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>; 453 template <typename Type> using NNOffset16To = Offset16To<Type, false>; 454 template <typename Type> using NNOffset24To = Offset24To<Type, false>; 455 template <typename Type> using NNOffset32To = Offset32To<Type, false>; 456 457 458 /* 459 * Array Types 460 */ 461 462 template <typename Type> 463 struct UnsizedArrayOf 464 { 465 typedef Type item_t; 466 static constexpr unsigned item_size = hb_static_size (Type); 467 468 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); 469 operator []OT::UnsizedArrayOf470 const Type& operator [] (unsigned int i) const 471 { 472 return arrayZ[i]; 473 } operator []OT::UnsizedArrayOf474 Type& operator [] (unsigned int i) 475 { 476 return arrayZ[i]; 477 } 478 get_sizeOT::UnsizedArrayOf479 static unsigned int get_size (unsigned int len) 480 { return len * Type::static_size; } 481 operator T*OT::UnsizedArrayOf482 template <typename T> operator T * () { return arrayZ; } operator const T*OT::UnsizedArrayOf483 template <typename T> operator const T * () const { return arrayZ; } as_arrayOT::UnsizedArrayOf484 hb_array_t<Type> as_array (unsigned int len) 485 { return hb_array (arrayZ, len); } as_arrayOT::UnsizedArrayOf486 hb_array_t<const Type> as_array (unsigned int len) const 487 { return hb_array (arrayZ, len); } 488 489 template <typename T> lsearchOT::UnsizedArrayOf490 Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 491 { return *as_array (len).lsearch (x, ¬_found); } 492 template <typename T> lsearchOT::UnsizedArrayOf493 const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 494 { return *as_array (len).lsearch (x, ¬_found); } 495 template <typename T> lfindOT::UnsizedArrayOf496 bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr, 497 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 498 unsigned int to_store = (unsigned int) -1) const 499 { return as_array (len).lfind (x, i, not_found, to_store); } 500 qsortOT::UnsizedArrayOf501 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) 502 { as_array (len).qsort (start, end); } 503 serializeOT::UnsizedArrayOf504 bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) 505 { 506 TRACE_SERIALIZE (this); 507 if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false); 508 return_trace (true); 509 } 510 template <typename Iterator, 511 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::UnsizedArrayOf512 bool serialize (hb_serialize_context_t *c, Iterator items) 513 { 514 TRACE_SERIALIZE (this); 515 unsigned count = hb_len (items); 516 if (unlikely (!serialize (c, count, false))) return_trace (false); 517 /* TODO Umm. Just exhaust the iterator instead? Being extra 518 * cautious right now.. */ 519 for (unsigned i = 0; i < count; i++, ++items) 520 arrayZ[i] = *items; 521 return_trace (true); 522 } 523 copyOT::UnsizedArrayOf524 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const 525 { 526 TRACE_SERIALIZE (this); 527 auto *out = c->start_embed (this); 528 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); 529 return_trace (out); 530 } 531 532 template <typename ...Ts> 533 HB_ALWAYS_INLINE sanitizeOT::UnsizedArrayOf534 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 535 { 536 TRACE_SANITIZE (this); 537 if (unlikely (!sanitize_shallow (c, count))) return_trace (false); 538 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 539 for (unsigned int i = 0; i < count; i++) 540 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 541 return_trace (false); 542 return_trace (true); 543 } 544 sanitize_shallowOT::UnsizedArrayOf545 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const 546 { 547 TRACE_SANITIZE (this); 548 return_trace (c->check_array (arrayZ, count)); 549 } 550 551 public: 552 Type arrayZ[HB_VAR_ARRAY]; 553 public: 554 DEFINE_SIZE_UNBOUNDED (0); 555 }; 556 557 /* Unsized array of offset's */ 558 template <typename Type, typename OffsetType, bool has_null=true> 559 using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; 560 561 /* Unsized array of offsets relative to the beginning of the array itself. */ 562 template <typename Type, typename OffsetType, bool has_null=true> 563 struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 564 { operator []OT::UnsizedListOfOffset16To565 const Type& operator [] (int i_) const 566 { 567 unsigned int i = (unsigned int) i_; 568 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 569 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */ 570 _hb_compiler_memory_r_barrier (); 571 return this+*p; 572 } operator []OT::UnsizedListOfOffset16To573 Type& operator [] (int i_) 574 { 575 unsigned int i = (unsigned int) i_; 576 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; 577 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */ 578 _hb_compiler_memory_r_barrier (); 579 return this+*p; 580 } 581 582 template <typename ...Ts> sanitizeOT::UnsizedListOfOffset16To583 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const 584 { 585 TRACE_SANITIZE (this); 586 return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null> 587 ::sanitize (c, count, this, std::forward<Ts> (ds)...))); 588 } 589 }; 590 591 /* An array with sorted elements. Supports binary searching. */ 592 template <typename Type> 593 struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> 594 { as_arrayOT::SortedUnsizedArrayOf595 hb_sorted_array_t<Type> as_array (unsigned int len) 596 { return hb_sorted_array (this->arrayZ, len); } as_arrayOT::SortedUnsizedArrayOf597 hb_sorted_array_t<const Type> as_array (unsigned int len) const 598 { return hb_sorted_array (this->arrayZ, len); } operator hb_sorted_array_t<Type>OT::SortedUnsizedArrayOf599 operator hb_sorted_array_t<Type> () { return as_array (); } operator hb_sorted_array_t<const Type>OT::SortedUnsizedArrayOf600 operator hb_sorted_array_t<const Type> () const { return as_array (); } 601 602 template <typename T> bsearchOT::SortedUnsizedArrayOf603 Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) 604 { return *as_array (len).bsearch (x, ¬_found); } 605 template <typename T> bsearchOT::SortedUnsizedArrayOf606 const Type &bsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const 607 { return *as_array (len).bsearch (x, ¬_found); } 608 template <typename T> bfindOT::SortedUnsizedArrayOf609 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, 610 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 611 unsigned int to_store = (unsigned int) -1) const 612 { return as_array (len).bfind (x, i, not_found, to_store); } 613 }; 614 615 616 /* An array with a number of elements. */ 617 template <typename Type, typename LenType> 618 struct ArrayOf 619 { 620 typedef Type item_t; 621 static constexpr unsigned item_size = hb_static_size (Type); 622 623 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf); 624 operator []OT::ArrayOf625 const Type& operator [] (int i_) const 626 { 627 unsigned int i = (unsigned int) i_; 628 if (unlikely (i >= len)) return Null (Type); 629 _hb_compiler_memory_r_barrier (); 630 return arrayZ[i]; 631 } operator []OT::ArrayOf632 Type& operator [] (int i_) 633 { 634 unsigned int i = (unsigned int) i_; 635 if (unlikely (i >= len)) return Crap (Type); 636 _hb_compiler_memory_r_barrier (); 637 return arrayZ[i]; 638 } 639 get_sizeOT::ArrayOf640 unsigned int get_size () const 641 { return len.static_size + len * Type::static_size; } 642 operator boolOT::ArrayOf643 explicit operator bool () const { return len; } 644 popOT::ArrayOf645 void pop () { len--; } 646 as_arrayOT::ArrayOf647 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } as_arrayOT::ArrayOf648 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); } 649 650 /* Iterator. */ 651 typedef hb_array_t<const Type> iter_t; 652 typedef hb_array_t< Type> writer_t; iterOT::ArrayOf653 iter_t iter () const { return as_array (); } writerOT::ArrayOf654 writer_t writer () { return as_array (); } operator iter_tOT::ArrayOf655 operator iter_t () const { return iter (); } operator writer_tOT::ArrayOf656 operator writer_t () { return writer (); } 657 658 /* Faster range-based for loop. */ beginOT::ArrayOf659 const Type *begin () const { return arrayZ; } endOT::ArrayOf660 const Type *end () const { return arrayZ + len; } 661 662 template <typename T> lsearchOT::ArrayOf663 Type &lsearch (const T &x, Type ¬_found = Crap (Type)) 664 { return *as_array ().lsearch (x, ¬_found); } 665 template <typename T> lsearchOT::ArrayOf666 const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const 667 { return *as_array ().lsearch (x, ¬_found); } 668 template <typename T> lfindOT::ArrayOf669 bool lfind (const T &x, unsigned int *i = nullptr, 670 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 671 unsigned int to_store = (unsigned int) -1) const 672 { return as_array ().lfind (x, i, not_found, to_store); } 673 qsortOT::ArrayOf674 void qsort () 675 { as_array ().qsort (); } 676 serializeOT::ArrayOf677 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true) 678 { 679 TRACE_SERIALIZE (this); 680 if (unlikely (!c->extend_min (this))) return_trace (false); 681 c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 682 if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); 683 return_trace (true); 684 } 685 template <typename Iterator, 686 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::ArrayOf687 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) 688 { 689 TRACE_SERIALIZE (this); 690 unsigned count = hb_len (items); 691 if (unlikely (!serialize (c, count, false))) return_trace (false); 692 /* TODO Umm. Just exhaust the iterator instead? Being extra 693 * cautious right now.. */ 694 for (unsigned i = 0; i < count; i++, ++items) 695 arrayZ[i] = *items; 696 return_trace (true); 697 } 698 serialize_appendOT::ArrayOf699 Type* serialize_append (hb_serialize_context_t *c) 700 { 701 TRACE_SERIALIZE (this); 702 len++; 703 if (unlikely (!len || !c->extend (this))) 704 { 705 len--; 706 return_trace (nullptr); 707 } 708 return_trace (&arrayZ[len - 1]); 709 } 710 copyOT::ArrayOf711 ArrayOf* copy (hb_serialize_context_t *c) const 712 { 713 TRACE_SERIALIZE (this); 714 auto *out = c->start_embed (this); 715 if (unlikely (!c->extend_min (out))) return_trace (nullptr); 716 c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 717 if (unlikely (!as_array ().copy (c))) return_trace (nullptr); 718 return_trace (out); 719 } 720 721 template <typename ...Ts> 722 HB_ALWAYS_INLINE sanitizeOT::ArrayOf723 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 724 { 725 TRACE_SANITIZE (this); 726 if (unlikely (!sanitize_shallow (c))) return_trace (false); 727 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 728 unsigned int count = len; 729 for (unsigned int i = 0; i < count; i++) 730 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 731 return_trace (false); 732 return_trace (true); 733 } 734 sanitize_shallowOT::ArrayOf735 bool sanitize_shallow (hb_sanitize_context_t *c) const 736 { 737 TRACE_SANITIZE (this); 738 return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType))); 739 } 740 741 public: 742 LenType len; 743 Type arrayZ[HB_VAR_ARRAY]; 744 public: 745 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 746 }; 747 template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>; 748 template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>; 749 template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>; 750 using PString = ArrayOf<HBUINT8, HBUINT8>; 751 752 /* Array of Offset's */ 753 template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>; 754 template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>; 755 template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; 756 757 /* Array of offsets relative to the beginning of the array itself. */ 758 template <typename Type, typename OffsetType> 759 struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16> 760 { operator []OT::List16OfOffsetTo761 const Type& operator [] (int i_) const 762 { 763 unsigned int i = (unsigned int) i_; 764 if (unlikely (i >= this->len)) return Null (Type); 765 _hb_compiler_memory_r_barrier (); 766 return this+this->arrayZ[i]; 767 } operator []OT::List16OfOffsetTo768 const Type& operator [] (int i_) 769 { 770 unsigned int i = (unsigned int) i_; 771 if (unlikely (i >= this->len)) return Crap (Type); 772 _hb_compiler_memory_r_barrier (); 773 return this+this->arrayZ[i]; 774 } 775 subsetOT::List16OfOffsetTo776 bool subset (hb_subset_context_t *c) const 777 { 778 TRACE_SUBSET (this); 779 struct List16OfOffsetTo *out = c->serializer->embed (*this); 780 if (unlikely (!out)) return_trace (false); 781 unsigned int count = this->len; 782 for (unsigned int i = 0; i < count; i++) 783 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out); 784 return_trace (true); 785 } 786 787 template <typename ...Ts> sanitizeOT::List16OfOffsetTo788 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 789 { 790 TRACE_SANITIZE (this); 791 return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...))); 792 } 793 }; 794 795 template <typename Type> 796 using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>; 797 798 /* An array starting at second element. */ 799 template <typename Type, typename LenType> 800 struct HeadlessArrayOf 801 { 802 static constexpr unsigned item_size = Type::static_size; 803 804 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf); 805 operator []OT::HeadlessArrayOf806 const Type& operator [] (int i_) const 807 { 808 unsigned int i = (unsigned int) i_; 809 if (unlikely (i >= lenP1 || !i)) return Null (Type); 810 _hb_compiler_memory_r_barrier (); 811 return arrayZ[i-1]; 812 } operator []OT::HeadlessArrayOf813 Type& operator [] (int i_) 814 { 815 unsigned int i = (unsigned int) i_; 816 if (unlikely (i >= lenP1 || !i)) return Crap (Type); 817 _hb_compiler_memory_r_barrier (); 818 return arrayZ[i-1]; 819 } get_sizeOT::HeadlessArrayOf820 unsigned int get_size () const 821 { return lenP1.static_size + get_length () * Type::static_size; } 822 get_lengthOT::HeadlessArrayOf823 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } 824 as_arrayOT::HeadlessArrayOf825 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } as_arrayOT::HeadlessArrayOf826 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); } 827 828 /* Iterator. */ 829 typedef hb_array_t<const Type> iter_t; 830 typedef hb_array_t< Type> writer_t; iterOT::HeadlessArrayOf831 iter_t iter () const { return as_array (); } writerOT::HeadlessArrayOf832 writer_t writer () { return as_array (); } operator iter_tOT::HeadlessArrayOf833 operator iter_t () const { return iter (); } operator writer_tOT::HeadlessArrayOf834 operator writer_t () { return writer (); } 835 836 /* Faster range-based for loop. */ beginOT::HeadlessArrayOf837 const Type *begin () const { return arrayZ; } endOT::HeadlessArrayOf838 const Type *end () const { return arrayZ + get_length (); } 839 serializeOT::HeadlessArrayOf840 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) 841 { 842 TRACE_SERIALIZE (this); 843 if (unlikely (!c->extend_min (this))) return_trace (false); 844 c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); 845 if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); 846 return_trace (true); 847 } 848 template <typename Iterator, 849 hb_requires (hb_is_source_of (Iterator, Type))> serializeOT::HeadlessArrayOf850 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) 851 { 852 TRACE_SERIALIZE (this); 853 unsigned count = hb_len (items); 854 if (unlikely (!serialize (c, count, false))) return_trace (false); 855 /* TODO Umm. Just exhaust the iterator instead? Being extra 856 * cautious right now.. */ 857 for (unsigned i = 0; i < count; i++, ++items) 858 arrayZ[i] = *items; 859 return_trace (true); 860 } 861 862 template <typename ...Ts> 863 HB_ALWAYS_INLINE sanitizeOT::HeadlessArrayOf864 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 865 { 866 TRACE_SANITIZE (this); 867 if (unlikely (!sanitize_shallow (c))) return_trace (false); 868 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 869 unsigned int count = get_length (); 870 for (unsigned int i = 0; i < count; i++) 871 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 872 return_trace (false); 873 return_trace (true); 874 } 875 876 private: sanitize_shallowOT::HeadlessArrayOf877 bool sanitize_shallow (hb_sanitize_context_t *c) const 878 { 879 TRACE_SANITIZE (this); 880 return_trace (lenP1.sanitize (c) && 881 (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType)))); 882 } 883 884 public: 885 LenType lenP1; 886 Type arrayZ[HB_VAR_ARRAY]; 887 public: 888 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 889 }; 890 template <typename Type> using HeadlessArray16Of = HeadlessArrayOf<Type, HBUINT16>; 891 892 /* An array storing length-1. */ 893 template <typename Type, typename LenType=HBUINT16> 894 struct ArrayOfM1 895 { 896 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1); 897 operator []OT::ArrayOfM1898 const Type& operator [] (int i_) const 899 { 900 unsigned int i = (unsigned int) i_; 901 if (unlikely (i > lenM1)) return Null (Type); 902 _hb_compiler_memory_r_barrier (); 903 return arrayZ[i]; 904 } operator []OT::ArrayOfM1905 Type& operator [] (int i_) 906 { 907 unsigned int i = (unsigned int) i_; 908 if (unlikely (i > lenM1)) return Crap (Type); 909 _hb_compiler_memory_r_barrier (); 910 return arrayZ[i]; 911 } get_sizeOT::ArrayOfM1912 unsigned int get_size () const 913 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } 914 915 template <typename ...Ts> 916 HB_ALWAYS_INLINE sanitizeOT::ArrayOfM1917 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 918 { 919 TRACE_SANITIZE (this); 920 if (unlikely (!sanitize_shallow (c))) return_trace (false); 921 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 922 unsigned int count = lenM1 + 1; 923 for (unsigned int i = 0; i < count; i++) 924 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) 925 return_trace (false); 926 return_trace (true); 927 } 928 929 private: sanitize_shallowOT::ArrayOfM1930 bool sanitize_shallow (hb_sanitize_context_t *c) const 931 { 932 TRACE_SANITIZE (this); 933 return_trace (lenM1.sanitize (c) && 934 (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType)))); 935 } 936 937 public: 938 LenType lenM1; 939 Type arrayZ[HB_VAR_ARRAY]; 940 public: 941 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); 942 }; 943 944 /* An array with sorted elements. Supports binary searching. */ 945 template <typename Type, typename LenType> 946 struct SortedArrayOf : ArrayOf<Type, LenType> 947 { as_arrayOT::SortedArrayOf948 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } as_arrayOT::SortedArrayOf949 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); } 950 951 /* Iterator. */ 952 typedef hb_sorted_array_t<const Type> iter_t; 953 typedef hb_sorted_array_t< Type> writer_t; iterOT::SortedArrayOf954 iter_t iter () const { return as_array (); } writerOT::SortedArrayOf955 writer_t writer () { return as_array (); } operator iter_tOT::SortedArrayOf956 operator iter_t () const { return iter (); } operator writer_tOT::SortedArrayOf957 operator writer_t () { return writer (); } 958 959 /* Faster range-based for loop. */ beginOT::SortedArrayOf960 const Type *begin () const { return this->arrayZ; } endOT::SortedArrayOf961 const Type *end () const { return this->arrayZ + this->len; } 962 serializeOT::SortedArrayOf963 bool serialize (hb_serialize_context_t *c, unsigned int items_len) 964 { 965 TRACE_SERIALIZE (this); 966 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len); 967 return_trace (ret); 968 } 969 template <typename Iterator, 970 hb_requires (hb_is_sorted_source_of (Iterator, Type))> serializeOT::SortedArrayOf971 bool serialize (hb_serialize_context_t *c, Iterator items) 972 { 973 TRACE_SERIALIZE (this); 974 bool ret = ArrayOf<Type, LenType>::serialize (c, items); 975 return_trace (ret); 976 } 977 978 template <typename T> bsearchOT::SortedArrayOf979 Type &bsearch (const T &x, Type ¬_found = Crap (Type)) 980 { return *as_array ().bsearch (x, ¬_found); } 981 template <typename T> bsearchOT::SortedArrayOf982 const Type &bsearch (const T &x, const Type ¬_found = Null (Type)) const 983 { return *as_array ().bsearch (x, ¬_found); } 984 template <typename T> bfindOT::SortedArrayOf985 bool bfind (const T &x, unsigned int *i = nullptr, 986 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, 987 unsigned int to_store = (unsigned int) -1) const 988 { return as_array ().bfind (x, i, not_found, to_store); } 989 }; 990 991 template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>; 992 template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>; 993 template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>; 994 995 /* 996 * Binary-search arrays 997 */ 998 999 template <typename LenType=HBUINT16> 1000 struct BinSearchHeader 1001 { operator uint32_tOT::BinSearchHeader1002 operator uint32_t () const { return len; } 1003 sanitizeOT::BinSearchHeader1004 bool sanitize (hb_sanitize_context_t *c) const 1005 { 1006 TRACE_SANITIZE (this); 1007 return_trace (c->check_struct (this)); 1008 } 1009 operator =OT::BinSearchHeader1010 BinSearchHeader& operator = (unsigned int v) 1011 { 1012 len = v; 1013 assert (len == v); 1014 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1; 1015 searchRange = 16 * (1u << entrySelector); 1016 rangeShift = v * 16 > searchRange 1017 ? 16 * v - searchRange 1018 : 0; 1019 return *this; 1020 } 1021 1022 protected: 1023 LenType len; 1024 LenType searchRange; 1025 LenType entrySelector; 1026 LenType rangeShift; 1027 1028 public: 1029 DEFINE_SIZE_STATIC (8); 1030 }; 1031 1032 template <typename Type, typename LenType=HBUINT16> 1033 using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>; 1034 1035 1036 struct VarSizedBinSearchHeader 1037 { 1038 sanitizeOT::VarSizedBinSearchHeader1039 bool sanitize (hb_sanitize_context_t *c) const 1040 { 1041 TRACE_SANITIZE (this); 1042 return_trace (c->check_struct (this)); 1043 } 1044 1045 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ 1046 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */ 1047 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2 1048 * that is less than or equal to the value of nUnits. */ 1049 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than 1050 * or equal to the value of nUnits. */ 1051 HBUINT16 rangeShift; /* The value of unitSize times the difference of the 1052 * value of nUnits minus the largest power of 2 less 1053 * than or equal to the value of nUnits. */ 1054 public: 1055 DEFINE_SIZE_STATIC (10); 1056 }; 1057 1058 template <typename Type> 1059 struct VarSizedBinSearchArrayOf 1060 { 1061 static constexpr unsigned item_size = Type::static_size; 1062 1063 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf); 1064 last_is_terminatorOT::VarSizedBinSearchArrayOf1065 bool last_is_terminator () const 1066 { 1067 if (unlikely (!header.nUnits)) return false; 1068 1069 /* Gah. 1070 * 1071 * "The number of termination values that need to be included is table-specific. 1072 * The value that indicates binary search termination is 0xFFFF." */ 1073 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize); 1074 unsigned int count = Type::TerminationWordCount; 1075 for (unsigned int i = 0; i < count; i++) 1076 if (words[i] != 0xFFFFu) 1077 return false; 1078 return true; 1079 } 1080 operator []OT::VarSizedBinSearchArrayOf1081 const Type& operator [] (int i_) const 1082 { 1083 unsigned int i = (unsigned int) i_; 1084 if (unlikely (i >= get_length ())) return Null (Type); 1085 _hb_compiler_memory_r_barrier (); 1086 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1087 } operator []OT::VarSizedBinSearchArrayOf1088 Type& operator [] (int i_) 1089 { 1090 unsigned int i = (unsigned int) i_; 1091 if (unlikely (i >= get_length ())) return Crap (Type); 1092 _hb_compiler_memory_r_barrier (); 1093 return StructAtOffset<Type> (&bytesZ, i * header.unitSize); 1094 } get_lengthOT::VarSizedBinSearchArrayOf1095 unsigned int get_length () const 1096 { return header.nUnits - last_is_terminator (); } get_sizeOT::VarSizedBinSearchArrayOf1097 unsigned int get_size () const 1098 { return header.static_size + header.nUnits * header.unitSize; } 1099 1100 template <typename ...Ts> 1101 HB_ALWAYS_INLINE sanitizeOT::VarSizedBinSearchArrayOf1102 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 1103 { 1104 TRACE_SANITIZE (this); 1105 if (unlikely (!sanitize_shallow (c))) return_trace (false); 1106 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); 1107 unsigned int count = get_length (); 1108 for (unsigned int i = 0; i < count; i++) 1109 if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...))) 1110 return_trace (false); 1111 return_trace (true); 1112 } 1113 1114 template <typename T> bsearchOT::VarSizedBinSearchArrayOf1115 const Type *bsearch (const T &key) const 1116 { 1117 unsigned pos; 1118 return hb_bsearch_impl (&pos, 1119 key, 1120 (const void *) bytesZ, 1121 get_length (), 1122 header.unitSize, 1123 _hb_cmp_method<T, Type>) 1124 ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize)) 1125 : nullptr; 1126 } 1127 1128 private: sanitize_shallowOT::VarSizedBinSearchArrayOf1129 bool sanitize_shallow (hb_sanitize_context_t *c) const 1130 { 1131 TRACE_SANITIZE (this); 1132 return_trace (header.sanitize (c) && 1133 Type::static_size <= header.unitSize && 1134 c->check_range (bytesZ.arrayZ, 1135 header.nUnits, 1136 header.unitSize)); 1137 } 1138 1139 protected: 1140 VarSizedBinSearchHeader header; 1141 UnsizedArrayOf<HBUINT8> bytesZ; 1142 public: 1143 DEFINE_SIZE_ARRAY (10, bytesZ); 1144 }; 1145 1146 1147 } /* namespace OT */ 1148 1149 1150 #endif /* HB_OPEN_TYPE_HH */ 1151