diff options
Diffstat (limited to 'src/3rdparty/harfbuzz-ng/src/hb-open-type.hh')
-rw-r--r-- | src/3rdparty/harfbuzz-ng/src/hb-open-type.hh | 482 |
1 files changed, 293 insertions, 189 deletions
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh index af242ece12..9c11f14344 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh @@ -33,6 +33,7 @@ #include "hb-blob.hh" #include "hb-face.hh" #include "hb-machinery.hh" +#include "hb-meta.hh" #include "hb-subset.hh" @@ -53,14 +54,19 @@ namespace OT { */ /* Integer types in big-endian order and no alignment requirement */ -template <typename Type, unsigned int Size> +template <typename Type, + unsigned int Size = sizeof (Type)> struct IntType { typedef Type type; - typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type; - IntType& operator = (wide_type i) { v = i; return *this; } - operator wide_type () const { return v; } + IntType () = default; + explicit constexpr IntType (Type V) : v {V} {} + IntType& operator = (Type i) { v = i; return *this; } + /* For reason we define cast out operator for signed/unsigned, instead of Type, see: + * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */ + operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () const { return v; } + bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } bool operator != (const IntType &o) const { return !(*this == o); } @@ -73,19 +79,33 @@ struct IntType HB_INTERNAL static int cmp (const IntType *a, const IntType *b) { return b->cmp (*a); } - template <typename Type2> + HB_INTERNAL static int cmp (const void *a, const void *b) + { + IntType *pa = (IntType *) a; + IntType *pb = (IntType *) b; + + return pb->cmp (*pa); + } + template <typename Type2, + hb_enable_if (std::is_integral<Type2>::value && + sizeof (Type2) < sizeof (int) && + sizeof (Type) < sizeof (int))> int cmp (Type2 a) const { Type b = v; - if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int)) - return (int) a - (int) b; - else - return a < b ? -1 : a == b ? 0 : +1; + return (int) a - (int) b; + } + template <typename Type2, + hb_enable_if (hb_is_convertible (Type2, Type))> + int cmp (Type2 a) const + { + Type b = v; + return a < b ? -1 : a == b ? 0 : +1; } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: BEInt<Type, Size> v; @@ -93,16 +113,25 @@ struct IntType DEFINE_SIZE_STATIC (Size); }; -typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */ -typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */ -typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */ -typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */ -typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */ -typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */ +typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */ +typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */ +typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */ +typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */ +typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */ +typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */ /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */ +/* 15-bit unsigned number; top bit used for extension. */ +struct HBUINT15 : HBUINT16 +{ + /* TODO Flesh out; actually mask top bit. */ + HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; } + public: + DEFINE_SIZE_STATIC (2); +}; + /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */ typedef HBINT16 FWORD; @@ -112,27 +141,29 @@ typedef HBINT32 FWORD32; /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ typedef HBUINT16 UFWORD; -/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ -struct F2DOT14 : HBINT16 +template <typename Type, unsigned fraction_bits> +struct HBFixed : Type { - F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } - // 16384 means 1<<14 - float to_float () const { return ((int32_t) v) / 16384.f; } - void set_float (float f) { v = roundf (f * 16384.f); } + static constexpr float shift = (float) (1 << fraction_bits); + static_assert (Type::static_size * 8 > fraction_bits, ""); + + operator signed () const = delete; + operator unsigned () const = delete; + typename Type::type to_int () const { return Type::v; } + void set_int (typename Type::type i ) { Type::v = i; } + float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; } + void set_float (float f) { Type::v = roundf (f * shift); } public: - DEFINE_SIZE_STATIC (2); + DEFINE_SIZE_STATIC (Type::static_size); }; +/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ +using F2DOT14 = HBFixed<HBINT16, 14>; +using F4DOT12 = HBFixed<HBINT16, 12>; +using F6DOT10 = HBFixed<HBINT16, 10>; + /* 32-bit signed fixed-point number (16.16). */ -struct HBFixed : HBINT32 -{ - HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } - // 65536 means 1<<16 - float to_float () const { return ((int32_t) v) / 65536.f; } - void set_float (float f) { v = roundf (f * 65536.f); } - public: - DEFINE_SIZE_STATIC (4); -}; +using F16DOT16 = HBFixed<HBINT32, 16>; /* Date represented in number of seconds since 12:00 midnight, January 1, * 1904. The value is represented as a signed 64-bit integer. */ @@ -141,7 +172,7 @@ struct LONGDATETIME bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: HBINT32 major; @@ -156,16 +187,20 @@ struct Tag : HBUINT32 { Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ - operator const char* () const { return reinterpret_cast<const char *> (&this->v); } - operator char* () { return reinterpret_cast<char *> (&this->v); } + operator const char* () const { return reinterpret_cast<const char *> (this); } + operator char* () { return reinterpret_cast<char *> (this); } public: DEFINE_SIZE_STATIC (4); }; /* Glyph index number, same as uint16 (length = 16 bits) */ -struct HBGlyphID : HBUINT16 +struct HBGlyphID16 : HBUINT16 +{ + HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } +}; +struct HBGlyphID24 : HBUINT24 { - HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } + HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; } }; /* Script/language-system/feature index */ @@ -177,6 +212,18 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, Index); typedef Index NameID; +struct VarIdx : HBUINT32 { + static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; + static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, ""); + static uint32_t add (uint32_t i, unsigned short v) + { + if (i == NO_VARIATION) return i; + return i + v; + } + VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } +}; +DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); + /* Offset, Null offset = 0 */ template <typename Type, bool has_null=true> struct Offset : Type @@ -187,18 +234,12 @@ struct Offset : Type bool is_null () const { return has_null && 0 == *this; } - void *serialize (hb_serialize_context_t *c, const void *base) - { - void *t = c->start_embed<void> (); - c->check_assign (*this, (unsigned) ((char *) t - (char *) base)); - return t; - } - public: DEFINE_SIZE_STATIC (sizeof (Type)); }; typedef Offset<HBUINT16> Offset16; +typedef Offset<HBUINT24> Offset24; typedef Offset<HBUINT32> Offset32; @@ -268,9 +309,15 @@ struct _hb_has_null<Type, true> static Type *get_crap () { return &Crap (Type); } }; -template <typename Type, typename OffsetType=HBUINT16, bool has_null=true> +template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true> struct OffsetTo : Offset<OffsetType, has_null> { + using target_t = Type; + + // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time. + static_assert (has_null == false || + (hb_has_null_size (Type) || !hb_has_min_size (Type)), ""); + HB_DELETE_COPY_ASSIGN (OffsetTo); OffsetTo () = default; @@ -288,29 +335,22 @@ struct OffsetTo : Offset<OffsetType, has_null> } template <typename Base, - hb_enable_if (hb_is_convertible (const Base, const void *))> + hb_enable_if (hb_is_convertible (const Base, const BaseType *))> friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } template <typename Base, - hb_enable_if (hb_is_convertible (const Base, const void *))> + hb_enable_if (hb_is_convertible (const Base, const BaseType *))> friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } template <typename Base, - hb_enable_if (hb_is_convertible (Base, void *))> + hb_enable_if (hb_is_convertible (Base, BaseType *))> friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } template <typename Base, - hb_enable_if (hb_is_convertible (Base, void *))> + hb_enable_if (hb_is_convertible (Base, BaseType *))> friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } - Type& serialize (hb_serialize_context_t *c, const void *base) - { - return * (Type *) Offset<OffsetType>::serialize (c, base); - } - template <typename ...Ts> - bool serialize_subset (hb_subset_context_t *c, - const OffsetTo& src, - const void *src_base, - const void *dst_base, - Ts&&... ds) + template <typename Base, typename ...Ts> + bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, + const Base *src_base, Ts&&... ds) { *this = 0; if (src.is_null ()) @@ -320,22 +360,41 @@ struct OffsetTo : Offset<OffsetType, has_null> s->push (); - bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...); + bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...); if (ret || !has_null) - s->add_link (*this, s->pop_pack (), dst_base); + s->add_link (*this, s->pop_pack ()); else s->pop_discard (); return ret; } + + template <typename ...Ts> + bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds) + { + *this = 0; + + Type* obj = c->push<Type> (); + bool ret = obj->serialize (c, std::forward<Ts> (ds)...); + + if (ret) + c->add_link (*this, c->pop_pack ()); + else + c->pop_discard (); + + return ret; + } + /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ + /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 + * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... + */ template <typename ...Ts> - bool serialize_copy (hb_serialize_context_t *c, - const OffsetTo& src, - const void *src_base, - const void *dst_base, + bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, + const void *src_base, unsigned dst_bias, + hb_serialize_context_t::whence_t whence, Ts&&... ds) { *this = 0; @@ -344,29 +403,38 @@ struct OffsetTo : Offset<OffsetType, has_null> c->push (); - bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...); + bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...); - c->add_link (*this, c->pop_pack (), dst_base); + c->add_link (*this, c->pop_pack (), whence, dst_bias); return ret; } - bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const + bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, + const void *src_base, unsigned dst_bias = 0) + { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } + + bool sanitize_shallow (hb_sanitize_context_t *c, const BaseType *base) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); - if (unlikely (this->is_null ())) return_trace (true); - if (unlikely (!c->check_range (base, *this))) return_trace (false); + hb_barrier (); + //if (unlikely (this->is_null ())) return_trace (true); + if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); return_trace (true); } template <typename ...Ts> - bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + bool sanitize (hb_sanitize_context_t *c, const BaseType *base, Ts&&... ds) const { TRACE_SANITIZE (this); return_trace (sanitize_shallow (c, base) && + hb_barrier () && (this->is_null () || - c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) || + c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) || neuter (c))); } @@ -379,12 +447,14 @@ struct OffsetTo : Offset<OffsetType, has_null> DEFINE_SIZE_STATIC (sizeof (OffsetType)); }; /* Partial specializations. */ -template <typename Type, bool has_null=true> -using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>; -template <typename Type, typename OffsetType=HBUINT16> -using NNOffsetTo = OffsetTo<Type, OffsetType, false>; -template <typename Type> -using LNNOffsetTo = LOffsetTo<Type, false>; +template <typename Type, typename BaseType=void, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, BaseType, has_null>; +template <typename Type, typename BaseType=void, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, BaseType, has_null>; +template <typename Type, typename BaseType=void, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, BaseType, has_null>; + +template <typename Type, typename OffsetType, typename BaseType=void> using NNOffsetTo = OffsetTo<Type, OffsetType, BaseType, false>; +template <typename Type, typename BaseType=void> using NNOffset16To = Offset16To<Type, BaseType, false>; +template <typename Type, typename BaseType=void> using NNOffset24To = Offset24To<Type, BaseType, false>; +template <typename Type, typename BaseType=void> using NNOffset32To = Offset32To<Type, BaseType, false>; /* @@ -399,22 +469,16 @@ struct UnsizedArrayOf HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); - const Type& operator [] (int i_) const + const Type& operator [] (unsigned int i) const { - unsigned int i = (unsigned int) i_; - const Type *p = &arrayZ[i]; - if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */ - return *p; + return arrayZ[i]; } - Type& operator [] (int i_) + Type& operator [] (unsigned int i) { - unsigned int i = (unsigned int) i_; - Type *p = &arrayZ[i]; - if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */ - return *p; + return arrayZ[i]; } - unsigned int get_size (unsigned int len) const + static unsigned int get_size (unsigned int len) { return len * Type::static_size; } template <typename T> operator T * () { return arrayZ; } @@ -423,8 +487,6 @@ struct UnsizedArrayOf { return hb_array (arrayZ, len); } hb_array_t<const Type> as_array (unsigned int len) const { return hb_array (arrayZ, len); } - operator hb_array_t< Type> () { return as_array (); } - operator hb_array_t<const Type> () const { return as_array (); } template <typename T> Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) @@ -432,14 +494,19 @@ struct UnsizedArrayOf template <typename T> const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const { return *as_array (len).lsearch (x, ¬_found); } + template <typename T> + bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr, + hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const + { return as_array (len).lfind (x, i, not_found, to_store); } void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array (len).qsort (start, end); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend (*this, items_len))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false); return_trace (true); } template <typename Iterator, @@ -447,8 +514,8 @@ struct UnsizedArrayOf bool serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); - unsigned count = items.len (); - if (unlikely (!serialize (c, count))) return_trace (false); + unsigned count = hb_len (items); + if (unlikely (!serialize (c, count, false))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ for (unsigned i = 0; i < count; i++, ++items) @@ -465,13 +532,15 @@ struct UnsizedArrayOf } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); for (unsigned int i = 0; i < count; i++) - if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) + if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) return_trace (false); return_trace (true); } @@ -489,25 +558,27 @@ struct UnsizedArrayOf }; /* Unsized array of offset's */ -template <typename Type, typename OffsetType, bool has_null=true> -using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>; +template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true> +using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, BaseType, has_null>>; /* Unsized array of offsets relative to the beginning of the array itself. */ -template <typename Type, typename OffsetType, bool has_null=true> -struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null> +template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true> +struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null> { const Type& operator [] (int i_) const { unsigned int i = (unsigned int) i_; - const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; - if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */ + const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i]; + if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */ + _hb_compiler_memory_r_barrier (); return this+*p; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; - const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i]; - if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */ + const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i]; + if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */ + _hb_compiler_memory_r_barrier (); return this+*p; } @@ -515,8 +586,8 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null> bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const { TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null> - ::sanitize (c, count, this, hb_forward<Ts> (ds)...))); + return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null> + ::sanitize (c, count, this, std::forward<Ts> (ds)...))); } }; @@ -539,14 +610,14 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf<Type> { return *as_array (len).bsearch (x, ¬_found); } template <typename T> bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const + hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const { return as_array (len).bfind (x, i, not_found, to_store); } }; /* An array with a number of elements. */ -template <typename Type, typename LenType=HBUINT16> +template <typename Type, typename LenType> struct ArrayOf { typedef Type item_t; @@ -558,12 +629,14 @@ struct ArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= len)) return Null (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= len)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } @@ -585,30 +658,40 @@ struct ArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return arrayZ; } + const Type *end () const { return arrayZ + len; } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + template <typename T> + Type &lsearch (const T &x, Type ¬_found = Crap (Type)) + { return *as_array ().lsearch (x, ¬_found); } + template <typename T> + const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const + { return *as_array ().lsearch (x, ¬_found); } + template <typename T> + bool lfind (const T &x, unsigned int *i = nullptr, + hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const + { return as_array ().lfind (x, i, not_found, to_store); } + + void qsort () + { as_array ().qsort (); } + + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - c->check_assign (len, items_len); - if (unlikely (!c->extend (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); + c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template <typename Iterator, hb_requires (hb_is_source_of (Iterator, Type))> - bool serialize (hb_serialize_context_t *c, Iterator items) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); - unsigned count = items.len (); - if (unlikely (!serialize (c, count))) return_trace (false); + unsigned count = hb_len (items); + if (unlikely (!serialize (c, count, false))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ for (unsigned i = 0; i < count; i++, ++items) @@ -620,7 +703,7 @@ struct ArrayOf { TRACE_SERIALIZE (this); len++; - if (unlikely (!len || !c->extend (*this))) + if (unlikely (!len || !c->extend (this))) { len--; return_trace (nullptr); @@ -633,38 +716,32 @@ struct ArrayOf TRACE_SERIALIZE (this); auto *out = c->start_embed (this); if (unlikely (!c->extend_min (out))) return_trace (nullptr); - c->check_assign (out->len, len); + c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); if (unlikely (!as_array ().copy (c))) return_trace (nullptr); return_trace (out); } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = len; for (unsigned int i = 0; i < count; i++) - if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) + if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) return_trace (false); return_trace (true); } - template <typename T> - Type &lsearch (const T &x, Type ¬_found = Crap (Type)) - { return *as_array ().lsearch (x, ¬_found); } - template <typename T> - const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const - { return *as_array ().lsearch (x, ¬_found); } - - void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) - { as_array ().qsort (start, end); } - bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); + return_trace (len.sanitize (c) && + hb_barrier () && + c->check_array_sized (arrayZ, len, sizeof (LenType))); } public: @@ -673,39 +750,39 @@ struct ArrayOf public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; -template <typename Type> -using LArrayOf = ArrayOf<Type, HBUINT32>; +template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>; +template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>; +template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>; using PString = ArrayOf<HBUINT8, HBUINT8>; /* Array of Offset's */ -template <typename Type> -using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>; -template <typename Type> -using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>; -template <typename Type> -using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; +template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>; +template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>; +template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>; /* Array of offsets relative to the beginning of the array itself. */ -template <typename Type> -struct OffsetListOf : OffsetArrayOf<Type> +template <typename Type, typename OffsetType> +struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16> { const Type& operator [] (int i_) const { unsigned int i = (unsigned int) i_; if (unlikely (i >= this->len)) return Null (Type); + _hb_compiler_memory_r_barrier (); return this+this->arrayZ[i]; } const Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= this->len)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return this+this->arrayZ[i]; } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - struct OffsetListOf<Type> *out = c->serializer->embed (*this); + struct List16OfOffsetTo *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); unsigned int count = this->len; for (unsigned int i = 0; i < count; i++) @@ -717,12 +794,15 @@ struct OffsetListOf : OffsetArrayOf<Type> bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); - return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...)); + return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...))); } }; +template <typename Type> +using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>; + /* An array starting at second element. */ -template <typename Type, typename LenType=HBUINT16> +template <typename Type, typename LenType> struct HeadlessArrayOf { static constexpr unsigned item_size = Type::static_size; @@ -733,12 +813,14 @@ struct HeadlessArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= lenP1 || !i)) return Null (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i-1]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= lenP1 || !i)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i-1]; } unsigned int get_size () const @@ -757,21 +839,25 @@ struct HeadlessArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + /* Faster range-based for loop. */ + const Type *begin () const { return arrayZ; } + const Type *end () const { return arrayZ + get_length (); } + + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - c->check_assign (lenP1, items_len + 1); - if (unlikely (!c->extend (*this))) return_trace (false); + if (unlikely (!c->extend_min (this))) return_trace (false); + c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template <typename Iterator, hb_requires (hb_is_source_of (Iterator, Type))> - bool serialize (hb_serialize_context_t *c, Iterator items) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); - unsigned count = items.len (); - if (unlikely (!serialize (c, count))) return_trace (false); + unsigned count = hb_len (items); + if (unlikely (!serialize (c, count, false))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ for (unsigned i = 0; i < count; i++, ++items) @@ -780,14 +866,16 @@ struct HeadlessArrayOf } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) - if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) + if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) return_trace (false); return_trace (true); } @@ -797,7 +885,8 @@ struct HeadlessArrayOf { TRACE_SANITIZE (this); return_trace (lenP1.sanitize (c) && - (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); + hb_barrier () && + (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType)))); } public: @@ -806,6 +895,7 @@ struct HeadlessArrayOf public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; +template <typename Type> using HeadlessArray16Of = HeadlessArrayOf<Type, HBUINT16>; /* An array storing length-1. */ template <typename Type, typename LenType=HBUINT16> @@ -817,25 +907,30 @@ struct ArrayOfM1 { unsigned int i = (unsigned int) i_; if (unlikely (i > lenM1)) return Null (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i > lenM1)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } unsigned int get_size () const { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) - if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...))) + if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) return_trace (false); return_trace (true); } @@ -845,7 +940,8 @@ struct ArrayOfM1 { TRACE_SANITIZE (this); return_trace (lenM1.sanitize (c) && - (c->check_array (arrayZ, lenM1 + 1))); + hb_barrier () && + (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType)))); } public: @@ -856,7 +952,7 @@ struct ArrayOfM1 }; /* An array with sorted elements. Supports binary searching. */ -template <typename Type, typename LenType=HBUINT16> +template <typename Type, typename LenType> struct SortedArrayOf : ArrayOf<Type, LenType> { hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } @@ -870,14 +966,9 @@ struct SortedArrayOf : ArrayOf<Type, LenType> operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return this->arrayZ; } + const Type *end () const { return this->arrayZ + this->len; } bool serialize (hb_serialize_context_t *c, unsigned int items_len) { @@ -894,6 +985,13 @@ struct SortedArrayOf : ArrayOf<Type, LenType> return_trace (ret); } + SortedArrayOf* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + SortedArrayOf* out = reinterpret_cast<SortedArrayOf *> (ArrayOf<Type, LenType>::copy (c)); + return_trace (out); + } + template <typename T> Type &bsearch (const T &x, Type ¬_found = Crap (Type)) { return *as_array ().bsearch (x, ¬_found); } @@ -902,11 +1000,15 @@ struct SortedArrayOf : ArrayOf<Type, LenType> { return *as_array ().bsearch (x, ¬_found); } template <typename T> bool bfind (const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, unsigned int to_store = (unsigned int) -1) const { return as_array ().bfind (x, i, not_found, to_store); } }; +template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>; +template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>; +template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>; + /* * Binary-search arrays */ @@ -997,12 +1099,14 @@ struct VarSizedBinSearchArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= get_length ())) return Null (Type); + _hb_compiler_memory_r_barrier (); return StructAtOffset<Type> (&bytesZ, i * header.unitSize); } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= get_length ())) return Crap (Type); + _hb_compiler_memory_r_barrier (); return StructAtOffset<Type> (&bytesZ, i * header.unitSize); } unsigned int get_length () const @@ -1011,14 +1115,16 @@ struct VarSizedBinSearchArrayOf { return header.static_size + header.nUnits * header.unitSize; } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); + hb_barrier (); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) - if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...))) + if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...))) return_trace (false); return_trace (true); } @@ -1026,18 +1132,15 @@ struct VarSizedBinSearchArrayOf template <typename T> const Type *bsearch (const T &key) const { - unsigned int size = header.unitSize; - int min = 0, max = (int) get_length () - 1; - while (min <= max) - { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size)); - int c = p->cmp (key); - if (c < 0) max = mid - 1; - else if (c > 0) min = mid + 1; - else return p; - } - return nullptr; + unsigned pos; + return hb_bsearch_impl (&pos, + key, + (const void *) bytesZ, + get_length (), + header.unitSize, + _hb_cmp_method<T, Type>) + ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize)) + : nullptr; } private: @@ -1045,6 +1148,7 @@ struct VarSizedBinSearchArrayOf { TRACE_SANITIZE (this); return_trace (header.sanitize (c) && + hb_barrier () && Type::static_size <= header.unitSize && c->check_range (bytesZ.arrayZ, header.nUnits, |