blob: 3cce512cdcf4f5c9cc0eab657edf34af619806dc [file] [log] [blame]
Behdad Esfahbod5a552f72018-12-16 20:07:44 -05001/*
2 * Copyright © 2018 Google, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
27#ifndef HB_ARRAY_HH
28#define HB_ARRAY_HH
29
30#include "hb.hh"
31
32
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050033template <typename Type>
34struct hb_sorted_array_t;
35
36template <typename Type>
37struct hb_array_t
38{
Behdad Esfahbod879faa22018-12-21 01:57:40 -050039 typedef Type item_t;
Behdad Esfahbod3656f562018-12-16 20:35:11 -050040 enum { item_size = hb_static_size (Type) };
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050041
Behdad Esfahboda4354d22018-12-16 23:57:27 -050042 /*
43 * Constructors.
44 */
Ebrahim Byagowie4120082018-12-17 21:31:01 +033045 hb_array_t () : arrayZ (nullptr), len (0) {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050046 hb_array_t (Type *array_, unsigned int len_) : arrayZ (array_), len (len_) {}
Behdad Esfahbod68d4a5e2018-12-17 00:02:42 -050047 template <unsigned int len_> hb_array_t (Type (&array_)[len_]) : arrayZ (array_), len (len_) {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050048
Behdad Esfahboda4354d22018-12-16 23:57:27 -050049 /*
50 * Operators.
51 */
52
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050053 Type& operator [] (int i_) const
54 {
55 unsigned int i = (unsigned int) i_;
Behdad Esfahbod6cd60c22018-12-17 00:09:06 -050056 if (unlikely (i >= len)) return CrapOrNull(Type);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050057 return arrayZ[i];
58 }
59
Ebrahim Byagowie4120082018-12-17 21:31:01 +033060 explicit_operator bool () const { return len; }
61 Type * operator & () const { return arrayZ; }
62 Type & operator * () { return (this->operator [])[0]; }
63 operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, len); }
64 template <typename T> operator T * () const { return arrayZ; }
Behdad Esfahbod94e72cf2018-12-17 00:06:40 -050065
Behdad Esfahbodf85f6e82018-12-16 23:45:07 -050066 hb_array_t<Type> & operator += (unsigned int count)
67 {
68 if (unlikely (count > len))
69 count = len;
70 len -= count;
71 arrayZ += count;
72 return *this;
73 }
Behdad Esfahbod470369a2018-12-17 00:20:19 -050074 hb_array_t<Type> & operator -= (unsigned int count)
75 {
76 if (unlikely (count > len))
77 count = len;
78 len -= count;
79 return *this;
80 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033081 hb_array_t<Type> & operator ++ () { *this += 1; }
82 hb_array_t<Type> & operator -- () { *this -= 1; }
Behdad Esfahbod470369a2018-12-17 00:20:19 -050083 hb_array_t<Type> operator + (unsigned int count)
84 { hb_array_t<Type> copy (*this); *this += count; return copy; }
85 hb_array_t<Type> operator - (unsigned int count)
86 { hb_array_t<Type> copy (*this); *this -= count; return copy; }
87 hb_array_t<Type> operator ++ (int)
88 { hb_array_t<Type> copy (*this); ++*this; return copy; }
89 hb_array_t<Type> operator -- (int)
90 { hb_array_t<Type> copy (*this); --*this; return copy; }
Behdad Esfahbodf85f6e82018-12-16 23:45:07 -050091
Behdad Esfahboda4354d22018-12-16 23:57:27 -050092 /*
93 * Compare, Sort, and Search.
94 */
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050095
Behdad Esfahboda4354d22018-12-16 23:57:27 -050096 /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
97 int cmp (const hb_array_t<Type> &a) const
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050098 {
Behdad Esfahboda4354d22018-12-16 23:57:27 -050099 if (len != a.len)
100 return (int) a.len - (int) len;
101 return hb_memcmp (a.arrayZ, arrayZ, get_size ());
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500102 }
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500103 static int cmp (const void *pa, const void *pb)
104 {
105 hb_array_t<Type> *a = (hb_array_t<Type> *) pa;
106 hb_array_t<Type> *b = (hb_array_t<Type> *) pb;
107 return b->cmp (*a);
108 }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500109
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500110 template <typename T>
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500111 Type *lsearch (const T &x, Type *not_found = nullptr)
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500112 {
113 unsigned int count = len;
114 for (unsigned int i = 0; i < count; i++)
115 if (!this->arrayZ[i].cmp (x))
116 return &this->arrayZ[i];
117 return not_found;
118 }
119 template <typename T>
120 const Type *lsearch (const T &x, const Type *not_found = nullptr) const
121 {
122 unsigned int count = len;
123 for (unsigned int i = 0; i < count; i++)
124 if (!this->arrayZ[i].cmp (x))
125 return &this->arrayZ[i];
126 return not_found;
127 }
128
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500129 hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500130 {
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500131 ::qsort (arrayZ, len, item_size, cmp_);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500132 return hb_sorted_array_t<Type> (*this);
133 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330134 hb_sorted_array_t<Type> qsort ()
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500135 {
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500136 ::qsort (arrayZ, len, item_size, Type::cmp);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500137 return hb_sorted_array_t<Type> (*this);
138 }
139 void qsort (unsigned int start, unsigned int end)
140 {
141 end = MIN (end, len);
142 assert (start <= end);
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500143 ::qsort (arrayZ + start, end - start, item_size, Type::cmp);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500144 }
145
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500146 /*
147 * Other methods.
148 */
149
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330150 unsigned int get_size () const { return len * item_size; }
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500151
152 hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
153 {
154 if (!start_offset && !seg_count)
155 return *this;
156
157 unsigned int count = len;
158 if (unlikely (start_offset > count))
159 count = 0;
160 else
161 count -= start_offset;
162 if (seg_count)
163 count = *seg_count = MIN (count, *seg_count);
164 return hb_array_t<Type> (arrayZ + start_offset, count);
165 }
166 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
167 { return sub_array (start_offset, &seg_count); }
168
169 /* Only call if you allocated the underlying array using malloc() or similar. */
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330170 void free ()
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500171 { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
172
173 template <typename hb_sanitize_context_t>
174 bool sanitize (hb_sanitize_context_t *c) const
175 { return c->check_array (arrayZ, len); }
176
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500177 /*
178 * Members
179 */
180
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500181 public:
182 Type *arrayZ;
183 unsigned int len;
184};
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500185template <typename T> inline hb_array_t<T>
186hb_array (T *array, unsigned int len)
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500187{ return hb_array_t<T> (array, len); }
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500188template <typename T, unsigned int len_> inline hb_array_t<T>
189hb_array (T (&array_)[len_])
190{ return hb_array_t<T> (array_); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500191
192
193enum hb_bfind_not_found_t
194{
195 HB_BFIND_NOT_FOUND_DONT_STORE,
196 HB_BFIND_NOT_FOUND_STORE,
197 HB_BFIND_NOT_FOUND_STORE_CLOSEST,
198};
199
200template <typename Type>
201struct hb_sorted_array_t : hb_array_t<Type>
202{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330203 hb_sorted_array_t () : hb_array_t<Type> () {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500204 hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
205 hb_sorted_array_t (Type *array_, unsigned int len_) : hb_array_t<Type> (array_, len_) {}
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500206 template <unsigned int len_> hb_sorted_array_t (Type (&array_)[len_]) : hb_array_t<Type> (array_) {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500207
208 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
209 { return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
210 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
211 { return sub_array (start_offset, &seg_count); }
212
213 template <typename T>
214 Type *bsearch (const T &x, Type *not_found = nullptr)
215 {
216 unsigned int i;
217 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
218 }
219 template <typename T>
220 const Type *bsearch (const T &x, const Type *not_found = nullptr) const
221 {
222 unsigned int i;
223 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
224 }
225 template <typename T>
226 bool bfind (const T &x, unsigned int *i = nullptr,
227 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
228 unsigned int to_store = (unsigned int) -1) const
229 {
230 int min = 0, max = (int) this->len - 1;
231 const Type *array = this->arrayZ;
232 while (min <= max)
233 {
234 int mid = ((unsigned int) min + (unsigned int) max) / 2;
235 int c = array[mid].cmp (x);
236 if (c < 0)
237 max = mid - 1;
238 else if (c > 0)
239 min = mid + 1;
240 else
241 {
242 if (i)
243 *i = mid;
244 return true;
245 }
246 }
247 if (i)
248 {
249 switch (not_found)
250 {
251 case HB_BFIND_NOT_FOUND_DONT_STORE:
252 break;
253
254 case HB_BFIND_NOT_FOUND_STORE:
255 *i = to_store;
256 break;
257
258 case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
259 if (max < 0 || (max < (int) this->len && array[max].cmp (x) > 0))
260 max++;
261 *i = max;
262 break;
263 }
264 }
265 return false;
266 }
267};
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500268template <typename T> inline hb_sorted_array_t<T>
269hb_sorted_array (T *array, unsigned int len)
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500270{ return hb_sorted_array_t<T> (array, len); }
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500271template <typename T, unsigned int len_> inline hb_sorted_array_t<T>
272hb_sorted_array (T (&array_)[len_])
273{ return hb_sorted_array_t<T> (array_); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500274
275
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500276typedef hb_array_t<const char> hb_bytes_t;
Behdad Esfahbod3d9d7dc2018-12-18 22:11:23 -0500277typedef hb_array_t<const unsigned char> hb_ubytes_t;
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500278
Behdad Esfahbod92680362018-12-16 23:38:51 -0500279
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500280#endif /* HB_ARRAY_HH */