OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. | 2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. |
3 * Copyright © 2012 Google, Inc. | 3 * Copyright © 2012 Google, Inc. |
4 * | 4 * |
5 * This is part of HarfBuzz, a text shaping library. | 5 * This is part of HarfBuzz, a text shaping library. |
6 * | 6 * |
7 * Permission is hereby granted, without written agreement and without | 7 * Permission is hereby granted, without written agreement and without |
8 * license or royalty fees, to use, copy, modify, and distribute this | 8 * license or royalty fees, to use, copy, modify, and distribute this |
9 * software and its documentation for any purpose, provided that the | 9 * software and its documentation for any purpose, provided that the |
10 * above copyright notice and the following two paragraphs appear in | 10 * above copyright notice and the following two paragraphs appear in |
(...skipping 16 matching lines...) Expand all Loading... |
27 */ | 27 */ |
28 | 28 |
29 #ifndef HB_OPEN_TYPE_PRIVATE_HH | 29 #ifndef HB_OPEN_TYPE_PRIVATE_HH |
30 #define HB_OPEN_TYPE_PRIVATE_HH | 30 #define HB_OPEN_TYPE_PRIVATE_HH |
31 | 31 |
32 #include "hb-private.hh" | 32 #include "hb-private.hh" |
33 | 33 |
34 #include "hb-blob.h" | 34 #include "hb-blob.h" |
35 | 35 |
36 | 36 |
| 37 namespace OT { |
| 38 |
37 | 39 |
38 /* | 40 /* |
39 * Casts | 41 * Casts |
40 */ | 42 */ |
41 | 43 |
42 /* Cast to struct T, reference to reference */ | 44 /* Cast to struct T, reference to reference */ |
43 template<typename Type, typename TObject> | 45 template<typename Type, typename TObject> |
44 inline const Type& CastR(const TObject &X) | 46 inline const Type& CastR(const TObject &X) |
45 { return reinterpret_cast<const Type&> (X); } | 47 { return reinterpret_cast<const Type&> (X); } |
46 template<typename Type, typename TObject> | 48 template<typename Type, typename TObject> |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 | 320 |
319 static const Type* lock_instance (hb_blob_t *blob) { | 321 static const Type* lock_instance (hb_blob_t *blob) { |
320 hb_blob_make_immutable (blob); | 322 hb_blob_make_immutable (blob); |
321 const char *base = hb_blob_get_data (blob, NULL); | 323 const char *base = hb_blob_get_data (blob, NULL); |
322 return unlikely (!base) ? &Null(Type) : CastP<Type> (base); | 324 return unlikely (!base) ? &Null(Type) : CastP<Type> (base); |
323 } | 325 } |
324 }; | 326 }; |
325 | 327 |
326 | 328 |
327 | 329 |
| 330 /* |
| 331 * Serialize |
| 332 */ |
| 333 |
| 334 #ifndef HB_DEBUG_SERIALIZE |
| 335 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0) |
| 336 #endif |
| 337 |
| 338 |
| 339 #define TRACE_SERIALIZE() \ |
| 340 hb_auto_trace_t<HB_DEBUG_SERIALIZE> trace (&c->debug_depth, "SERIALIZE",
c, HB_FUNC, ""); |
| 341 |
| 342 |
| 343 struct hb_serialize_context_t |
| 344 { |
| 345 inline hb_serialize_context_t (void *start, unsigned int size) |
| 346 { |
| 347 this->start = (char *) start; |
| 348 this->end = this->start + size; |
| 349 |
| 350 this->ran_out_of_room = false; |
| 351 this->head = this->start; |
| 352 this->debug_depth = 0; |
| 353 } |
| 354 |
| 355 template <typename Type> |
| 356 inline Type *start_serialize (void) |
| 357 { |
| 358 DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, |
| 359 "start [%p..%p] (%lu bytes)", |
| 360 this->start, this->end, |
| 361 (unsigned long) (this->end - this->start)); |
| 362 |
| 363 return start_embed<Type> (); |
| 364 } |
| 365 |
| 366 inline void end_serialize (void) |
| 367 { |
| 368 DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, |
| 369 "end [%p..%p] serialized %d bytes; %s", |
| 370 this->start, this->end, |
| 371 (int) (this->head - this->start), |
| 372 this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran ou
t of room"); |
| 373 |
| 374 } |
| 375 |
| 376 template <typename Type> |
| 377 inline Type *copy (void) |
| 378 { |
| 379 assert (!this->ran_out_of_room); |
| 380 unsigned int len = this->head - this->start; |
| 381 void *p = malloc (len); |
| 382 if (p) |
| 383 memcpy (p, this->start, len); |
| 384 return reinterpret_cast<Type *> (p); |
| 385 } |
| 386 |
| 387 template <typename Type> |
| 388 inline Type *allocate_size (unsigned int size) |
| 389 { |
| 390 if (unlikely (this->ran_out_of_room || this->end - this->head < size)) { |
| 391 this->ran_out_of_room = true; |
| 392 return NULL; |
| 393 } |
| 394 memset (this->head, 0, size); |
| 395 char *ret = this->head; |
| 396 this->head += size; |
| 397 return reinterpret_cast<Type *> (ret); |
| 398 } |
| 399 |
| 400 template <typename Type> |
| 401 inline Type *allocate_min (void) |
| 402 { |
| 403 return this->allocate_size<Type> (Type::min_size); |
| 404 } |
| 405 |
| 406 template <typename Type> |
| 407 inline Type *start_embed (void) |
| 408 { |
| 409 Type *ret = reinterpret_cast<Type *> (this->head); |
| 410 return ret; |
| 411 } |
| 412 |
| 413 template <typename Type> |
| 414 inline Type *embed (const Type &obj) |
| 415 { |
| 416 unsigned int size = obj.get_size (); |
| 417 Type *ret = this->allocate_size<Type> (size); |
| 418 if (unlikely (!ret)) return NULL; |
| 419 memcpy (ret, obj, size); |
| 420 return ret; |
| 421 } |
| 422 |
| 423 template <typename Type> |
| 424 inline Type *extend_min (Type &obj) |
| 425 { |
| 426 unsigned int size = obj.min_size; |
| 427 assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char
*) &obj + size >= this->head); |
| 428 if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->hea
d))) return NULL; |
| 429 return reinterpret_cast<Type *> (&obj); |
| 430 } |
| 431 |
| 432 template <typename Type> |
| 433 inline Type *extend (Type &obj) |
| 434 { |
| 435 unsigned int size = obj.get_size (); |
| 436 assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char
*) &obj + size >= this->head); |
| 437 if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->hea
d))) return NULL; |
| 438 return reinterpret_cast<Type *> (&obj); |
| 439 } |
| 440 |
| 441 inline void truncate (void *head) |
| 442 { |
| 443 assert (this->start < head && head <= this->head); |
| 444 this->head = (char *) head; |
| 445 } |
| 446 |
| 447 unsigned int debug_depth; |
| 448 char *start, *end, *head; |
| 449 bool ran_out_of_room; |
| 450 }; |
| 451 |
| 452 template <typename Type> |
| 453 struct Supplier |
| 454 { |
| 455 inline Supplier (const Type *array, unsigned int len_) |
| 456 { |
| 457 head = array; |
| 458 len = len_; |
| 459 } |
| 460 inline const Type operator [] (unsigned int i) const |
| 461 { |
| 462 if (unlikely (i >= len)) return Type (); |
| 463 return head[i]; |
| 464 } |
| 465 |
| 466 inline void advance (unsigned int count) |
| 467 { |
| 468 if (unlikely (count > len)) |
| 469 count = len; |
| 470 len -= count; |
| 471 head += count; |
| 472 } |
| 473 |
| 474 private: |
| 475 inline Supplier (const Supplier<Type> &); /* Disallow copy */ |
| 476 inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */ |
| 477 |
| 478 unsigned int len; |
| 479 const Type *head; |
| 480 }; |
| 481 |
| 482 |
| 483 |
328 | 484 |
329 /* | 485 /* |
330 * | 486 * |
331 * The OpenType Font File: Data Types | 487 * The OpenType Font File: Data Types |
332 */ | 488 */ |
333 | 489 |
334 | 490 |
335 /* "The following data types are used in the OpenType font file. | 491 /* "The following data types are used in the OpenType font file. |
336 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ | 492 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ |
337 | 493 |
338 /* | 494 /* |
339 * Int types | 495 * Int types |
340 */ | 496 */ |
341 | 497 |
342 | 498 |
343 template <typename Type, int Bytes> struct BEInt; | 499 template <typename Type, int Bytes> struct BEInt; |
344 | 500 |
345 /* LONGTERMTODO: On machines allowing unaligned access, we can make the | |
346 * following tighter by using byteswap instructions on ints directly. */ | |
347 template <typename Type> | 501 template <typename Type> |
348 struct BEInt<Type, 2> | 502 struct BEInt<Type, 2> |
349 { | 503 { |
350 public: | 504 public: |
351 inline void set (Type i) { hb_be_uint16_put (v,i); } | 505 inline void set (Type i) { hb_be_uint16_put (v,i); } |
352 inline operator Type (void) const { return hb_be_uint16_get (v); } | 506 inline operator Type (void) const { return hb_be_uint16_get (v); } |
353 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_
eq (v, o.v); } | 507 inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_
eq (v, o.v); } |
354 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o)
; } | 508 inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o)
; } |
355 private: uint8_t v[2]; | 509 private: uint8_t v[2]; |
356 }; | 510 }; |
357 template <typename Type> | 511 template <typename Type> |
358 struct BEInt<Type, 4> | 512 struct BEInt<Type, 4> |
359 { | 513 { |
360 public: | 514 public: |
361 inline void set (Type i) { hb_be_uint32_put (v,i); } | 515 inline void set (Type i) { hb_be_uint32_put (v,i); } |
362 inline operator Type (void) const { return hb_be_uint32_get (v); } | 516 inline operator Type (void) const { return hb_be_uint32_get (v); } |
363 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_
eq (v, o.v); } | 517 inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_
eq (v, o.v); } |
364 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o)
; } | 518 inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o)
; } |
365 private: uint8_t v[4]; | 519 private: uint8_t v[4]; |
366 }; | 520 }; |
367 | 521 |
368 /* Integer types in big-endian order and no alignment requirement */ | 522 /* Integer types in big-endian order and no alignment requirement */ |
369 template <typename Type> | 523 template <typename Type> |
370 struct IntType | 524 struct IntType |
371 { | 525 { |
372 inline void set (Type i) { v.set (i); } | 526 inline void set (Type i) { v.set (i); } |
373 inline operator Type(void) const { return v; } | 527 inline operator Type(void) const { return v; } |
374 inline bool operator == (const IntType<Type> &o) const { return v == o.v; } | 528 inline bool operator == (const IntType<Type> &o) const { return v == o.v; } |
375 inline bool operator != (const IntType<Type> &o) const { return v != o.v; } | 529 inline bool operator != (const IntType<Type> &o) const { return v != o.v; } |
| 530 static inline int cmp (const IntType<Type> *a, const IntType<Type> *b) { retur
n b->cmp (*a); } |
| 531 inline int cmp (IntType<Type> va) const { Type a = va; Type b = v; return a <
b ? -1 : a == b ? 0 : +1; } |
376 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +
1; } | 532 inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +
1; } |
377 inline bool sanitize (hb_sanitize_context_t *c) { | 533 inline bool sanitize (hb_sanitize_context_t *c) { |
378 TRACE_SANITIZE (); | 534 TRACE_SANITIZE (); |
379 return TRACE_RETURN (likely (c->check_struct (this))); | 535 return TRACE_RETURN (likely (c->check_struct (this))); |
380 } | 536 } |
381 protected: | 537 protected: |
382 BEInt<Type, sizeof (Type)> v; | 538 BEInt<Type, sizeof (Type)> v; |
383 public: | 539 public: |
384 DEFINE_SIZE_STATIC (sizeof (Type)); | 540 DEFINE_SIZE_STATIC (sizeof (Type)); |
385 }; | 541 }; |
386 | 542 |
387 /* Typedef these to avoid clash with windows.h */ | |
388 #define USHORT HB_USHORT | |
389 #define SHORT HB_SHORT | |
390 #define ULONG HB_ULONG | |
391 #define LONG HB_LONG | |
392 typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */ | 543 typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */ |
393 typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */ | 544 typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */ |
394 typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */ | 545 typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */ |
395 typedef IntType<int32_t> LONG; /* 32-bit signed integer. */ | 546 typedef IntType<int32_t> LONG; /* 32-bit signed integer. */ |
396 | 547 |
397 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ | 548 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ |
398 typedef SHORT FWORD; | 549 typedef SHORT FWORD; |
399 | 550 |
400 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ | 551 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ |
401 typedef USHORT UFWORD; | 552 typedef USHORT UFWORD; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 | 639 |
489 template <typename OffsetType, typename Type> | 640 template <typename OffsetType, typename Type> |
490 struct GenericOffsetTo : OffsetType | 641 struct GenericOffsetTo : OffsetType |
491 { | 642 { |
492 inline const Type& operator () (const void *base) const | 643 inline const Type& operator () (const void *base) const |
493 { | 644 { |
494 unsigned int offset = *this; | 645 unsigned int offset = *this; |
495 if (unlikely (!offset)) return Null(Type); | 646 if (unlikely (!offset)) return Null(Type); |
496 return StructAtOffset<Type> (base, offset); | 647 return StructAtOffset<Type> (base, offset); |
497 } | 648 } |
| 649 inline Type& operator () (void *base) |
| 650 { |
| 651 unsigned int offset = *this; |
| 652 return StructAtOffset<Type> (base, offset); |
| 653 } |
| 654 |
| 655 inline Type& serialize (hb_serialize_context_t *c, void *base) |
| 656 { |
| 657 Type *t = c->start_embed<Type> (); |
| 658 this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ |
| 659 return *t; |
| 660 } |
498 | 661 |
499 inline bool sanitize (hb_sanitize_context_t *c, void *base) { | 662 inline bool sanitize (hb_sanitize_context_t *c, void *base) { |
500 TRACE_SANITIZE (); | 663 TRACE_SANITIZE (); |
501 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); | 664 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); |
502 unsigned int offset = *this; | 665 unsigned int offset = *this; |
503 if (unlikely (!offset)) return TRACE_RETURN (true); | 666 if (unlikely (!offset)) return TRACE_RETURN (true); |
504 Type &obj = StructAtOffset<Type> (base, offset); | 667 Type &obj = StructAtOffset<Type> (base, offset); |
505 return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c)); | 668 return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c)); |
506 } | 669 } |
507 template <typename T> | 670 template <typename T> |
(...skipping 10 matching lines...) Expand all Loading... |
518 /* Set the offset to Null */ | 681 /* Set the offset to Null */ |
519 inline bool neuter (hb_sanitize_context_t *c) { | 682 inline bool neuter (hb_sanitize_context_t *c) { |
520 if (c->may_edit (this, this->static_size)) { | 683 if (c->may_edit (this, this->static_size)) { |
521 this->set (0); /* 0 is Null offset */ | 684 this->set (0); /* 0 is Null offset */ |
522 return true; | 685 return true; |
523 } | 686 } |
524 return false; | 687 return false; |
525 } | 688 } |
526 }; | 689 }; |
527 template <typename Base, typename OffsetType, typename Type> | 690 template <typename Base, typename OffsetType, typename Type> |
528 inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Typ
e> offset) { return offset (base); } | 691 inline const Type& operator + (const Base &base, const GenericOffsetTo<OffsetTyp
e, Type> &offset) { return offset (base); } |
| 692 template <typename Base, typename OffsetType, typename Type> |
| 693 inline Type& operator + (Base &base, GenericOffsetTo<OffsetType, Type> &offset)
{ return offset (base); } |
529 | 694 |
530 template <typename Type> | 695 template <typename Type> |
531 struct OffsetTo : GenericOffsetTo<Offset, Type> {}; | 696 struct OffsetTo : GenericOffsetTo<Offset, Type> {}; |
532 | 697 |
533 template <typename Type> | 698 template <typename Type> |
534 struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {}; | 699 struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {}; |
535 | 700 |
536 | 701 |
537 /* | 702 /* |
538 * Array Types | 703 * Array Types |
(...skipping 12 matching lines...) Expand all Loading... |
551 count = MIN (count, *pcount); | 716 count = MIN (count, *pcount); |
552 *pcount = count; | 717 *pcount = count; |
553 return array + start_offset; | 718 return array + start_offset; |
554 } | 719 } |
555 | 720 |
556 inline const Type& operator [] (unsigned int i) const | 721 inline const Type& operator [] (unsigned int i) const |
557 { | 722 { |
558 if (unlikely (i >= len)) return Null(Type); | 723 if (unlikely (i >= len)) return Null(Type); |
559 return array[i]; | 724 return array[i]; |
560 } | 725 } |
| 726 inline Type& operator [] (unsigned int i) |
| 727 { |
| 728 return array[i]; |
| 729 } |
561 inline unsigned int get_size (void) const | 730 inline unsigned int get_size (void) const |
562 { return len.static_size + len * Type::static_size; } | 731 { return len.static_size + len * Type::static_size; } |
563 | 732 |
| 733 inline bool serialize (hb_serialize_context_t *c, |
| 734 unsigned int items_len) |
| 735 { |
| 736 TRACE_SERIALIZE (); |
| 737 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); |
| 738 len.set (items_len); /* TODO(serialize) Overflow? */ |
| 739 if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); |
| 740 return TRACE_RETURN (true); |
| 741 } |
| 742 |
| 743 inline bool serialize (hb_serialize_context_t *c, |
| 744 Supplier<Type> &items, |
| 745 unsigned int items_len) |
| 746 { |
| 747 TRACE_SERIALIZE (); |
| 748 if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false); |
| 749 for (unsigned int i = 0; i < items_len; i++) |
| 750 array[i] = items[i]; |
| 751 items.advance (items_len); |
| 752 return TRACE_RETURN (true); |
| 753 } |
| 754 |
564 inline bool sanitize (hb_sanitize_context_t *c) { | 755 inline bool sanitize (hb_sanitize_context_t *c) { |
565 TRACE_SANITIZE (); | 756 TRACE_SANITIZE (); |
566 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); | 757 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); |
567 | 758 |
568 /* Note: for structs that do not reference other structs, | 759 /* Note: for structs that do not reference other structs, |
569 * we do not need to call their sanitize() as we already did | 760 * we do not need to call their sanitize() as we already did |
570 * a bound check on the aggregate array size. We just include | 761 * a bound check on the aggregate array size. We just include |
571 * a small unreachable expression to make sure the structs | 762 * a small unreachable expression to make sure the structs |
572 * pointed to do have a simple sanitize(), ie. they do not | 763 * pointed to do have a simple sanitize(), ie. they do not |
573 * reference other structs via offsets. | 764 * reference other structs via offsets. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 struct HeadlessArrayOf | 848 struct HeadlessArrayOf |
658 { | 849 { |
659 inline const Type& operator [] (unsigned int i) const | 850 inline const Type& operator [] (unsigned int i) const |
660 { | 851 { |
661 if (unlikely (i >= len || !i)) return Null(Type); | 852 if (unlikely (i >= len || !i)) return Null(Type); |
662 return array[i-1]; | 853 return array[i-1]; |
663 } | 854 } |
664 inline unsigned int get_size (void) const | 855 inline unsigned int get_size (void) const |
665 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } | 856 { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } |
666 | 857 |
| 858 inline bool serialize (hb_serialize_context_t *c, |
| 859 Supplier<Type> &items, |
| 860 unsigned int items_len) |
| 861 { |
| 862 TRACE_SERIALIZE (); |
| 863 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); |
| 864 len.set (items_len); /* TODO(serialize) Overflow? */ |
| 865 if (unlikely (!items_len)) return TRACE_RETURN (true); |
| 866 if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); |
| 867 for (unsigned int i = 0; i < items_len - 1; i++) |
| 868 array[i] = items[i]; |
| 869 items.advance (items_len - 1); |
| 870 return TRACE_RETURN (true); |
| 871 } |
| 872 |
667 inline bool sanitize_shallow (hb_sanitize_context_t *c) { | 873 inline bool sanitize_shallow (hb_sanitize_context_t *c) { |
668 return c->check_struct (this) | 874 return c->check_struct (this) |
669 && c->check_array (this, Type::static_size, len); | 875 && c->check_array (this, Type::static_size, len); |
670 } | 876 } |
671 | 877 |
672 inline bool sanitize (hb_sanitize_context_t *c) { | 878 inline bool sanitize (hb_sanitize_context_t *c) { |
673 TRACE_SANITIZE (); | 879 TRACE_SANITIZE (); |
674 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); | 880 if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); |
675 | 881 |
676 /* Note: for structs that do not reference other structs, | 882 /* Note: for structs that do not reference other structs, |
(...skipping 14 matching lines...) Expand all Loading... |
691 DEFINE_SIZE_ARRAY (sizeof (USHORT), array); | 897 DEFINE_SIZE_ARRAY (sizeof (USHORT), array); |
692 }; | 898 }; |
693 | 899 |
694 | 900 |
695 /* An array with sorted elements. Supports binary searching. */ | 901 /* An array with sorted elements. Supports binary searching. */ |
696 template <typename Type> | 902 template <typename Type> |
697 struct SortedArrayOf : ArrayOf<Type> { | 903 struct SortedArrayOf : ArrayOf<Type> { |
698 | 904 |
699 template <typename SearchType> | 905 template <typename SearchType> |
700 inline int search (const SearchType &x) const { | 906 inline int search (const SearchType &x) const { |
701 struct Cmp { | 907 unsigned int count = this->len; |
702 static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a);
} | 908 /* Linear search is *much* faster for small counts. */ |
703 }; | 909 if (likely (count < 32)) { |
704 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (
this->array[0]), (hb_compare_func_t) Cmp::cmp); | 910 for (unsigned int i = 0; i < count; i++) |
705 return p ? p - this->array : -1; | 911 » if (this->array[i].cmp (x) == 0) |
| 912 » return i; |
| 913 return -1; |
| 914 } else { |
| 915 struct Cmp { |
| 916 » static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a)
; } |
| 917 }; |
| 918 const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof
(this->array[0]), (hb_compare_func_t) Cmp::cmp); |
| 919 return p ? p - this->array : -1; |
| 920 } |
706 } | 921 } |
707 }; | 922 }; |
708 | 923 |
709 | 924 |
| 925 } // namespace OT |
| 926 |
710 | 927 |
711 #endif /* HB_OPEN_TYPE_PRIVATE_HH */ | 928 #endif /* HB_OPEN_TYPE_PRIVATE_HH */ |
OLD | NEW |