2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OPEN_TYPE_HH
30 #define HB_OPEN_TYPE_HH
35 #include "hb-machinery.hh"
36 #include "hb-subset.hh"
44 * The OpenType Font File: Data Types
48 /* "The following data types are used in the OpenType font file.
49 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
55 /* Integer types in big-endian order and no alignment requirement */
56 template <typename Type
,
57 unsigned int Size
= sizeof (Type
)>
63 explicit constexpr IntType (Type V
) : v
{V
} {}
64 IntType
& operator = (Type i
) { v
= i
; return *this; }
65 /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
66 * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
67 operator typename
std::conditional
<std::is_signed
<Type
>::value
, signed, unsigned>::type () const { return v
; }
69 bool operator == (const IntType
&o
) const { return (Type
) v
== (Type
) o
.v
; }
70 bool operator != (const IntType
&o
) const { return !(*this == o
); }
72 IntType
& operator += (unsigned count
) { *this = *this + count
; return *this; }
73 IntType
& operator -= (unsigned count
) { *this = *this - count
; return *this; }
74 IntType
& operator ++ () { *this += 1; return *this; }
75 IntType
& operator -- () { *this -= 1; return *this; }
76 IntType
operator ++ (int) { IntType
c (*this); ++*this; return c
; }
77 IntType
operator -- (int) { IntType
c (*this); --*this; return c
; }
79 HB_INTERNAL
static int cmp (const IntType
*a
, const IntType
*b
)
80 { return b
->cmp (*a
); }
81 HB_INTERNAL
static int cmp (const void *a
, const void *b
)
83 IntType
*pa
= (IntType
*) a
;
84 IntType
*pb
= (IntType
*) b
;
88 template <typename Type2
,
89 hb_enable_if (std::is_integral
<Type2
>::value
&&
90 sizeof (Type2
) < sizeof (int) &&
91 sizeof (Type
) < sizeof (int))>
92 int cmp (Type2 a
) const
95 return (int) a
- (int) b
;
97 template <typename Type2
,
98 hb_enable_if (hb_is_convertible (Type2
, Type
))>
99 int cmp (Type2 a
) const
102 return a
< b
? -1 : a
== b
? 0 : +1;
104 bool sanitize (hb_sanitize_context_t
*c
) const
106 TRACE_SANITIZE (this);
107 return_trace (likely (c
->check_struct (this)));
112 DEFINE_SIZE_STATIC (Size
);
115 typedef IntType
<uint8_t> HBUINT8
; /* 8-bit unsigned integer. */
116 typedef IntType
<int8_t> HBINT8
; /* 8-bit signed integer. */
117 typedef IntType
<uint16_t> HBUINT16
; /* 16-bit unsigned integer. */
118 typedef IntType
<int16_t> HBINT16
; /* 16-bit signed integer. */
119 typedef IntType
<uint32_t> HBUINT32
; /* 32-bit unsigned integer. */
120 typedef IntType
<int32_t> HBINT32
; /* 32-bit signed integer. */
121 /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
122 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
123 typedef IntType
<uint32_t, 3> HBUINT24
; /* 24-bit unsigned integer. */
125 /* 15-bit unsigned number; top bit used for extension. */
126 struct HBUINT15
: HBUINT16
128 /* TODO Flesh out; actually mask top bit. */
129 HBUINT15
& operator = (uint16_t i
) { HBUINT16::operator= (i
); return *this; }
131 DEFINE_SIZE_STATIC (2);
134 /* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
135 typedef HBINT16 FWORD
;
137 /* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
138 typedef HBINT32 FWORD32
;
140 /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
141 typedef HBUINT16 UFWORD
;
143 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
144 struct F2DOT14
: HBINT16
146 F2DOT14
& operator = (uint16_t i
) { HBINT16::operator= (i
); return *this; }
148 float to_float () const { return ((int32_t) v
) / 16384.f
; }
149 void set_float (float f
) { v
= roundf (f
* 16384.f
); }
151 DEFINE_SIZE_STATIC (2);
154 /* 32-bit signed fixed-point number (16.16). */
155 struct HBFixed
: HBINT32
157 HBFixed
& operator = (uint32_t i
) { HBINT32::operator= (i
); return *this; }
159 float to_float () const { return ((int32_t) v
) / 65536.f
; }
160 void set_float (float f
) { v
= roundf (f
* 65536.f
); }
162 DEFINE_SIZE_STATIC (4);
165 /* Date represented in number of seconds since 12:00 midnight, January 1,
166 * 1904. The value is represented as a signed 64-bit integer. */
169 bool sanitize (hb_sanitize_context_t
*c
) const
171 TRACE_SANITIZE (this);
172 return_trace (likely (c
->check_struct (this)));
178 DEFINE_SIZE_STATIC (8);
181 /* Array of four uint8s (length = 32 bits) used to identify a script, language
182 * system, feature, or baseline */
183 struct Tag
: HBUINT32
185 Tag
& operator = (hb_tag_t i
) { HBUINT32::operator= (i
); return *this; }
186 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
187 operator const char* () const { return reinterpret_cast<const char *> (this); }
188 operator char* () { return reinterpret_cast<char *> (this); }
190 DEFINE_SIZE_STATIC (4);
193 /* Glyph index number, same as uint16 (length = 16 bits) */
194 struct HBGlyphID16
: HBUINT16
196 HBGlyphID16
& operator = (uint16_t i
) { HBUINT16::operator= (i
); return *this; }
199 /* Script/language-system/feature index */
200 struct Index
: HBUINT16
{
201 static constexpr unsigned NOT_FOUND_INDEX
= 0xFFFFu
;
202 Index
& operator = (uint16_t i
) { HBUINT16::operator= (i
); return *this; }
204 DECLARE_NULL_NAMESPACE_BYTES (OT
, Index
);
206 typedef Index NameID
;
208 struct VarIdx
: HBUINT32
{
209 static constexpr unsigned NO_VARIATION
= 0xFFFFFFFFu
;
210 VarIdx
& operator = (uint32_t i
) { HBUINT32::operator= (i
); return *this; }
212 DECLARE_NULL_NAMESPACE_BYTES (OT
, VarIdx
);
214 /* Offset, Null offset = 0 */
215 template <typename Type
, bool has_null
=true>
218 Offset
& operator = (typename
Type::type i
) { Type::operator= (i
); return *this; }
222 bool is_null () const { return has_null
&& 0 == *this; }
225 DEFINE_SIZE_STATIC (sizeof (Type
));
228 typedef Offset
<HBUINT16
> Offset16
;
229 typedef Offset
<HBUINT24
> Offset24
;
230 typedef Offset
<HBUINT32
> Offset32
;
234 struct CheckSum
: HBUINT32
236 CheckSum
& operator = (uint32_t i
) { HBUINT32::operator= (i
); return *this; }
238 /* This is reference implementation from the spec. */
239 static uint32_t CalcTableChecksum (const HBUINT32
*Table
, uint32_t Length
)
242 assert (0 == (Length
& 3));
243 const HBUINT32
*EndPtr
= Table
+ Length
/ HBUINT32::static_size
;
245 while (Table
< EndPtr
)
250 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
251 void set_for_data (const void *data
, unsigned int length
)
252 { *this = CalcTableChecksum ((const HBUINT32
*) data
, length
); }
255 DEFINE_SIZE_STATIC (4);
263 template <typename FixedType
=HBUINT16
>
266 uint32_t to_int () const { return (major
<< (sizeof (FixedType
) * 8)) + minor
; }
268 bool sanitize (hb_sanitize_context_t
*c
) const
270 TRACE_SANITIZE (this);
271 return_trace (c
->check_struct (this));
277 DEFINE_SIZE_STATIC (2 * sizeof (FixedType
));
282 * Template subclasses of Offset that do the dereferencing.
286 template <typename Type
, bool has_null
>
289 static const Type
*get_null () { return nullptr; }
290 static Type
*get_crap () { return nullptr; }
292 template <typename Type
>
293 struct _hb_has_null
<Type
, true>
295 static const Type
*get_null () { return &Null (Type
); }
296 static Type
*get_crap () { return &Crap (Type
); }
299 template <typename Type
, typename OffsetType
, bool has_null
=true>
300 struct OffsetTo
: Offset
<OffsetType
, has_null
>
302 HB_DELETE_COPY_ASSIGN (OffsetTo
);
303 OffsetTo () = default;
305 OffsetTo
& operator = (typename
OffsetType::type i
) { OffsetType::operator= (i
); return *this; }
307 const Type
& operator () (const void *base
) const
309 if (unlikely (this->is_null ())) return *_hb_has_null
<Type
, has_null
>::get_null ();
310 return StructAtOffset
<const Type
> (base
, *this);
312 Type
& operator () (void *base
) const
314 if (unlikely (this->is_null ())) return *_hb_has_null
<Type
, has_null
>::get_crap ();
315 return StructAtOffset
<Type
> (base
, *this);
318 template <typename Base
,
319 hb_enable_if (hb_is_convertible (const Base
, const void *))>
320 friend const Type
& operator + (const Base
&base
, const OffsetTo
&offset
) { return offset ((const void *) base
); }
321 template <typename Base
,
322 hb_enable_if (hb_is_convertible (const Base
, const void *))>
323 friend const Type
& operator + (const OffsetTo
&offset
, const Base
&base
) { return offset ((const void *) base
); }
324 template <typename Base
,
325 hb_enable_if (hb_is_convertible (Base
, void *))>
326 friend Type
& operator + (Base
&&base
, OffsetTo
&offset
) { return offset ((void *) base
); }
327 template <typename Base
,
328 hb_enable_if (hb_is_convertible (Base
, void *))>
329 friend Type
& operator + (OffsetTo
&offset
, Base
&&base
) { return offset ((void *) base
); }
332 template <typename
...Ts
>
333 bool serialize_subset (hb_subset_context_t
*c
, const OffsetTo
& src
,
334 const void *src_base
, Ts
&&... ds
)
340 auto *s
= c
->serializer
;
344 bool ret
= c
->dispatch (src_base
+src
, std::forward
<Ts
> (ds
)...);
346 if (ret
|| !has_null
)
347 s
->add_link (*this, s
->pop_pack ());
355 template <typename
...Ts
>
356 bool serialize_serialize (hb_serialize_context_t
*c
, Ts
&&... ds
)
360 Type
* obj
= c
->push
<Type
> ();
361 bool ret
= obj
->serialize (c
, std::forward
<Ts
> (ds
)...);
364 c
->add_link (*this, c
->pop_pack ());
371 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
372 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
373 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
375 template <typename
...Ts
>
376 bool serialize_copy (hb_serialize_context_t
*c
, const OffsetTo
& src
,
377 const void *src_base
, unsigned dst_bias
,
378 hb_serialize_context_t::whence_t whence
,
387 bool ret
= c
->copy (src_base
+src
, std::forward
<Ts
> (ds
)...);
389 c
->add_link (*this, c
->pop_pack (), whence
, dst_bias
);
394 bool serialize_copy (hb_serialize_context_t
*c
, const OffsetTo
& src
,
395 const void *src_base
, unsigned dst_bias
= 0)
396 { return serialize_copy (c
, src
, src_base
, dst_bias
, hb_serialize_context_t::Head
); }
398 bool sanitize_shallow (hb_sanitize_context_t
*c
, const void *base
) const
400 TRACE_SANITIZE (this);
401 if (unlikely (!c
->check_struct (this))) return_trace (false);
402 if (unlikely (this->is_null ())) return_trace (true);
403 if (unlikely ((const char *) base
+ (unsigned) *this < (const char *) base
)) return_trace (false);
407 template <typename
...Ts
>
408 bool sanitize (hb_sanitize_context_t
*c
, const void *base
, Ts
&&... ds
) const
410 TRACE_SANITIZE (this);
411 return_trace (sanitize_shallow (c
, base
) &&
413 c
->dispatch (StructAtOffset
<Type
> (base
, *this), std::forward
<Ts
> (ds
)...) ||
417 /* Set the offset to Null */
418 bool neuter (hb_sanitize_context_t
*c
) const
420 if (!has_null
) return false;
421 return c
->try_set (this, 0);
423 DEFINE_SIZE_STATIC (sizeof (OffsetType
));
425 /* Partial specializations. */
426 template <typename Type
, bool has_null
=true> using Offset16To
= OffsetTo
<Type
, HBUINT16
, has_null
>;
427 template <typename Type
, bool has_null
=true> using Offset24To
= OffsetTo
<Type
, HBUINT24
, has_null
>;
428 template <typename Type
, bool has_null
=true> using Offset32To
= OffsetTo
<Type
, HBUINT32
, has_null
>;
430 template <typename Type
, typename OffsetType
> using NNOffsetTo
= OffsetTo
<Type
, OffsetType
, false>;
431 template <typename Type
> using NNOffset16To
= Offset16To
<Type
, false>;
432 template <typename Type
> using NNOffset24To
= Offset24To
<Type
, false>;
433 template <typename Type
> using NNOffset32To
= Offset32To
<Type
, false>;
440 template <typename Type
>
441 struct UnsizedArrayOf
444 static constexpr unsigned item_size
= hb_static_size (Type
);
446 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf
);
448 const Type
& operator [] (int i_
) const
450 unsigned int i
= (unsigned int) i_
;
451 const Type
*p
= &arrayZ
[i
];
452 if (unlikely (p
< arrayZ
)) return Null (Type
); /* Overflowed. */
455 Type
& operator [] (int i_
)
457 unsigned int i
= (unsigned int) i_
;
458 Type
*p
= &arrayZ
[i
];
459 if (unlikely (p
< arrayZ
)) return Crap (Type
); /* Overflowed. */
463 unsigned int get_size (unsigned int len
) const
464 { return len
* Type::static_size
; }
466 template <typename T
> operator T
* () { return arrayZ
; }
467 template <typename T
> operator const T
* () const { return arrayZ
; }
468 hb_array_t
<Type
> as_array (unsigned int len
)
469 { return hb_array (arrayZ
, len
); }
470 hb_array_t
<const Type
> as_array (unsigned int len
) const
471 { return hb_array (arrayZ
, len
); }
473 template <typename T
>
474 Type
&lsearch (unsigned int len
, const T
&x
, Type
¬_found
= Crap (Type
))
475 { return *as_array (len
).lsearch (x
, ¬_found
); }
476 template <typename T
>
477 const Type
&lsearch (unsigned int len
, const T
&x
, const Type
¬_found
= Null (Type
)) const
478 { return *as_array (len
).lsearch (x
, ¬_found
); }
479 template <typename T
>
480 bool lfind (unsigned int len
, const T
&x
, unsigned int *i
= nullptr,
481 hb_not_found_t not_found
= HB_NOT_FOUND_DONT_STORE
,
482 unsigned int to_store
= (unsigned int) -1) const
483 { return as_array (len
).lfind (x
, i
, not_found
, to_store
); }
485 void qsort (unsigned int len
, unsigned int start
= 0, unsigned int end
= (unsigned int) -1)
486 { as_array (len
).qsort (start
, end
); }
488 bool serialize (hb_serialize_context_t
*c
, unsigned int items_len
)
490 TRACE_SERIALIZE (this);
491 if (unlikely (!c
->extend (this, items_len
))) return_trace (false);
494 template <typename Iterator
,
495 hb_requires (hb_is_source_of (Iterator
, Type
))>
496 bool serialize (hb_serialize_context_t
*c
, Iterator items
)
498 TRACE_SERIALIZE (this);
499 unsigned count
= items
.len ();
500 if (unlikely (!serialize (c
, count
))) return_trace (false);
501 /* TODO Umm. Just exhaust the iterator instead? Being extra
502 * cautious right now.. */
503 for (unsigned i
= 0; i
< count
; i
++, ++items
)
508 UnsizedArrayOf
* copy (hb_serialize_context_t
*c
, unsigned count
) const
510 TRACE_SERIALIZE (this);
511 auto *out
= c
->start_embed (this);
512 if (unlikely (!as_array (count
).copy (c
))) return_trace (nullptr);
516 template <typename
...Ts
>
517 bool sanitize (hb_sanitize_context_t
*c
, unsigned int count
, Ts
&&... ds
) const
519 TRACE_SANITIZE (this);
520 if (unlikely (!sanitize_shallow (c
, count
))) return_trace (false);
521 if (!sizeof... (Ts
) && std::is_trivially_copyable
<Type
>::value
) return_trace (true);
522 for (unsigned int i
= 0; i
< count
; i
++)
523 if (unlikely (!c
->dispatch (arrayZ
[i
], std::forward
<Ts
> (ds
)...)))
524 return_trace (false);
528 bool sanitize_shallow (hb_sanitize_context_t
*c
, unsigned int count
) const
530 TRACE_SANITIZE (this);
531 return_trace (c
->check_array (arrayZ
, count
));
535 Type arrayZ
[HB_VAR_ARRAY
];
537 DEFINE_SIZE_UNBOUNDED (0);
540 /* Unsized array of offset's */
541 template <typename Type
, typename OffsetType
, bool has_null
=true>
542 using UnsizedArray16OfOffsetTo
= UnsizedArrayOf
<OffsetTo
<Type
, OffsetType
, has_null
>>;
544 /* Unsized array of offsets relative to the beginning of the array itself. */
545 template <typename Type
, typename OffsetType
, bool has_null
=true>
546 struct UnsizedListOfOffset16To
: UnsizedArray16OfOffsetTo
<Type
, OffsetType
, has_null
>
548 const Type
& operator [] (int i_
) const
550 unsigned int i
= (unsigned int) i_
;
551 const OffsetTo
<Type
, OffsetType
, has_null
> *p
= &this->arrayZ
[i
];
552 if (unlikely (p
< this->arrayZ
)) return Null (Type
); /* Overflowed. */
555 Type
& operator [] (int i_
)
557 unsigned int i
= (unsigned int) i_
;
558 const OffsetTo
<Type
, OffsetType
, has_null
> *p
= &this->arrayZ
[i
];
559 if (unlikely (p
< this->arrayZ
)) return Crap (Type
); /* Overflowed. */
563 template <typename
...Ts
>
564 bool sanitize (hb_sanitize_context_t
*c
, unsigned int count
, Ts
&&... ds
) const
566 TRACE_SANITIZE (this);
567 return_trace ((UnsizedArray16OfOffsetTo
<Type
, OffsetType
, has_null
>
568 ::sanitize (c
, count
, this, std::forward
<Ts
> (ds
)...)));
572 /* An array with sorted elements. Supports binary searching. */
573 template <typename Type
>
574 struct SortedUnsizedArrayOf
: UnsizedArrayOf
<Type
>
576 hb_sorted_array_t
<Type
> as_array (unsigned int len
)
577 { return hb_sorted_array (this->arrayZ
, len
); }
578 hb_sorted_array_t
<const Type
> as_array (unsigned int len
) const
579 { return hb_sorted_array (this->arrayZ
, len
); }
580 operator hb_sorted_array_t
<Type
> () { return as_array (); }
581 operator hb_sorted_array_t
<const Type
> () const { return as_array (); }
583 template <typename T
>
584 Type
&bsearch (unsigned int len
, const T
&x
, Type
¬_found
= Crap (Type
))
585 { return *as_array (len
).bsearch (x
, ¬_found
); }
586 template <typename T
>
587 const Type
&bsearch (unsigned int len
, const T
&x
, const Type
¬_found
= Null (Type
)) const
588 { return *as_array (len
).bsearch (x
, ¬_found
); }
589 template <typename T
>
590 bool bfind (unsigned int len
, const T
&x
, unsigned int *i
= nullptr,
591 hb_not_found_t not_found
= HB_NOT_FOUND_DONT_STORE
,
592 unsigned int to_store
= (unsigned int) -1) const
593 { return as_array (len
).bfind (x
, i
, not_found
, to_store
); }
597 /* An array with a number of elements. */
598 template <typename Type
, typename LenType
>
602 static constexpr unsigned item_size
= hb_static_size (Type
);
604 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf
);
606 const Type
& operator [] (int i_
) const
608 unsigned int i
= (unsigned int) i_
;
609 if (unlikely (i
>= len
)) return Null (Type
);
612 Type
& operator [] (int i_
)
614 unsigned int i
= (unsigned int) i_
;
615 if (unlikely (i
>= len
)) return Crap (Type
);
619 unsigned int get_size () const
620 { return len
.static_size
+ len
* Type::static_size
; }
622 explicit operator bool () const { return len
; }
624 void pop () { len
--; }
626 hb_array_t
< Type
> as_array () { return hb_array (arrayZ
, len
); }
627 hb_array_t
<const Type
> as_array () const { return hb_array (arrayZ
, len
); }
630 typedef hb_array_t
<const Type
> iter_t
;
631 typedef hb_array_t
< Type
> writer_t
;
632 iter_t
iter () const { return as_array (); }
633 writer_t
writer () { return as_array (); }
634 operator iter_t () const { return iter (); }
635 operator writer_t () { return writer (); }
637 hb_array_t
<const Type
> sub_array (unsigned int start_offset
, unsigned int count
) const
638 { return as_array ().sub_array (start_offset
, count
); }
639 hb_array_t
<const Type
> sub_array (unsigned int start_offset
, unsigned int *count
= nullptr /* IN/OUT */) const
640 { return as_array ().sub_array (start_offset
, count
); }
641 hb_array_t
<Type
> sub_array (unsigned int start_offset
, unsigned int count
)
642 { return as_array ().sub_array (start_offset
, count
); }
643 hb_array_t
<Type
> sub_array (unsigned int start_offset
, unsigned int *count
= nullptr /* IN/OUT */)
644 { return as_array ().sub_array (start_offset
, count
); }
646 template <typename T
>
647 Type
&lsearch (const T
&x
, Type
¬_found
= Crap (Type
))
648 { return *as_array ().lsearch (x
, ¬_found
); }
649 template <typename T
>
650 const Type
&lsearch (const T
&x
, const Type
¬_found
= Null (Type
)) const
651 { return *as_array ().lsearch (x
, ¬_found
); }
652 template <typename T
>
653 bool lfind (const T
&x
, unsigned int *i
= nullptr,
654 hb_not_found_t not_found
= HB_NOT_FOUND_DONT_STORE
,
655 unsigned int to_store
= (unsigned int) -1) const
656 { return as_array ().lfind (x
, i
, not_found
, to_store
); }
658 void qsort (unsigned int start
= 0, unsigned int end
= (unsigned int) -1)
659 { as_array ().qsort (start
, end
); }
661 HB_NODISCARD
bool serialize (hb_serialize_context_t
*c
, unsigned items_len
)
663 TRACE_SERIALIZE (this);
664 if (unlikely (!c
->extend_min (this))) return_trace (false);
665 c
->check_assign (len
, items_len
, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW
);
666 if (unlikely (!c
->extend (this))) return_trace (false);
669 template <typename Iterator
,
670 hb_requires (hb_is_source_of (Iterator
, Type
))>
671 HB_NODISCARD
bool serialize (hb_serialize_context_t
*c
, Iterator items
)
673 TRACE_SERIALIZE (this);
674 unsigned count
= items
.len ();
675 if (unlikely (!serialize (c
, count
))) return_trace (false);
676 /* TODO Umm. Just exhaust the iterator instead? Being extra
677 * cautious right now.. */
678 for (unsigned i
= 0; i
< count
; i
++, ++items
)
683 Type
* serialize_append (hb_serialize_context_t
*c
)
685 TRACE_SERIALIZE (this);
687 if (unlikely (!len
|| !c
->extend (this)))
690 return_trace (nullptr);
692 return_trace (&arrayZ
[len
- 1]);
695 ArrayOf
* copy (hb_serialize_context_t
*c
) const
697 TRACE_SERIALIZE (this);
698 auto *out
= c
->start_embed (this);
699 if (unlikely (!c
->extend_min (out
))) return_trace (nullptr);
700 c
->check_assign (out
->len
, len
, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW
);
701 if (unlikely (!as_array ().copy (c
))) return_trace (nullptr);
705 template <typename
...Ts
>
706 bool sanitize (hb_sanitize_context_t
*c
, Ts
&&... ds
) const
708 TRACE_SANITIZE (this);
709 if (unlikely (!sanitize_shallow (c
))) return_trace (false);
710 if (!sizeof... (Ts
) && std::is_trivially_copyable
<Type
>::value
) return_trace (true);
711 unsigned int count
= len
;
712 for (unsigned int i
= 0; i
< count
; i
++)
713 if (unlikely (!c
->dispatch (arrayZ
[i
], std::forward
<Ts
> (ds
)...)))
714 return_trace (false);
718 bool sanitize_shallow (hb_sanitize_context_t
*c
) const
720 TRACE_SANITIZE (this);
721 return_trace (len
.sanitize (c
) && c
->check_array (arrayZ
, len
));
726 Type arrayZ
[HB_VAR_ARRAY
];
728 DEFINE_SIZE_ARRAY (sizeof (LenType
), arrayZ
);
730 template <typename Type
> using Array16Of
= ArrayOf
<Type
, HBUINT16
>;
731 template <typename Type
> using Array32Of
= ArrayOf
<Type
, HBUINT32
>;
732 using PString
= ArrayOf
<HBUINT8
, HBUINT8
>;
734 /* Array of Offset's */
735 template <typename Type
> using Array16OfOffset16To
= ArrayOf
<OffsetTo
<Type
, HBUINT16
>, HBUINT16
>;
736 template <typename Type
> using Array16OfOffset32To
= ArrayOf
<OffsetTo
<Type
, HBUINT32
>, HBUINT16
>;
737 template <typename Type
> using Array32OfOffset32To
= ArrayOf
<OffsetTo
<Type
, HBUINT32
>, HBUINT32
>;
739 /* Array of offsets relative to the beginning of the array itself. */
740 template <typename Type
>
741 struct List16OfOffset16To
: Array16OfOffset16To
<Type
>
743 const Type
& operator [] (int i_
) const
745 unsigned int i
= (unsigned int) i_
;
746 if (unlikely (i
>= this->len
)) return Null (Type
);
747 return this+this->arrayZ
[i
];
749 const Type
& operator [] (int i_
)
751 unsigned int i
= (unsigned int) i_
;
752 if (unlikely (i
>= this->len
)) return Crap (Type
);
753 return this+this->arrayZ
[i
];
756 bool subset (hb_subset_context_t
*c
) const
759 struct List16OfOffset16To
<Type
> *out
= c
->serializer
->embed (*this);
760 if (unlikely (!out
)) return_trace (false);
761 unsigned int count
= this->len
;
762 for (unsigned int i
= 0; i
< count
; i
++)
763 out
->arrayZ
[i
].serialize_subset (c
, this->arrayZ
[i
], this, out
);
767 template <typename
...Ts
>
768 bool sanitize (hb_sanitize_context_t
*c
, Ts
&&... ds
) const
770 TRACE_SANITIZE (this);
771 return_trace (Array16OfOffset16To
<Type
>::sanitize (c
, this, std::forward
<Ts
> (ds
)...));
775 /* An array starting at second element. */
776 template <typename Type
, typename LenType
=HBUINT16
>
777 struct HeadlessArrayOf
779 static constexpr unsigned item_size
= Type::static_size
;
781 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf
);
783 const Type
& operator [] (int i_
) const
785 unsigned int i
= (unsigned int) i_
;
786 if (unlikely (i
>= lenP1
|| !i
)) return Null (Type
);
789 Type
& operator [] (int i_
)
791 unsigned int i
= (unsigned int) i_
;
792 if (unlikely (i
>= lenP1
|| !i
)) return Crap (Type
);
795 unsigned int get_size () const
796 { return lenP1
.static_size
+ get_length () * Type::static_size
; }
798 unsigned get_length () const { return lenP1
? lenP1
- 1 : 0; }
800 hb_array_t
< Type
> as_array () { return hb_array (arrayZ
, get_length ()); }
801 hb_array_t
<const Type
> as_array () const { return hb_array (arrayZ
, get_length ()); }
804 typedef hb_array_t
<const Type
> iter_t
;
805 typedef hb_array_t
< Type
> writer_t
;
806 iter_t
iter () const { return as_array (); }
807 writer_t
writer () { return as_array (); }
808 operator iter_t () const { return iter (); }
809 operator writer_t () { return writer (); }
811 bool serialize (hb_serialize_context_t
*c
, unsigned int items_len
)
813 TRACE_SERIALIZE (this);
814 if (unlikely (!c
->extend_min (this))) return_trace (false);
815 c
->check_assign (lenP1
, items_len
+ 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW
);
816 if (unlikely (!c
->extend (this))) return_trace (false);
819 template <typename Iterator
,
820 hb_requires (hb_is_source_of (Iterator
, Type
))>
821 bool serialize (hb_serialize_context_t
*c
, Iterator items
)
823 TRACE_SERIALIZE (this);
824 unsigned count
= items
.len ();
825 if (unlikely (!serialize (c
, count
))) return_trace (false);
826 /* TODO Umm. Just exhaust the iterator instead? Being extra
827 * cautious right now.. */
828 for (unsigned i
= 0; i
< count
; i
++, ++items
)
833 template <typename
...Ts
>
834 bool sanitize (hb_sanitize_context_t
*c
, Ts
&&... ds
) const
836 TRACE_SANITIZE (this);
837 if (unlikely (!sanitize_shallow (c
))) return_trace (false);
838 if (!sizeof... (Ts
) && std::is_trivially_copyable
<Type
>::value
) return_trace (true);
839 unsigned int count
= get_length ();
840 for (unsigned int i
= 0; i
< count
; i
++)
841 if (unlikely (!c
->dispatch (arrayZ
[i
], std::forward
<Ts
> (ds
)...)))
842 return_trace (false);
847 bool sanitize_shallow (hb_sanitize_context_t
*c
) const
849 TRACE_SANITIZE (this);
850 return_trace (lenP1
.sanitize (c
) &&
851 (!lenP1
|| c
->check_array (arrayZ
, lenP1
- 1)));
856 Type arrayZ
[HB_VAR_ARRAY
];
858 DEFINE_SIZE_ARRAY (sizeof (LenType
), arrayZ
);
861 /* An array storing length-1. */
862 template <typename Type
, typename LenType
=HBUINT16
>
865 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1
);
867 const Type
& operator [] (int i_
) const
869 unsigned int i
= (unsigned int) i_
;
870 if (unlikely (i
> lenM1
)) return Null (Type
);
873 Type
& operator [] (int i_
)
875 unsigned int i
= (unsigned int) i_
;
876 if (unlikely (i
> lenM1
)) return Crap (Type
);
879 unsigned int get_size () const
880 { return lenM1
.static_size
+ (lenM1
+ 1) * Type::static_size
; }
882 template <typename
...Ts
>
883 bool sanitize (hb_sanitize_context_t
*c
, Ts
&&... ds
) const
885 TRACE_SANITIZE (this);
886 if (unlikely (!sanitize_shallow (c
))) return_trace (false);
887 if (!sizeof... (Ts
) && std::is_trivially_copyable
<Type
>::value
) return_trace (true);
888 unsigned int count
= lenM1
+ 1;
889 for (unsigned int i
= 0; i
< count
; i
++)
890 if (unlikely (!c
->dispatch (arrayZ
[i
], std::forward
<Ts
> (ds
)...)))
891 return_trace (false);
896 bool sanitize_shallow (hb_sanitize_context_t
*c
) const
898 TRACE_SANITIZE (this);
899 return_trace (lenM1
.sanitize (c
) &&
900 (c
->check_array (arrayZ
, lenM1
+ 1)));
905 Type arrayZ
[HB_VAR_ARRAY
];
907 DEFINE_SIZE_ARRAY (sizeof (LenType
), arrayZ
);
910 /* An array with sorted elements. Supports binary searching. */
911 template <typename Type
, typename LenType
>
912 struct SortedArrayOf
: ArrayOf
<Type
, LenType
>
914 hb_sorted_array_t
< Type
> as_array () { return hb_sorted_array (this->arrayZ
, this->len
); }
915 hb_sorted_array_t
<const Type
> as_array () const { return hb_sorted_array (this->arrayZ
, this->len
); }
918 typedef hb_sorted_array_t
<const Type
> iter_t
;
919 typedef hb_sorted_array_t
< Type
> writer_t
;
920 iter_t
iter () const { return as_array (); }
921 writer_t
writer () { return as_array (); }
922 operator iter_t () const { return iter (); }
923 operator writer_t () { return writer (); }
925 hb_sorted_array_t
<const Type
> sub_array (unsigned int start_offset
, unsigned int count
) const
926 { return as_array ().sub_array (start_offset
, count
); }
927 hb_sorted_array_t
<const Type
> sub_array (unsigned int start_offset
, unsigned int *count
= nullptr /* IN/OUT */) const
928 { return as_array ().sub_array (start_offset
, count
); }
929 hb_sorted_array_t
<Type
> sub_array (unsigned int start_offset
, unsigned int count
)
930 { return as_array ().sub_array (start_offset
, count
); }
931 hb_sorted_array_t
<Type
> sub_array (unsigned int start_offset
, unsigned int *count
= nullptr /* IN/OUT */)
932 { return as_array ().sub_array (start_offset
, count
); }
934 bool serialize (hb_serialize_context_t
*c
, unsigned int items_len
)
936 TRACE_SERIALIZE (this);
937 bool ret
= ArrayOf
<Type
, LenType
>::serialize (c
, items_len
);
940 template <typename Iterator
,
941 hb_requires (hb_is_sorted_source_of (Iterator
, Type
))>
942 bool serialize (hb_serialize_context_t
*c
, Iterator items
)
944 TRACE_SERIALIZE (this);
945 bool ret
= ArrayOf
<Type
, LenType
>::serialize (c
, items
);
949 template <typename T
>
950 Type
&bsearch (const T
&x
, Type
¬_found
= Crap (Type
))
951 { return *as_array ().bsearch (x
, ¬_found
); }
952 template <typename T
>
953 const Type
&bsearch (const T
&x
, const Type
¬_found
= Null (Type
)) const
954 { return *as_array ().bsearch (x
, ¬_found
); }
955 template <typename T
>
956 bool bfind (const T
&x
, unsigned int *i
= nullptr,
957 hb_not_found_t not_found
= HB_NOT_FOUND_DONT_STORE
,
958 unsigned int to_store
= (unsigned int) -1) const
959 { return as_array ().bfind (x
, i
, not_found
, to_store
); }
962 template <typename Type
> using SortedArray16Of
= SortedArrayOf
<Type
, HBUINT16
>;
963 template <typename Type
> using SortedArray32Of
= SortedArrayOf
<Type
, HBUINT32
>;
966 * Binary-search arrays
969 template <typename LenType
=HBUINT16
>
970 struct BinSearchHeader
972 operator uint32_t () const { return len
; }
974 bool sanitize (hb_sanitize_context_t
*c
) const
976 TRACE_SANITIZE (this);
977 return_trace (c
->check_struct (this));
980 BinSearchHeader
& operator = (unsigned int v
)
984 entrySelector
= hb_max (1u, hb_bit_storage (v
)) - 1;
985 searchRange
= 16 * (1u << entrySelector
);
986 rangeShift
= v
* 16 > searchRange
987 ? 16 * v
- searchRange
995 LenType entrySelector
;
999 DEFINE_SIZE_STATIC (8);
1002 template <typename Type
, typename LenType
=HBUINT16
>
1003 using BinSearchArrayOf
= SortedArrayOf
<Type
, BinSearchHeader
<LenType
>>;
1006 struct VarSizedBinSearchHeader
1009 bool sanitize (hb_sanitize_context_t
*c
) const
1011 TRACE_SANITIZE (this);
1012 return_trace (c
->check_struct (this));
1015 HBUINT16 unitSize
; /* Size of a lookup unit for this search in bytes. */
1016 HBUINT16 nUnits
; /* Number of units of the preceding size to be searched. */
1017 HBUINT16 searchRange
; /* The value of unitSize times the largest power of 2
1018 * that is less than or equal to the value of nUnits. */
1019 HBUINT16 entrySelector
; /* The log base 2 of the largest power of 2 less than
1020 * or equal to the value of nUnits. */
1021 HBUINT16 rangeShift
; /* The value of unitSize times the difference of the
1022 * value of nUnits minus the largest power of 2 less
1023 * than or equal to the value of nUnits. */
1025 DEFINE_SIZE_STATIC (10);
1028 template <typename Type
>
1029 struct VarSizedBinSearchArrayOf
1031 static constexpr unsigned item_size
= Type::static_size
;
1033 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf
);
1035 bool last_is_terminator () const
1037 if (unlikely (!header
.nUnits
)) return false;
1041 * "The number of termination values that need to be included is table-specific.
1042 * The value that indicates binary search termination is 0xFFFF." */
1043 const HBUINT16
*words
= &StructAtOffset
<HBUINT16
> (&bytesZ
, (header
.nUnits
- 1) * header
.unitSize
);
1044 unsigned int count
= Type::TerminationWordCount
;
1045 for (unsigned int i
= 0; i
< count
; i
++)
1046 if (words
[i
] != 0xFFFFu
)
1051 const Type
& operator [] (int i_
) const
1053 unsigned int i
= (unsigned int) i_
;
1054 if (unlikely (i
>= get_length ())) return Null (Type
);
1055 return StructAtOffset
<Type
> (&bytesZ
, i
* header
.unitSize
);
1057 Type
& operator [] (int i_
)
1059 unsigned int i
= (unsigned int) i_
;
1060 if (unlikely (i
>= get_length ())) return Crap (Type
);
1061 return StructAtOffset
<Type
> (&bytesZ
, i
* header
.unitSize
);
1063 unsigned int get_length () const
1064 { return header
.nUnits
- last_is_terminator (); }
1065 unsigned int get_size () const
1066 { return header
.static_size
+ header
.nUnits
* header
.unitSize
; }
1068 template <typename
...Ts
>
1069 bool sanitize (hb_sanitize_context_t
*c
, Ts
&&... ds
) const
1071 TRACE_SANITIZE (this);
1072 if (unlikely (!sanitize_shallow (c
))) return_trace (false);
1073 if (!sizeof... (Ts
) && std::is_trivially_copyable
<Type
>::value
) return_trace (true);
1074 unsigned int count
= get_length ();
1075 for (unsigned int i
= 0; i
< count
; i
++)
1076 if (unlikely (!(*this)[i
].sanitize (c
, std::forward
<Ts
> (ds
)...)))
1077 return_trace (false);
1078 return_trace (true);
1081 template <typename T
>
1082 const Type
*bsearch (const T
&key
) const
1085 return hb_bsearch_impl (&pos
,
1087 (const void *) bytesZ
,
1090 _hb_cmp_method
<T
, Type
>)
1091 ? (const Type
*) (((const char *) &bytesZ
) + (pos
* header
.unitSize
))
1096 bool sanitize_shallow (hb_sanitize_context_t
*c
) const
1098 TRACE_SANITIZE (this);
1099 return_trace (header
.sanitize (c
) &&
1100 Type::static_size
<= header
.unitSize
&&
1101 c
->check_range (bytesZ
.arrayZ
,
1107 VarSizedBinSearchHeader header
;
1108 UnsizedArrayOf
<HBUINT8
> bytesZ
;
1110 DEFINE_SIZE_ARRAY (10, bytesZ
);
1114 } /* namespace OT */
1117 #endif /* HB_OPEN_TYPE_HH */