blob: d0d01a68c52216a0911486768cccdcbc74762dc7 [file] [log] [blame]
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02003 * Copyright © 2012 Google, Inc.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -05006 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +020026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod64aef3a2008-01-23 16:14:38 -050027 */
28
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070029#ifndef HB_OPEN_TYPE_HH
30#define HB_OPEN_TYPE_HH
Behdad Esfahbod12c45682006-12-28 06:10:59 -050031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb.hh"
33#include "hb-blob.hh"
34#include "hb-face.hh"
35#include "hb-machinery.hh"
Thomas Devoogdtc657c4e2022-05-10 10:00:06 +020036#include "hb-meta.hh"
Behdad Esfahbodd1f29902018-08-31 16:31:00 -070037#include "hb-subset.hh"
Behdad Esfahbod12c45682006-12-28 06:10:59 -050038
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050039
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040040namespace OT {
41
Behdad Esfahboda3263aa2010-04-22 18:29:09 -040042
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -050043/*
44 *
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -040045 * The OpenType Font File: Data Types
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -050046 */
47
48
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -050049/* "The following data types are used in the OpenType font file.
50 * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
Behdad Esfahbodf78e70c2006-12-21 22:30:38 -050051
Behdad Esfahbod5f810362009-05-17 00:54:25 -040052/*
53 * Int types
54 */
55
Behdad Esfahbod2467c662010-04-21 23:11:45 -040056/* Integer types in big-endian order and no alignment requirement */
Behdad Esfahbodcc16b262021-02-22 17:55:47 -070057template <typename Type,
Behdad Esfahbod567cedc2021-02-22 22:09:15 -070058 unsigned int Size = sizeof (Type)>
Behdad Esfahbode032ed92010-04-21 03:11:46 -040059struct IntType
60{
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -070061 typedef Type type;
Behdad Esfahbod11d2f492018-12-01 13:12:21 -050062
Behdad Esfahbodcc16b262021-02-22 17:55:47 -070063 IntType () = default;
Behdad Esfahbod567cedc2021-02-22 22:09:15 -070064 explicit constexpr IntType (Type V) : v {V} {}
65 IntType& operator = (Type i) { v = i; return *this; }
Behdad Esfahbod486da352021-02-23 13:58:14 -070066 /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
67 * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
Behdad Esfahbod7a078c32021-11-02 00:44:51 -060068 operator typename std::conditional<std::is_signed<Type>::value, signed, unsigned>::type () const { return v; }
Behdad Esfahbod09836012021-02-22 22:33:17 -070069
Behdad Esfahbod8938dd22019-06-17 14:12:11 -070070 bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
71 bool operator != (const IntType &o) const { return !(*this == o); }
Behdad Esfahbod307bd6d2019-08-28 13:49:17 -070072
73 IntType& operator += (unsigned count) { *this = *this + count; return *this; }
74 IntType& operator -= (unsigned count) { *this = *this - count; return *this; }
75 IntType& operator ++ () { *this += 1; return *this; }
76 IntType& operator -- () { *this -= 1; return *this; }
77 IntType operator ++ (int) { IntType c (*this); ++*this; return c; }
78 IntType operator -- (int) { IntType c (*this); --*this; return c; }
79
Behdad Esfahbod8938dd22019-06-17 14:12:11 -070080 HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
Behdad Esfahbod95df00a2019-04-12 17:50:03 -040081 { return b->cmp (*a); }
Qunxin Liu82afc752020-02-04 13:24:37 -080082 HB_INTERNAL static int cmp (const void *a, const void *b)
83 {
84 IntType *pa = (IntType *) a;
85 IntType *pb = (IntType *) b;
86
87 return pb->cmp (*pa);
88 }
Behdad Esfahbod98374ce2021-02-05 13:40:10 -050089 template <typename Type2,
Behdad Esfahbod943921c2021-11-02 00:26:46 -060090 hb_enable_if (std::is_integral<Type2>::value &&
Behdad Esfahbod98374ce2021-02-05 13:40:10 -050091 sizeof (Type2) < sizeof (int) &&
92 sizeof (Type) < sizeof (int))>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033093 int cmp (Type2 a) const
Behdad Esfahbod88a399a2015-02-19 16:57:12 +030094 {
95 Type b = v;
Behdad Esfahbod98374ce2021-02-05 13:40:10 -050096 return (int) a - (int) b;
97 }
98 template <typename Type2,
99 hb_enable_if (hb_is_convertible (Type2, Type))>
100 int cmp (Type2 a) const
101 {
102 Type b = v;
103 return a < b ? -1 : a == b ? 0 : +1;
Behdad Esfahbod88a399a2015-02-19 16:57:12 +0300104 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330105 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300106 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500107 TRACE_SANITIZE (this);
Behdad Esfahbod7c4e9082022-07-11 14:01:52 -0600108 return_trace (c->check_struct (this));
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400109 }
Behdad Esfahboda82ef7a2010-05-10 17:55:03 -0400110 protected:
Behdad Esfahbodbd61bc12012-12-11 16:00:43 -0500111 BEInt<Type, Size> v;
Behdad Esfahbod569da922010-05-10 16:38:32 -0400112 public:
Behdad Esfahbodbd61bc12012-12-11 16:00:43 -0500113 DEFINE_SIZE_STATIC (Size);
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400114};
115
Behdad Esfahbode5b7bc42020-06-29 01:24:02 -0700116typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */
117typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */
118typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */
119typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */
120typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */
121typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */
Behdad Esfahbod11d2f492018-12-01 13:12:21 -0500122/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
123 * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
Behdad Esfahbodc3a8b042018-12-01 00:14:48 -0500124typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
Behdad Esfahbode032ed92010-04-21 03:11:46 -0400125
Behdad Esfahbod14a2df72021-09-19 23:06:09 -0400126/* 15-bit unsigned number; top bit used for extension. */
127struct HBUINT15 : HBUINT16
128{
129 /* TODO Flesh out; actually mask top bit. */
130 HBUINT15& operator = (uint16_t i ) { HBUINT16::operator= (i); return *this; }
131 public:
132 DEFINE_SIZE_STATIC (2);
133};
134
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100135/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
136typedef HBINT16 FWORD;
Behdad Esfahbodae9877d2011-08-17 14:43:45 +0200137
Behdad Esfahbod22955b22018-10-10 19:58:20 -0400138/* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
139typedef HBINT32 FWORD32;
140
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100141/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
142typedef HBUINT16 UFWORD;
Behdad Esfahbodae9877d2011-08-17 14:43:45 +0200143
Behdad Esfahbod68b62962016-03-01 16:41:53 +0900144/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100145struct F2DOT14 : HBINT16
Behdad Esfahbod68b62962016-03-01 16:41:53 +0900146{
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700147 F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
Ebrahim Byagowice99dd02018-04-15 22:08:50 +0430148 // 16384 means 1<<14
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330149 float to_float () const { return ((int32_t) v) / 16384.f; }
Behdad Esfahboddfc57802019-05-07 23:26:09 -0700150 void set_float (float f) { v = roundf (f * 16384.f); }
Behdad Esfahbod68b62962016-03-01 16:41:53 +0900151 public:
152 DEFINE_SIZE_STATIC (2);
153};
154
Behdad Esfahbod587d4622016-04-30 19:20:56 +0200155/* 32-bit signed fixed-point number (16.16). */
Behdad Esfahbod229ef1d2019-09-10 10:31:07 -0700156struct HBFixed : HBINT32
Behdad Esfahbod587d4622016-04-30 19:20:56 +0200157{
Behdad Esfahbod229ef1d2019-09-10 10:31:07 -0700158 HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
Ebrahim Byagowice99dd02018-04-15 22:08:50 +0430159 // 65536 means 1<<16
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330160 float to_float () const { return ((int32_t) v) / 65536.f; }
Behdad Esfahboddfc57802019-05-07 23:26:09 -0700161 void set_float (float f) { v = roundf (f * 65536.f); }
Behdad Esfahbod587d4622016-04-30 19:20:56 +0200162 public:
163 DEFINE_SIZE_STATIC (4);
164};
165
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400166/* Date represented in number of seconds since 12:00 midnight, January 1,
167 * 1904. The value is represented as a signed 64-bit integer. */
168struct LONGDATETIME
169{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330170 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300171 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500172 TRACE_SANITIZE (this);
Behdad Esfahbod7c4e9082022-07-11 14:01:52 -0600173 return_trace (c->check_struct (this));
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400174 }
Behdad Esfahbod6775da32014-01-23 14:18:49 -0500175 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100176 HBINT32 major;
177 HBUINT32 minor;
Behdad Esfahbode29caf32010-05-19 11:47:17 -0400178 public:
179 DEFINE_SIZE_STATIC (8);
180};
181
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500182/* Array of four uint8s (length = 32 bits) used to identify a script, language
183 * system, feature, or baseline */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100184struct Tag : HBUINT32
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400185{
Behdad Esfahbod6492b232019-06-17 14:19:13 -0700186 Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
Behdad Esfahbodbefc0222006-12-25 09:14:52 -0500187 /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
Behdad Esfahbod8b2f9ad2021-02-22 17:42:24 -0700188 operator const char* () const { return reinterpret_cast<const char *> (this); }
189 operator char* () { return reinterpret_cast<char *> (this); }
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400190 public:
191 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500192};
193
194/* Glyph index number, same as uint16 (length = 16 bits) */
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400195struct HBGlyphID16 : HBUINT16
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700196{
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400197 HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700198};
Behdad Esfahbod2c672612022-07-06 12:26:16 -0600199struct HBGlyphID24 : HBUINT24
200{
201 HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; }
202};
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500203
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400204/* Script/language-system/feature index */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100205struct Index : HBUINT16 {
Behdad Esfahbod5d4b0372019-01-22 12:11:24 +0100206 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700207 Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400208};
Behdad Esfahbod92806ee2018-08-05 21:41:52 -0700209DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
Behdad Esfahbodb5db4f12010-05-10 22:22:22 -0400210
Behdad Esfahbod07386ea2018-10-22 21:18:27 -0700211typedef Index NameID;
212
Behdad Esfahbod9ffc46b2021-03-31 11:26:18 -0600213struct VarIdx : HBUINT32 {
214 static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
215 VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
216};
217DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
218
Behdad Esfahbod99d28172014-06-27 15:12:52 -0400219/* Offset, Null offset = 0 */
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200220template <typename Type, bool has_null=true>
Behdad Esfahbod99d28172014-06-27 15:12:52 -0400221struct Offset : Type
Behdad Esfahbode95e0312013-01-08 16:15:46 -0600222{
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700223 Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
224
Behdad Esfahbodf7c0b432018-10-19 15:23:49 -0700225 typedef Type type;
226
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330227 bool is_null () const { return has_null && 0 == *this; }
Behdad Esfahbodc479a592018-02-07 21:13:10 -0600228
Behdad Esfahboddf1c7d52018-02-25 19:06:25 -0800229 public:
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330230 DEFINE_SIZE_STATIC (sizeof (Type));
Behdad Esfahbode95e0312013-01-08 16:15:46 -0600231};
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400232
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100233typedef Offset<HBUINT16> Offset16;
Behdad Esfahbod21792812021-03-31 11:20:21 -0600234typedef Offset<HBUINT24> Offset24;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100235typedef Offset<HBUINT32> Offset32;
Behdad Esfahbodc6173a32017-11-14 21:09:03 -0800236
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500237
238/* CheckSum */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100239struct CheckSum : HBUINT32
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400240{
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700241 CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
242
Behdad Esfahbod05bad3b2013-07-21 17:05:02 -0400243 /* This is reference implementation from the spec. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330244 static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400245 {
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500246 uint32_t Sum = 0L;
Behdad Esfahbodec2538c2018-02-23 15:51:26 -0800247 assert (0 == (Length & 3));
248 const HBUINT32 *EndPtr = Table + Length / HBUINT32::static_size;
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500249
250 while (Table < EndPtr)
251 Sum += *Table++;
252 return Sum;
253 }
Behdad Esfahbod05bad3b2013-07-21 17:05:02 -0400254
255 /* Note: data should be 4byte aligned and have 4byte padding at the end. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330256 void set_for_data (const void *data, unsigned int length)
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700257 { *this = CalcTableChecksum ((const HBUINT32 *) data, length); }
Behdad Esfahbod05bad3b2013-07-21 17:05:02 -0400258
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400259 public:
260 DEFINE_SIZE_STATIC (4);
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500261};
262
263
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500264/*
265 * Version Numbers
266 */
267
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100268template <typename FixedType=HBUINT16>
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -0400269struct FixedVersion
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400270{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330271 uint32_t to_int () const { return (major << (sizeof (FixedType) * 8)) + minor; }
Behdad Esfahbod96908b82009-05-24 12:30:40 -0400272
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330273 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300274 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500275 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100276 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400277 }
278
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +0900279 FixedType major;
280 FixedType minor;
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400281 public:
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330282 DEFINE_SIZE_STATIC (2 * sizeof (FixedType));
Behdad Esfahbod6b4ce012006-12-21 22:31:10 -0500283};
284
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400285
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400286/*
Behdad Esfahbod99d28172014-06-27 15:12:52 -0400287 * Template subclasses of Offset that do the dereferencing.
Behdad Esfahbodf0abcd62010-05-02 18:14:25 -0400288 * Use: (base+offset)
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400289 */
290
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500291template <typename Type, bool has_null>
292struct _hb_has_null
293{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330294 static const Type *get_null () { return nullptr; }
295 static Type *get_crap () { return nullptr; }
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500296};
297template <typename Type>
298struct _hb_has_null<Type, true>
299{
Ebrahim Byagowi05584132019-10-01 13:49:55 +0330300 static const Type *get_null () { return &Null (Type); }
301 static Type *get_crap () { return &Crap (Type); }
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500302};
303
Behdad Esfahbod9b4b5842021-03-31 13:27:21 -0600304template <typename Type, typename OffsetType, bool has_null=true>
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200305struct OffsetTo : Offset<OffsetType, has_null>
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400306{
Behdad Esfahbod9843f072022-07-15 16:03:55 -0600307 // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
308 static_assert (has_null == false ||
309 (hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
310
Behdad Esfahbod07776b62019-04-15 16:43:34 -0400311 HB_DELETE_COPY_ASSIGN (OffsetTo);
312 OffsetTo () = default;
313
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700314 OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
315
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330316 const Type& operator () (const void *base) const
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400317 {
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500318 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200319 return StructAtOffset<const Type> (base, *this);
Behdad Esfahboddcd1b072018-05-31 17:58:40 -0700320 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330321 Type& operator () (void *base) const
Behdad Esfahboddcd1b072018-05-31 17:58:40 -0700322 {
Behdad Esfahbod4d4fd642018-11-22 18:07:36 -0500323 if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_crap ();
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200324 return StructAtOffset<Type> (base, *this);
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400325 }
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400326
Behdad Esfahbod203ea582019-05-15 16:14:40 -0700327 template <typename Base,
328 hb_enable_if (hb_is_convertible (const Base, const void *))>
329 friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
330 template <typename Base,
Behdad Esfahboddfa5e422019-05-15 21:18:14 -0700331 hb_enable_if (hb_is_convertible (const Base, const void *))>
332 friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
333 template <typename Base,
Behdad Esfahbod203ea582019-05-15 16:14:40 -0700334 hb_enable_if (hb_is_convertible (Base, void *))>
335 friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
Behdad Esfahboddfa5e422019-05-15 21:18:14 -0700336 template <typename Base,
337 hb_enable_if (hb_is_convertible (Base, void *))>
338 friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
Behdad Esfahbod763ea422019-05-15 01:15:11 -0700339
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400340
Behdad Esfahbod88a41472019-05-02 14:22:31 -0700341 template <typename ...Ts>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +0330342 bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
343 const void *src_base, Ts&&... ds)
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700344 {
Behdad Esfahbodbfa02be2019-04-01 21:36:13 -0700345 *this = 0;
Behdad Esfahbod1834cf82019-05-31 14:39:32 -0700346 if (src.is_null ())
Behdad Esfahbode42b82c2019-04-02 17:21:54 -0700347 return false;
Behdad Esfahbodbfa02be2019-04-01 21:36:13 -0700348
Behdad Esfahbodaa2293a2019-04-02 17:42:10 -0700349 auto *s = c->serializer;
350
351 s->push ();
Behdad Esfahbode42b82c2019-04-02 17:21:54 -0700352
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600353 bool ret = c->dispatch (src_base+src, std::forward<Ts> (ds)...);
Behdad Esfahbode42b82c2019-04-02 17:21:54 -0700354
355 if (ret || !has_null)
ariza188a0a42020-03-07 11:02:36 -0800356 s->add_link (*this, s->pop_pack ());
Behdad Esfahbod7f73c972019-04-02 17:12:24 -0700357 else
Behdad Esfahbodaa2293a2019-04-02 17:42:10 -0700358 s->pop_discard ();
Behdad Esfahbode42b82c2019-04-02 17:21:54 -0700359
360 return ret;
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700361 }
362
Garret Rieger35458b62021-06-11 13:14:51 -0700363
364 template <typename ...Ts>
365 bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds)
366 {
367 *this = 0;
368
369 Type* obj = c->push<Type> ();
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600370 bool ret = obj->serialize (c, std::forward<Ts> (ds)...);
Garret Rieger35458b62021-06-11 13:14:51 -0700371
372 if (ret)
373 c->add_link (*this, c->pop_pack ());
374 else
375 c->pop_discard ();
376
377 return ret;
378 }
379
Behdad Esfahbod95426ea2019-05-07 15:56:51 -0700380 /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
ariza4ca8e0d2020-02-19 12:52:18 -0800381 /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
382 * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
383 */
384 template <typename ...Ts>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +0330385 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
386 const void *src_base, unsigned dst_bias,
ariza4ca8e0d2020-02-19 12:52:18 -0800387 hb_serialize_context_t::whence_t whence,
388 Ts&&... ds)
389 {
390 *this = 0;
391 if (src.is_null ())
392 return false;
393
394 c->push ();
395
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600396 bool ret = c->copy (src_base+src, std::forward<Ts> (ds)...);
ariza4ca8e0d2020-02-19 12:52:18 -0800397
ariza188a0a42020-03-07 11:02:36 -0800398 c->add_link (*this, c->pop_pack (), whence, dst_bias);
ariza4ca8e0d2020-02-19 12:52:18 -0800399
400 return ret;
401 }
402
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +0330403 bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
404 const void *src_base, unsigned dst_bias = 0)
ariza188a0a42020-03-07 11:02:36 -0800405 { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
Behdad Esfahbod273ed612019-05-02 14:04:51 -0700406
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330407 bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300408 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500409 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100410 if (unlikely (!c->check_struct (this))) return_trace (false);
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200411 if (unlikely (this->is_null ())) return_trace (true);
Behdad Esfahbod70110f62021-03-31 17:04:02 -0600412 if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200413 return_trace (true);
414 }
415
Behdad Esfahbod20f31342019-04-23 12:58:52 -0400416 template <typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700417 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200418 {
419 TRACE_SANITIZE (this);
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200420 return_trace (sanitize_shallow (c, base) &&
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200421 (this->is_null () ||
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600422 c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) ||
Behdad Esfahboda73bea62018-09-13 16:31:31 +0200423 neuter (c)));
Behdad Esfahbodb482e522018-09-13 16:29:49 +0200424 }
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400425
Behdad Esfahbodc9f14682010-05-04 14:38:08 -0400426 /* Set the offset to Null */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330427 bool neuter (hb_sanitize_context_t *c) const
Behdad Esfahbod29faebe2018-09-13 18:45:35 +0200428 {
429 if (!has_null) return false;
Behdad Esfahbod51f56352014-06-04 18:42:32 -0400430 return c->try_set (this, 0);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400431 }
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330432 DEFINE_SIZE_STATIC (sizeof (OffsetType));
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400433};
Behdad Esfahbod205d72a2019-01-17 18:10:38 -0500434/* Partial specializations. */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600435template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
436template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
437template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
438
439template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
440template <typename Type> using NNOffset16To = Offset16To<Type, false>;
441template <typename Type> using NNOffset24To = Offset24To<Type, false>;
442template <typename Type> using NNOffset32To = Offset32To<Type, false>;
Behdad Esfahbodf47a60a2018-11-22 17:53:29 -0500443
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -0400444
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400445/*
446 * Array Types
447 */
448
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100449template <typename Type>
450struct UnsizedArrayOf
451{
Behdad Esfahbod879faa22018-12-21 01:57:40 -0500452 typedef Type item_t;
Behdad Esfahbod70a52d62019-01-22 12:15:23 +0100453 static constexpr unsigned item_size = hb_static_size (Type);
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500454
Behdad Esfahbodb52c0e52019-04-11 11:20:10 -0400455 HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700456
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330457 const Type& operator [] (int i_) const
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800458 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500459 unsigned int i = (unsigned int) i_;
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800460 const Type *p = &arrayZ[i];
Behdad Esfahbod91c60802022-07-18 22:24:28 -0600461 if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600462 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800463 return *p;
464 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330465 Type& operator [] (int i_)
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800466 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500467 unsigned int i = (unsigned int) i_;
Behdad Esfahbod9714e112018-11-16 16:52:42 -0800468 Type *p = &arrayZ[i];
Behdad Esfahbod91c60802022-07-18 22:24:28 -0600469 if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600470 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod52f61cd2018-11-16 16:41:59 -0800471 return *p;
472 }
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100473
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330474 unsigned int get_size (unsigned int len) const
Behdad Esfahbod1cf075e2018-11-02 11:38:00 -0400475 { return len * Type::static_size; }
476
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330477 template <typename T> operator T * () { return arrayZ; }
478 template <typename T> operator const T * () const { return arrayZ; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330479 hb_array_t<Type> as_array (unsigned int len)
Behdad Esfahbode6043062018-11-24 01:24:48 -0500480 { return hb_array (arrayZ, len); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330481 hb_array_t<const Type> as_array (unsigned int len) const
Behdad Esfahbode6043062018-11-24 01:24:48 -0500482 { return hb_array (arrayZ, len); }
Behdad Esfahbod72462eb2018-11-02 11:46:24 -0400483
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500484 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330485 Type &lsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
Behdad Esfahbod52ae9862018-11-24 10:46:56 -0500486 { return *as_array (len).lsearch (x, &not_found); }
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500487 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330488 const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
Behdad Esfahbod52ae9862018-11-24 10:46:56 -0500489 { return *as_array (len).lsearch (x, &not_found); }
Ebrahim Byagowi08d57d92020-06-28 13:13:25 +0430490 template <typename T>
Behdad Esfahbod03cd9c52021-07-22 11:27:33 -0700491 bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr,
492 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
493 unsigned int to_store = (unsigned int) -1) const
494 { return as_array (len).lfind (x, i, not_found, to_store); }
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500495
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330496 void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
Behdad Esfahbod70d80c92018-11-24 01:59:50 -0500497 { as_array (len).qsort (start, end); }
498
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700499 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
500 {
501 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600502 if (unlikely (!c->extend (this, items_len))) return_trace (false);
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700503 return_trace (true);
504 }
505 template <typename Iterator,
Behdad Esfahboded972d52019-05-09 16:58:28 -0700506 hb_requires (hb_is_source_of (Iterator, Type))>
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700507 bool serialize (hb_serialize_context_t *c, Iterator items)
508 {
509 TRACE_SERIALIZE (this);
510 unsigned count = items.len ();
511 if (unlikely (!serialize (c, count))) return_trace (false);
512 /* TODO Umm. Just exhaust the iterator instead? Being extra
513 * cautious right now.. */
Behdad Esfahbod7166bd52019-05-08 14:24:57 -0700514 for (unsigned i = 0; i < count; i++, ++items)
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700515 arrayZ[i] = *items;
516 return_trace (true);
517 }
518
Behdad Esfahbod8a32c9e2019-05-02 16:20:18 -0700519 UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700520 {
521 TRACE_SERIALIZE (this);
Behdad Esfahbod8a32c9e2019-05-02 16:20:18 -0700522 auto *out = c->start_embed (this);
Behdad Esfahbode8b45c12019-05-08 16:37:38 -0700523 if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700524 return_trace (out);
525 }
526
Behdad Esfahbod20f31342019-04-23 12:58:52 -0400527 template <typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700528 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100529 {
530 TRACE_SANITIZE (this);
531 if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
Thomas Devoogdtc657c4e2022-05-10 10:00:06 +0200532 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100533 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600534 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330535 return_trace (false);
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100536 return_trace (true);
537 }
538
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330539 bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100540 {
541 TRACE_SANITIZE (this);
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200542 return_trace (c->check_array (arrayZ, count));
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100543 }
544
545 public:
Behdad Esfahbod0e294c42019-09-06 16:54:27 -0400546 Type arrayZ[HB_VAR_ARRAY];
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100547 public:
Behdad Esfahbodf47a60a2018-11-22 17:53:29 -0500548 DEFINE_SIZE_UNBOUNDED (0);
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100549};
550
551/* Unsized array of offset's */
Behdad Esfahbod87205ef2018-10-16 15:40:44 -0700552template <typename Type, typename OffsetType, bool has_null=true>
Behdad Esfahbod1fc6b692021-03-31 15:30:35 -0600553using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100554
555/* Unsized array of offsets relative to the beginning of the array itself. */
Behdad Esfahbod87205ef2018-10-16 15:40:44 -0700556template <typename Type, typename OffsetType, bool has_null=true>
Behdad Esfahbod5efe3602021-03-31 15:33:22 -0600557struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100558{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330559 const Type& operator [] (int i_) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100560 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500561 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500562 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
Behdad Esfahbod91c60802022-07-18 22:24:28 -0600563 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600564 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500565 return this+*p;
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100566 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330567 Type& operator [] (int i_)
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500568 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500569 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500570 const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
Behdad Esfahbod91c60802022-07-18 22:24:28 -0600571 if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600572 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -0500573 return this+*p;
574 }
575
Behdad Esfahbod20f31342019-04-23 12:58:52 -0400576 template <typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700577 bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100578 {
579 TRACE_SANITIZE (this);
Behdad Esfahbod1fc6b692021-03-31 15:30:35 -0600580 return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600581 ::sanitize (c, count, this, std::forward<Ts> (ds)...)));
Behdad Esfahbod6418ae42018-03-14 16:18:42 +0100582 }
583};
584
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500585/* An array with sorted elements. Supports binary searching. */
586template <typename Type>
587struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
588{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330589 hb_sorted_array_t<Type> as_array (unsigned int len)
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500590 { return hb_sorted_array (this->arrayZ, len); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330591 hb_sorted_array_t<const Type> as_array (unsigned int len) const
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500592 { return hb_sorted_array (this->arrayZ, len); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330593 operator hb_sorted_array_t<Type> () { return as_array (); }
594 operator hb_sorted_array_t<const Type> () const { return as_array (); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500595
596 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330597 Type &bsearch (unsigned int len, const T &x, Type &not_found = Crap (Type))
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500598 { return *as_array (len).bsearch (x, &not_found); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500599 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330600 const Type &bsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500601 { return *as_array (len).bsearch (x, &not_found); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500602 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330603 bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
Behdad Esfahbod03cd9c52021-07-22 11:27:33 -0700604 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
Ebrahim Byagowi7e3edfa2020-07-18 19:03:36 +0430605 unsigned int to_store = (unsigned int) -1) const
Behdad Esfahbodd77a0982018-11-24 10:06:13 -0500606 { return as_array (len).bfind (x, i, not_found, to_store); }
Behdad Esfahbod7c1600d2018-11-24 01:37:11 -0500607};
608
609
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400610/* An array with a number of elements. */
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600611template <typename Type, typename LenType>
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400612struct ArrayOf
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400613{
Behdad Esfahbod879faa22018-12-21 01:57:40 -0500614 typedef Type item_t;
Behdad Esfahbod70a52d62019-01-22 12:15:23 +0100615 static constexpr unsigned item_size = hb_static_size (Type);
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500616
Behdad Esfahbodb52c0e52019-04-11 11:20:10 -0400617 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700618
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330619 const Type& operator [] (int i_) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400620 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500621 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330622 if (unlikely (i >= len)) return Null (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600623 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700624 return arrayZ[i];
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400625 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330626 Type& operator [] (int i_)
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400627 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500628 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330629 if (unlikely (i >= len)) return Crap (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600630 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700631 return arrayZ[i];
Behdad Esfahbod9f2348d2012-08-29 21:08:59 -0400632 }
Behdad Esfahbod28b68cf2018-10-30 23:33:30 -0700633
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330634 unsigned int get_size () const
Behdad Esfahbode45d3f82010-05-06 19:33:31 -0400635 { return len.static_size + len * Type::static_size; }
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400636
Behdad Esfahbod3f36c892019-03-29 15:22:46 -0700637 explicit operator bool () const { return len; }
Behdad Esfahbod362d4e72019-01-08 13:41:30 -0800638
Behdad Esfahbod3ca809e2019-08-28 13:49:35 -0700639 void pop () { len--; }
640
Behdad Esfahbod362d4e72019-01-08 13:41:30 -0800641 hb_array_t< Type> as_array () { return hb_array (arrayZ, len); }
642 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
643
644 /* Iterator. */
Behdad Esfahboda4ea0d32019-01-09 00:32:11 -0800645 typedef hb_array_t<const Type> iter_t;
646 typedef hb_array_t< Type> writer_t;
647 iter_t iter () const { return as_array (); }
648 writer_t writer () { return as_array (); }
649 operator iter_t () const { return iter (); }
650 operator writer_t () { return writer (); }
Behdad Esfahbodc514f652018-11-23 16:04:56 -0500651
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330652 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430653 { return as_array ().sub_array (start_offset, count); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330654 hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430655 { return as_array ().sub_array (start_offset, count); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330656 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430657 { return as_array ().sub_array (start_offset, count); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330658 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430659 { return as_array ().sub_array (start_offset, count); }
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500660
Behdad Esfahbod7a2eda72021-03-29 17:32:29 -0600661 template <typename T>
662 Type &lsearch (const T &x, Type &not_found = Crap (Type))
663 { return *as_array ().lsearch (x, &not_found); }
664 template <typename T>
665 const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
666 { return *as_array ().lsearch (x, &not_found); }
667 template <typename T>
Behdad Esfahbod03cd9c52021-07-22 11:27:33 -0700668 bool lfind (const T &x, unsigned int *i = nullptr,
669 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
670 unsigned int to_store = (unsigned int) -1) const
671 { return as_array ().lfind (x, i, not_found, to_store); }
Behdad Esfahbod7a2eda72021-03-29 17:32:29 -0600672
673 void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
674 { as_array ().qsort (start, end); }
675
Behdad Esfahbod23976892021-03-29 17:34:23 -0600676 HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400677 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500678 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600679 if (unlikely (!c->extend_min (this))) return_trace (false);
Garret Riegerb14475d2021-03-18 10:51:26 -0700680 c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600681 if (unlikely (!c->extend (this))) return_trace (false);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100682 return_trace (true);
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400683 }
Behdad Esfahbod79870952019-01-09 01:02:38 -0800684 template <typename Iterator,
Behdad Esfahboded972d52019-05-09 16:58:28 -0700685 hb_requires (hb_is_source_of (Iterator, Type))>
Behdad Esfahbod23976892021-03-29 17:34:23 -0600686 HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400687 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500688 TRACE_SERIALIZE (this);
Behdad Esfahbod49161d42018-12-26 22:50:33 -0500689 unsigned count = items.len ();
690 if (unlikely (!serialize (c, count))) return_trace (false);
Behdad Esfahboddf138da2018-12-28 16:29:48 -0500691 /* TODO Umm. Just exhaust the iterator instead? Being extra
692 * cautious right now.. */
Behdad Esfahbod7166bd52019-05-08 14:24:57 -0700693 for (unsigned i = 0; i < count; i++, ++items)
Behdad Esfahbod4c38a9f2019-03-29 20:23:07 -0700694 arrayZ[i] = *items;
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100695 return_trace (true);
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400696 }
697
Behdad Esfahbod062cad52019-08-28 13:33:08 -0700698 Type* serialize_append (hb_serialize_context_t *c)
699 {
700 TRACE_SERIALIZE (this);
701 len++;
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600702 if (unlikely (!len || !c->extend (this)))
Behdad Esfahbod062cad52019-08-28 13:33:08 -0700703 {
704 len--;
705 return_trace (nullptr);
706 }
707 return_trace (&arrayZ[len - 1]);
708 }
709
Behdad Esfahbod8a32c9e2019-05-02 16:20:18 -0700710 ArrayOf* copy (hb_serialize_context_t *c) const
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700711 {
712 TRACE_SERIALIZE (this);
Behdad Esfahbod8a32c9e2019-05-02 16:20:18 -0700713 auto *out = c->start_embed (this);
Behdad Esfahbode8b45c12019-05-08 16:37:38 -0700714 if (unlikely (!c->extend_min (out))) return_trace (nullptr);
Garret Riegerb14475d2021-03-18 10:51:26 -0700715 c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
Behdad Esfahbode8b45c12019-05-08 16:37:38 -0700716 if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
Behdad Esfahbod998b0b62019-05-02 14:39:52 -0700717 return_trace (out);
718 }
719
Behdad Esfahbod20f31342019-04-23 12:58:52 -0400720 template <typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700721 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300722 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500723 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100724 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Thomas Devoogdtc657c4e2022-05-10 10:00:06 +0200725 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
Behdad Esfahbode6ab2c52009-08-04 10:23:01 -0400726 unsigned int count = len;
727 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600728 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330729 return_trace (false);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100730 return_trace (true);
Behdad Esfahbod42b778f2009-08-04 13:30:49 -0400731 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400732
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330733 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300734 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500735 TRACE_SANITIZE (this);
Behdad Esfahbod9507b052018-09-10 23:18:07 +0200736 return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
Behdad Esfahbod30fa2822010-05-04 14:28:18 -0400737 }
738
739 public:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200740 LenType len;
Behdad Esfahbod0e294c42019-09-06 16:54:27 -0400741 Type arrayZ[HB_VAR_ARRAY];
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400742 public:
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700743 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400744};
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600745template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
Behdad Esfahbod486555c2022-07-05 17:12:59 -0600746template <typename Type> using Array24Of = ArrayOf<Type, HBUINT24>;
Behdad Esfahbod5639e252021-03-31 16:04:43 -0600747template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
Behdad Esfahbod489faf82019-03-29 20:01:37 -0700748using PString = ArrayOf<HBUINT8, HBUINT8>;
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400749
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400750/* Array of Offset's */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -0600751template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>;
Behdad Esfahbod2520a822021-03-31 15:34:26 -0600752template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>;
Behdad Esfahbod2a54c9f2021-03-31 15:26:42 -0600753template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
Behdad Esfahbod92b5dd82009-08-04 10:41:32 -0400754
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400755/* Array of offsets relative to the beginning of the array itself. */
Behdad Esfahbodf6c2aae2022-07-11 13:06:48 -0600756template <typename Type, typename OffsetType>
757struct List16OfOffsetTo : ArrayOf<OffsetTo<Type, OffsetType>, HBUINT16>
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400758{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330759 const Type& operator [] (int i_) const
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400760 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500761 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330762 if (unlikely (i >= this->len)) return Null (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600763 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700764 return this+this->arrayZ[i];
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400765 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330766 const Type& operator [] (int i_)
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700767 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500768 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330769 if (unlikely (i >= this->len)) return Crap (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600770 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700771 return this+this->arrayZ[i];
772 }
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400773
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330774 bool subset (hb_subset_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700775 {
776 TRACE_SUBSET (this);
Behdad Esfahbodf6c2aae2022-07-11 13:06:48 -0600777 struct List16OfOffsetTo *out = c->serializer->embed (*this);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700778 if (unlikely (!out)) return_trace (false);
779 unsigned int count = this->len;
780 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod1834cf82019-05-31 14:39:32 -0700781 out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -0700782 return_trace (true);
783 }
784
Behdad Esfahbod20f31342019-04-23 12:58:52 -0400785 template <typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700786 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300787 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500788 TRACE_SANITIZE (this);
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -0600789 return_trace ((Array16Of<OffsetTo<Type, OffsetType>>::sanitize (c, this, std::forward<Ts> (ds)...)));
Behdad Esfahbod80e2aa22009-08-14 18:40:56 -0400790 }
791};
792
Behdad Esfahbodf6c2aae2022-07-11 13:06:48 -0600793template <typename Type>
794using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
795
Behdad Esfahbod51d9ba02014-06-27 15:27:15 -0400796/* An array starting at second element. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100797template <typename Type, typename LenType=HBUINT16>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400798struct HeadlessArrayOf
799{
Behdad Esfahbod70a52d62019-01-22 12:15:23 +0100800 static constexpr unsigned item_size = Type::static_size;
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500801
Behdad Esfahbodb52c0e52019-04-11 11:20:10 -0400802 HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700803
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330804 const Type& operator [] (int i_) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400805 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500806 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330807 if (unlikely (i >= lenP1 || !i)) return Null (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600808 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700809 return arrayZ[i-1];
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400810 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330811 Type& operator [] (int i_)
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700812 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500813 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330814 if (unlikely (i >= lenP1 || !i)) return Crap (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600815 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod5d801292018-05-24 11:33:15 -0700816 return arrayZ[i-1];
817 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330818 unsigned int get_size () const
Behdad Esfahboddc2c9aa2019-08-28 15:05:49 -0700819 { return lenP1.static_size + get_length () * Type::static_size; }
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400820
Behdad Esfahboddc2c9aa2019-08-28 15:05:49 -0700821 unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; }
Behdad Esfahbod42d887b2019-08-28 14:47:14 -0700822
Behdad Esfahboddc2c9aa2019-08-28 15:05:49 -0700823 hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); }
824 hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); }
Behdad Esfahbod42d887b2019-08-28 14:47:14 -0700825
826 /* Iterator. */
827 typedef hb_array_t<const Type> iter_t;
828 typedef hb_array_t< Type> writer_t;
829 iter_t iter () const { return as_array (); }
830 writer_t writer () { return as_array (); }
831 operator iter_t () const { return iter (); }
832 operator writer_t () { return writer (); }
833
834 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
Behdad Esfahboda930c682012-09-04 18:17:57 -0400835 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500836 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600837 if (unlikely (!c->extend_min (this))) return_trace (false);
Garret Riegerb14475d2021-03-18 10:51:26 -0700838 c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600839 if (unlikely (!c->extend (this))) return_trace (false);
Behdad Esfahbod42d887b2019-08-28 14:47:14 -0700840 return_trace (true);
841 }
842 template <typename Iterator,
843 hb_requires (hb_is_source_of (Iterator, Type))>
844 bool serialize (hb_serialize_context_t *c, Iterator items)
845 {
846 TRACE_SERIALIZE (this);
847 unsigned count = items.len ();
848 if (unlikely (!serialize (c, count))) return_trace (false);
849 /* TODO Umm. Just exhaust the iterator instead? Being extra
850 * cautious right now.. */
851 for (unsigned i = 0; i < count; i++, ++items)
852 arrayZ[i] = *items;
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100853 return_trace (true);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400854 }
855
Behdad Esfahbod4dcf6532019-05-10 22:23:24 -0700856 template <typename ...Ts>
857 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300858 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500859 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100860 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Thomas Devoogdtc657c4e2022-05-10 10:00:06 +0200861 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
Behdad Esfahboddc2c9aa2019-08-28 15:05:49 -0700862 unsigned int count = get_length ();
Behdad Esfahbod4dcf6532019-05-10 22:23:24 -0700863 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600864 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
Behdad Esfahbod4dcf6532019-05-10 22:23:24 -0700865 return_trace (false);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100866 return_trace (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400867 }
868
Behdad Esfahbod5f047112017-10-31 18:10:40 -0600869 private:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330870 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbod5f047112017-10-31 18:10:40 -0600871 {
872 TRACE_SANITIZE (this);
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +0200873 return_trace (lenP1.sanitize (c) &&
874 (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
Behdad Esfahbod5f047112017-10-31 18:10:40 -0600875 }
876
877 public:
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +0200878 LenType lenP1;
Behdad Esfahbod0e294c42019-09-06 16:54:27 -0400879 Type arrayZ[HB_VAR_ARRAY];
Behdad Esfahboded074222010-05-10 18:08:46 -0400880 public:
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700881 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
Behdad Esfahbod5f810362009-05-17 00:54:25 -0400882};
883
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200884/* An array storing length-1. */
885template <typename Type, typename LenType=HBUINT16>
886struct ArrayOfM1
887{
Behdad Esfahbodb52c0e52019-04-11 11:20:10 -0400888 HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1);
Behdad Esfahboda256a922018-10-29 11:25:35 -0700889
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330890 const Type& operator [] (int i_) const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200891 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500892 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330893 if (unlikely (i > lenM1)) return Null (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600894 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200895 return arrayZ[i];
896 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330897 Type& operator [] (int i_)
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200898 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -0500899 unsigned int i = (unsigned int) i_;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330900 if (unlikely (i > lenM1)) return Crap (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600901 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200902 return arrayZ[i];
903 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330904 unsigned int get_size () const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200905 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
906
Behdad Esfahbod20f31342019-04-23 12:58:52 -0400907 template <typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700908 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200909 {
910 TRACE_SANITIZE (this);
911 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Thomas Devoogdtc657c4e2022-05-10 10:00:06 +0200912 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200913 unsigned int count = lenM1 + 1;
914 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -0600915 if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330916 return_trace (false);
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200917 return_trace (true);
918 }
919
920 private:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330921 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200922 {
923 TRACE_SANITIZE (this);
924 return_trace (lenM1.sanitize (c) &&
925 (c->check_array (arrayZ, lenM1 + 1)));
926 }
927
928 public:
929 LenType lenM1;
Behdad Esfahbod0e294c42019-09-06 16:54:27 -0400930 Type arrayZ[HB_VAR_ARRAY];
Behdad Esfahbod3789c552018-09-13 20:30:04 +0200931 public:
932 DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
933};
934
Behdad Esfahbod92b1e022018-07-25 16:58:47 -0700935/* An array with sorted elements. Supports binary searching. */
Behdad Esfahbod4dba7492021-03-31 16:09:39 -0600936template <typename Type, typename LenType>
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400937struct SortedArrayOf : ArrayOf<Type, LenType>
Behdad Esfahbod40a47972014-05-08 18:21:04 -0400938{
Behdad Esfahbod362d4e72019-01-08 13:41:30 -0800939 hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); }
940 hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
941
942 /* Iterator. */
Behdad Esfahboda4ea0d32019-01-09 00:32:11 -0800943 typedef hb_sorted_array_t<const Type> iter_t;
944 typedef hb_sorted_array_t< Type> writer_t;
945 iter_t iter () const { return as_array (); }
946 writer_t writer () { return as_array (); }
947 operator iter_t () const { return iter (); }
948 operator writer_t () { return writer (); }
Behdad Esfahbode7003922018-11-24 01:31:00 -0500949
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800950 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430951 { return as_array ().sub_array (start_offset, count); }
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800952 hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430953 { return as_array ().sub_array (start_offset, count); }
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800954 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430955 { return as_array ().sub_array (start_offset, count); }
Behdad Esfahbod2f837a32019-01-08 13:05:01 -0800956 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
Ebrahim Byagowiaab8e082019-07-26 02:19:22 +0430957 { return as_array ().sub_array (start_offset, count); }
Behdad Esfahbod3246a8e2018-11-24 21:32:00 -0500958
Behdad Esfahbod82378092019-01-07 22:00:45 -0500959 bool serialize (hb_serialize_context_t *c, unsigned int items_len)
960 {
961 TRACE_SERIALIZE (this);
962 bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
963 return_trace (ret);
964 }
Behdad Esfahbod79870952019-01-09 01:02:38 -0800965 template <typename Iterator,
Behdad Esfahboded972d52019-05-09 16:58:28 -0700966 hb_requires (hb_is_sorted_source_of (Iterator, Type))>
Behdad Esfahbod79870952019-01-09 01:02:38 -0800967 bool serialize (hb_serialize_context_t *c, Iterator items)
Behdad Esfahbod82378092019-01-07 22:00:45 -0500968 {
969 TRACE_SERIALIZE (this);
970 bool ret = ArrayOf<Type, LenType>::serialize (c, items);
971 return_trace (ret);
972 }
973
Behdad Esfahbod30cb45b2018-11-24 00:35:31 -0500974 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330975 Type &bsearch (const T &x, Type &not_found = Crap (Type))
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500976 { return *as_array ().bsearch (x, &not_found); }
Behdad Esfahbod30cb45b2018-11-24 00:35:31 -0500977 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330978 const Type &bsearch (const T &x, const Type &not_found = Null (Type)) const
Behdad Esfahbod918b1ee2018-11-24 10:09:17 -0500979 { return *as_array ().bsearch (x, &not_found); }
Behdad Esfahbod30cb45b2018-11-24 00:35:31 -0500980 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330981 bool bfind (const T &x, unsigned int *i = nullptr,
Behdad Esfahbod03cd9c52021-07-22 11:27:33 -0700982 hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
Ebrahim Byagowi05584132019-10-01 13:49:55 +0330983 unsigned int to_store = (unsigned int) -1) const
Behdad Esfahbodd77a0982018-11-24 10:06:13 -0500984 { return as_array ().bfind (x, i, not_found, to_store); }
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -0400985};
986
Behdad Esfahbod4dba7492021-03-31 16:09:39 -0600987template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
Behdad Esfahbod486555c2022-07-05 17:12:59 -0600988template <typename Type> using SortedArray24Of = SortedArrayOf<Type, HBUINT24>;
Behdad Esfahbod4dba7492021-03-31 16:09:39 -0600989template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
990
Behdad Esfahbod456a68c2018-10-07 22:28:45 -0400991/*
992 * Binary-search arrays
993 */
994
Behdad Esfahbod4c3b19d2018-10-07 22:30:42 -0400995template <typename LenType=HBUINT16>
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600996struct BinSearchHeader
997{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330998 operator uint32_t () const { return len; }
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -0600999
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301000 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -06001001 {
1002 TRACE_SANITIZE (this);
1003 return_trace (c->check_struct (this));
1004 }
1005
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -07001006 BinSearchHeader& operator = (unsigned int v)
Behdad Esfahbodc479a592018-02-07 21:13:10 -06001007 {
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -07001008 len = v;
Behdad Esfahbodc479a592018-02-07 21:13:10 -06001009 assert (len == v);
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001010 entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -07001011 searchRange = 16 * (1u << entrySelector);
1012 rangeShift = v * 16 > searchRange
1013 ? 16 * v - searchRange
1014 : 0;
1015 return *this;
Behdad Esfahbodc479a592018-02-07 21:13:10 -06001016 }
1017
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -06001018 protected:
Behdad Esfahbod4c3b19d2018-10-07 22:30:42 -04001019 LenType len;
1020 LenType searchRange;
1021 LenType entrySelector;
1022 LenType rangeShift;
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -06001023
1024 public:
1025 DEFINE_SIZE_STATIC (8);
1026};
1027
Behdad Esfahbod4c3b19d2018-10-07 22:30:42 -04001028template <typename Type, typename LenType=HBUINT16>
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001029using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
Behdad Esfahbodb0e33da2017-10-31 20:05:37 -06001030
Behdad Esfahboda256a922018-10-29 11:25:35 -07001031
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001032struct VarSizedBinSearchHeader
1033{
1034
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301035 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001036 {
1037 TRACE_SANITIZE (this);
1038 return_trace (c->check_struct (this));
1039 }
1040
1041 HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
1042 HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
1043 HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
1044 * that is less than or equal to the value of nUnits. */
1045 HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
1046 * or equal to the value of nUnits. */
1047 HBUINT16 rangeShift; /* The value of unitSize times the difference of the
1048 * value of nUnits minus the largest power of 2 less
1049 * than or equal to the value of nUnits. */
1050 public:
1051 DEFINE_SIZE_STATIC (10);
1052};
1053
1054template <typename Type>
1055struct VarSizedBinSearchArrayOf
1056{
Behdad Esfahbod70a52d62019-01-22 12:15:23 +01001057 static constexpr unsigned item_size = Type::static_size;
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -05001058
Behdad Esfahbodb52c0e52019-04-11 11:20:10 -04001059 HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf);
Behdad Esfahboda256a922018-10-29 11:25:35 -07001060
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301061 bool last_is_terminator () const
Behdad Esfahbod3d309722018-11-24 23:12:28 -05001062 {
1063 if (unlikely (!header.nUnits)) return false;
1064
1065 /* Gah.
1066 *
1067 * "The number of termination values that need to be included is table-specific.
1068 * The value that indicates binary search termination is 0xFFFF." */
1069 const HBUINT16 *words = &StructAtOffset<HBUINT16> (&bytesZ, (header.nUnits - 1) * header.unitSize);
1070 unsigned int count = Type::TerminationWordCount;
1071 for (unsigned int i = 0; i < count; i++)
1072 if (words[i] != 0xFFFFu)
Ebrahim Byagowia0b4ac42019-08-24 17:57:14 +04301073 return false;
Behdad Esfahbod3d309722018-11-24 23:12:28 -05001074 return true;
1075 }
1076
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301077 const Type& operator [] (int i_) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001078 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -05001079 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -05001080 if (unlikely (i >= get_length ())) return Null (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -06001081 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001082 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
1083 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301084 Type& operator [] (int i_)
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001085 {
Behdad Esfahboddfad19a2018-11-30 19:57:12 -05001086 unsigned int i = (unsigned int) i_;
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -05001087 if (unlikely (i >= get_length ())) return Crap (Type);
Behdad Esfahbodf0707e22022-07-17 16:47:16 -06001088 _hb_compiler_memory_r_barrier ();
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001089 return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
1090 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301091 unsigned int get_length () const
1092 { return header.nUnits - last_is_terminator (); }
1093 unsigned int get_size () const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001094 { return header.static_size + header.nUnits * header.unitSize; }
1095
Behdad Esfahbod20f31342019-04-23 12:58:52 -04001096 template <typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07001097 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001098 {
1099 TRACE_SANITIZE (this);
1100 if (unlikely (!sanitize_shallow (c))) return_trace (false);
Thomas Devoogdtc657c4e2022-05-10 10:00:06 +02001101 if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
Behdad Esfahbod4202a3c2018-11-24 22:48:34 -05001102 unsigned int count = get_length ();
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001103 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06001104 if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...)))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301105 return_trace (false);
Ebrahim Byagowib8b00fb2018-11-08 18:53:14 +03301106 return_trace (true);
1107 }
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001108
1109 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301110 const Type *bsearch (const T &key) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001111 {
Behdad Esfahbodb1dc6762019-12-10 11:41:24 -06001112 unsigned pos;
1113 return hb_bsearch_impl (&pos,
1114 key,
1115 (const void *) bytesZ,
1116 get_length (),
1117 header.unitSize,
1118 _hb_cmp_method<T, Type>)
1119 ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize))
1120 : nullptr;
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001121 }
1122
1123 private:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301124 bool sanitize_shallow (hb_sanitize_context_t *c) const
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001125 {
1126 TRACE_SANITIZE (this);
1127 return_trace (header.sanitize (c) &&
Behdad Esfahbod2c824d32018-10-11 16:41:01 -04001128 Type::static_size <= header.unitSize &&
Behdad Esfahbode0144052018-11-12 14:23:31 -05001129 c->check_range (bytesZ.arrayZ,
1130 header.nUnits,
1131 header.unitSize));
Behdad Esfahbod456a68c2018-10-07 22:28:45 -04001132 }
1133
1134 protected:
1135 VarSizedBinSearchHeader header;
1136 UnsizedArrayOf<HBUINT8> bytesZ;
1137 public:
1138 DEFINE_SIZE_ARRAY (10, bytesZ);
1139};
1140
Behdad Esfahbodcc8a4ab2010-07-08 00:40:04 -04001141
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08001142} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001143
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001144
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07001145#endif /* HB_OPEN_TYPE_HH */