blob: 2bfbdd4f5ff008100ab301c02e9ba2749c3646d6 [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"
Behdad Esfahbod6e3ad652019-01-09 09:05:01 -080031#include "hb-algs.hh"
Behdad Esfahbod865deeb2018-12-21 17:35:58 -050032#include "hb-iter.hh"
33#include "hb-null.hh"
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050034
35
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050036template <typename Type>
37struct hb_sorted_array_t;
38
39template <typename Type>
Behdad Esfahbod849a0f12019-01-29 17:10:19 -080040struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050041{
Behdad Esfahboda4354d22018-12-16 23:57:27 -050042 /*
43 * Constructors.
44 */
Behdad Esfahbod474a1202018-12-21 18:46:51 -050045 hb_array_t () : arrayZ (nullptr), length (0) {}
Behdad Esfahbod20a73da2019-04-03 14:32:15 -070046 hb_array_t (const hb_array_t<Type> &o) : arrayZ (o.arrayZ), length (o.length) {}
Behdad Esfahbod177a8af2019-01-07 20:20:44 -050047 template <typename U = Type, hb_enable_if (hb_is_const (U))>
Behdad Esfahbod815cde92019-01-07 18:33:04 -050048 hb_array_t (const hb_array_t<hb_remove_const (Type)> &o) : arrayZ (o.arrayZ), length (o.length) {}
Behdad Esfahbodf02ebc82019-04-03 15:23:06 -070049
Behdad Esfahbod0363ce62019-01-27 01:03:56 +010050 hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
Behdad Esfahbod474a1202018-12-21 18:46:51 -050051 template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050052
Behdad Esfahbodf02ebc82019-04-03 15:23:06 -070053 template <typename U = Type, hb_enable_if (hb_is_const (U))>
54 hb_array_t& operator = (const hb_array_t<hb_remove_const (Type)> &o)
55 { arrayZ = o.arrayZ; length = o.length; return *this; }
56 hb_array_t& operator = (const hb_array_t &o)
57 { arrayZ = o.arrayZ; length = o.length; return *this; }
Behdad Esfahbod25786f42018-12-21 19:29:00 -050058 /*
59 * Iterator implementation.
60 */
Behdad Esfahbod636786e2019-01-08 23:48:35 -080061 typedef Type& __item_t__;
Behdad Esfahbod090fe562019-01-25 15:34:03 +010062 static constexpr bool is_random_access_iterator = true;
Behdad Esfahbod25786f42018-12-21 19:29:00 -050063 Type& __item_at__ (unsigned i) const
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050064 {
Behdad Esfahbod25786f42018-12-21 19:29:00 -050065 if (unlikely (i >= length)) return CrapOrNull (Type);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050066 return arrayZ[i];
67 }
Behdad Esfahbod25786f42018-12-21 19:29:00 -050068 void __forward__ (unsigned n)
69 {
70 if (unlikely (n > length))
71 n = length;
72 length -= n;
73 arrayZ += n;
74 }
75 void __rewind__ (unsigned n)
76 {
77 if (unlikely (n > length))
78 n = length;
79 length -= n;
80 }
81 unsigned __len__ () const { return length; }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050082
Behdad Esfahbod25786f42018-12-21 19:29:00 -050083 /* Extra operators.
84 */
Ebrahim Byagowie4120082018-12-17 21:31:01 +033085 Type * operator & () const { return arrayZ; }
Behdad Esfahbod474a1202018-12-21 18:46:51 -050086 operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033087 template <typename T> operator T * () const { return arrayZ; }
Behdad Esfahbod94e72cf2018-12-17 00:06:40 -050088
Behdad Esfahbod5b66b032019-04-02 19:27:02 -070089 bool operator == (const hb_array_t &o) const;
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -070090 uint32_t hash () const;
91
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 Esfahbod474a1202018-12-21 18:46:51 -050099 if (length != a.length)
100 return (int) a.length - (int) length;
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500101 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 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500113 unsigned int count = length;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500114 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 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500122 unsigned int count = length;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500123 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 Esfahbod89949ed2018-12-30 01:52:19 -0500131 if (likely (length))
132 ::qsort (arrayZ, length, this->item_size, cmp_);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500133 return hb_sorted_array_t<Type> (*this);
134 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330135 hb_sorted_array_t<Type> qsort ()
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500136 {
Behdad Esfahbod89949ed2018-12-30 01:52:19 -0500137 if (likely (length))
138 ::qsort (arrayZ, length, this->item_size, Type::cmp);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500139 return hb_sorted_array_t<Type> (*this);
140 }
141 void qsort (unsigned int start, unsigned int end)
142 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500143 end = MIN (end, length);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500144 assert (start <= end);
Behdad Esfahbod89949ed2018-12-30 01:52:19 -0500145 if (likely (start < end))
146 ::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500147 }
148
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500149 /*
150 * Other methods.
151 */
152
Behdad Esfahbod25786f42018-12-21 19:29:00 -0500153 unsigned int get_size () const { return length * this->item_size; }
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500154
155 hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
156 {
157 if (!start_offset && !seg_count)
158 return *this;
159
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500160 unsigned int count = length;
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500161 if (unlikely (start_offset > count))
162 count = 0;
163 else
164 count -= start_offset;
165 if (seg_count)
166 count = *seg_count = MIN (count, *seg_count);
167 return hb_array_t<Type> (arrayZ + start_offset, count);
168 }
169 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
170 { return sub_array (start_offset, &seg_count); }
171
172 /* Only call if you allocated the underlying array using malloc() or similar. */
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330173 void free ()
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500174 { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500175
176 template <typename hb_sanitize_context_t>
177 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500178 { return c->check_array (arrayZ, length); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500179
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500180 /*
181 * Members
182 */
183
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500184 public:
185 Type *arrayZ;
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500186 unsigned int length;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500187};
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500188template <typename T> inline hb_array_t<T>
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500189hb_array (T *array, unsigned int length)
190{ return hb_array_t<T> (array, length); }
191template <typename T, unsigned int length_> inline hb_array_t<T>
192hb_array (T (&array_)[length_])
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500193{ return hb_array_t<T> (array_); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500194
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500195enum hb_bfind_not_found_t
196{
197 HB_BFIND_NOT_FOUND_DONT_STORE,
198 HB_BFIND_NOT_FOUND_STORE,
199 HB_BFIND_NOT_FOUND_STORE_CLOSEST,
200};
201
202template <typename Type>
Behdad Esfahbod25786f42018-12-21 19:29:00 -0500203struct hb_sorted_array_t :
Behdad Esfahbodb5d6fe12019-01-02 16:20:40 -0500204 hb_iter_t<hb_sorted_array_t<Type>, Type&>,
Behdad Esfahbod570473a2018-12-27 13:29:51 -0500205 hb_array_t<Type>
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500206{
Behdad Esfahbodb5d6fe12019-01-02 16:20:40 -0500207 typedef hb_iter_t<hb_sorted_array_t<Type>, Type&> iter_base_t;
Behdad Esfahbod570473a2018-12-27 13:29:51 -0500208 HB_ITER_USING (iter_base_t);
Behdad Esfahbod090fe562019-01-25 15:34:03 +0100209 static constexpr bool is_random_access_iterator = true;
210 static constexpr bool is_sorted_iterator = true;
Behdad Esfahbod570473a2018-12-27 13:29:51 -0500211
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330212 hb_sorted_array_t () : hb_array_t<Type> () {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500213 hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
Behdad Esfahbod177a8af2019-01-07 20:20:44 -0500214 template <typename U = Type, hb_enable_if (hb_is_const (U))>
Behdad Esfahbod815cde92019-01-07 18:33:04 -0500215 hb_sorted_array_t (const hb_sorted_array_t<hb_remove_const (Type)> &o) : hb_array_t<Type> (o) {}
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500216 hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
217 template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500218
219 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
220 { return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
221 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
222 { return sub_array (start_offset, &seg_count); }
223
224 template <typename T>
225 Type *bsearch (const T &x, Type *not_found = nullptr)
226 {
227 unsigned int i;
228 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
229 }
230 template <typename T>
231 const Type *bsearch (const T &x, const Type *not_found = nullptr) const
232 {
233 unsigned int i;
234 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
235 }
236 template <typename T>
237 bool bfind (const T &x, unsigned int *i = nullptr,
238 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
239 unsigned int to_store = (unsigned int) -1) const
240 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500241 int min = 0, max = (int) this->length - 1;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500242 const Type *array = this->arrayZ;
243 while (min <= max)
244 {
245 int mid = ((unsigned int) min + (unsigned int) max) / 2;
246 int c = array[mid].cmp (x);
247 if (c < 0)
248 max = mid - 1;
249 else if (c > 0)
250 min = mid + 1;
251 else
252 {
253 if (i)
254 *i = mid;
255 return true;
256 }
257 }
258 if (i)
259 {
260 switch (not_found)
261 {
262 case HB_BFIND_NOT_FOUND_DONT_STORE:
263 break;
264
265 case HB_BFIND_NOT_FOUND_STORE:
266 *i = to_store;
267 break;
268
269 case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500270 if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500271 max++;
272 *i = max;
273 break;
274 }
275 }
276 return false;
277 }
278};
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500279template <typename T> inline hb_sorted_array_t<T>
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500280hb_sorted_array (T *array, unsigned int length)
281{ return hb_sorted_array_t<T> (array, length); }
282template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
283hb_sorted_array (T (&array_)[length_])
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500284{ return hb_sorted_array_t<T> (array_); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500285
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700286template <typename T>
Behdad Esfahbod5b66b032019-04-02 19:27:02 -0700287bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
288{
289 return length == o.length &&
290 + hb_zip (*this, o)
291 | hb_map ([] (hb_pair_t<T&, T&> &&_) -> bool { return _.first == _.second; })
292 | hb_all
293 ;
294}
295template <typename T>
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700296uint32_t hb_array_t<T>::hash () const
297{
Behdad Esfahbodd0da5472019-04-02 18:22:39 -0700298 return
Behdad Esfahbod42ab32c2019-04-02 18:41:33 -0700299 + hb_iter (*this)
Behdad Esfahbodd0da5472019-04-02 18:22:39 -0700300 | hb_map (hb_hash)
301 | hb_reduce ([] (uint32_t a, uint32_t b) -> uint32_t { return a * 31 + b; }, 0)
302 ;
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700303}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500304
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500305typedef hb_array_t<const char> hb_bytes_t;
Behdad Esfahbod3d9d7dc2018-12-18 22:11:23 -0500306typedef hb_array_t<const unsigned char> hb_ubytes_t;
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500307
Behdad Esfahbod5b66b032019-04-02 19:27:02 -0700308/* TODO Specialize opeator==/hash() for hb_bytes_t and hb_ubytes_t. */
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700309//template <>
310//uint32_t hb_array_t<const char>::hash () const { return 0; }
Behdad Esfahbod92680362018-12-16 23:38:51 -0500311
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500312#endif /* HB_ARRAY_HH */