blob: 20d3eb7011509ef8a05618be0c0584e95d9f397a [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 */
David Corbettb854d4f2019-05-10 22:51:49 -040045 hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
46 hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
Behdad Esfahbod322627a2019-05-09 16:08:10 -070047 template <unsigned int length_>
David Corbettb854d4f2019-05-10 22:51:49 -040048 hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050049
Behdad Esfahbod91d958a2019-04-18 10:04:10 -040050 template <typename U,
Behdad Esfahbod726002a2019-05-09 14:53:02 -070051 hb_enable_if (hb_is_cr_convertible(U, Type))>
Behdad Esfahbod91d958a2019-04-18 10:04:10 -040052 hb_array_t (const hb_array_t<U> &o) :
Behdad Esfahboda06edf12019-08-29 15:21:18 -070053 hb_iter_with_fallback_t<hb_array_t, Type&> (),
David Corbettb854d4f2019-05-10 22:51:49 -040054 arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
Behdad Esfahbod91d958a2019-04-18 10:04:10 -040055 template <typename U,
Behdad Esfahbod726002a2019-05-09 14:53:02 -070056 hb_enable_if (hb_is_cr_convertible(U, Type))>
Behdad Esfahbod91d958a2019-04-18 10:04:10 -040057 hb_array_t& operator = (const hb_array_t<U> &o)
David Corbettb854d4f2019-05-10 22:51:49 -040058 { arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
Behdad Esfahbod91d958a2019-04-18 10:04:10 -040059
Behdad Esfahbod25786f42018-12-21 19:29:00 -050060 /*
61 * Iterator implementation.
62 */
Behdad Esfahbod636786e2019-01-08 23:48:35 -080063 typedef Type& __item_t__;
Behdad Esfahbod090fe562019-01-25 15:34:03 +010064 static constexpr bool is_random_access_iterator = true;
Behdad Esfahbod25786f42018-12-21 19:29:00 -050065 Type& __item_at__ (unsigned i) const
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050066 {
Behdad Esfahbod25786f42018-12-21 19:29:00 -050067 if (unlikely (i >= length)) return CrapOrNull (Type);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050068 return arrayZ[i];
69 }
Behdad Esfahbod25786f42018-12-21 19:29:00 -050070 void __forward__ (unsigned n)
71 {
72 if (unlikely (n > length))
73 n = length;
74 length -= n;
David Corbettb854d4f2019-05-10 22:51:49 -040075 backwards_length += n;
Behdad Esfahbod25786f42018-12-21 19:29:00 -050076 arrayZ += n;
77 }
78 void __rewind__ (unsigned n)
79 {
David Corbettb854d4f2019-05-10 22:51:49 -040080 if (unlikely (n > backwards_length))
81 n = backwards_length;
82 length += n;
83 backwards_length -= n;
84 arrayZ -= n;
Behdad Esfahbod25786f42018-12-21 19:29:00 -050085 }
86 unsigned __len__ () const { return length; }
Behdad Esfahbodd822e0a2019-05-15 16:30:08 -070087 /* Ouch. The operator== compares the contents of the array. For range-based for loops,
88 * it's best if we can just compare arrayZ, though comparing contents is still fast,
89 * but also would require that Type has operator==. As such, we optimize this operator
90 * for range-based for loop and just compare arrayZ. No need to compare length, as we
91 * assume we're only compared to .end(). */
Behdad Esfahbod4c2fd052019-05-06 19:57:15 -070092 bool operator != (const hb_array_t& o) const
Behdad Esfahbodd822e0a2019-05-15 16:30:08 -070093 { return arrayZ != o.arrayZ; }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -050094
Behdad Esfahbod25786f42018-12-21 19:29:00 -050095 /* Extra operators.
96 */
Ebrahim Byagowie4120082018-12-17 21:31:01 +033097 Type * operator & () const { return arrayZ; }
Behdad Esfahbod474a1202018-12-21 18:46:51 -050098 operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033099 template <typename T> operator T * () const { return arrayZ; }
Behdad Esfahbod94e72cf2018-12-17 00:06:40 -0500100
Behdad Esfahbodcaa20e42019-04-12 17:59:18 -0400101 HB_INTERNAL bool operator == (const hb_array_t &o) const;
102 HB_INTERNAL uint32_t hash () const;
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700103
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500104 /*
105 * Compare, Sort, and Search.
106 */
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500107
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500108 /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700109 int cmp (const hb_array_t &a) const
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500110 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500111 if (length != a.length)
112 return (int) a.length - (int) length;
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500113 return hb_memcmp (a.arrayZ, arrayZ, get_size ());
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500114 }
Behdad Esfahbod95df00a2019-04-12 17:50:03 -0400115 HB_INTERNAL static int cmp (const void *pa, const void *pb)
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500116 {
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700117 hb_array_t *a = (hb_array_t *) pa;
118 hb_array_t *b = (hb_array_t *) pb;
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500119 return b->cmp (*a);
120 }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500121
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500122 template <typename T>
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500123 Type *lsearch (const T &x, Type *not_found = nullptr)
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500124 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500125 unsigned int count = length;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500126 for (unsigned int i = 0; i < count; i++)
127 if (!this->arrayZ[i].cmp (x))
128 return &this->arrayZ[i];
129 return not_found;
130 }
131 template <typename T>
132 const Type *lsearch (const T &x, const Type *not_found = nullptr) const
133 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500134 unsigned int count = length;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500135 for (unsigned int i = 0; i < count; i++)
136 if (!this->arrayZ[i].cmp (x))
137 return &this->arrayZ[i];
138 return not_found;
139 }
140
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500141 hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500142 {
Behdad Esfahbod89949ed2018-12-30 01:52:19 -0500143 if (likely (length))
Behdad Esfahbodc72589f2019-08-29 15:45:21 -0700144 hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500145 return hb_sorted_array_t<Type> (*this);
146 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330147 hb_sorted_array_t<Type> qsort ()
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500148 {
Behdad Esfahbod89949ed2018-12-30 01:52:19 -0500149 if (likely (length))
Behdad Esfahbodc72589f2019-08-29 15:45:21 -0700150 hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500151 return hb_sorted_array_t<Type> (*this);
152 }
153 void qsort (unsigned int start, unsigned int end)
154 {
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700155 end = hb_min (end, length);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500156 assert (start <= end);
Behdad Esfahbod89949ed2018-12-30 01:52:19 -0500157 if (likely (start < end))
Behdad Esfahbodc72589f2019-08-29 15:45:21 -0700158 hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500159 }
160
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500161 /*
162 * Other methods.
163 */
164
Behdad Esfahbodc72589f2019-08-29 15:45:21 -0700165 unsigned int get_size () const { return length * this->get_item_size (); }
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500166
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700167 hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500168 {
169 if (!start_offset && !seg_count)
170 return *this;
171
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500172 unsigned int count = length;
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500173 if (unlikely (start_offset > count))
174 count = 0;
175 else
176 count -= start_offset;
177 if (seg_count)
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700178 count = *seg_count = hb_min (count, *seg_count);
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700179 return hb_array_t (arrayZ + start_offset, count);
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500180 }
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700181 hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500182 { return sub_array (start_offset, &seg_count); }
183
Behdad Esfahbodd58e2482019-08-29 15:23:48 -0700184 hb_array_t truncate (unsigned length) const { return sub_array (0, length); }
185
Ebrahim Byagowidce42ce2019-08-27 14:32:05 +0430186 template <typename T,
187 unsigned P = sizeof (Type),
188 hb_enable_if (P == 1)>
189 const T *as () const
190 { return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
191
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500192 /* Only call if you allocated the underlying array using malloc() or similar. */
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330193 void free ()
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500194 { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500195
Behdad Esfahbode8b45c12019-05-08 16:37:38 -0700196 template <typename hb_serialize_context_t>
197 hb_array_t copy (hb_serialize_context_t *c) const
198 {
199 TRACE_SERIALIZE (this);
Behdad Esfahbod34764452019-05-08 21:14:01 -0700200 auto* out = c->start_embed (arrayZ);
Behdad Esfahbode8b45c12019-05-08 16:37:38 -0700201 if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
202 for (unsigned i = 0; i < length; i++)
203 out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
204 return_trace (hb_array_t (out, length));
205 }
206
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500207 template <typename hb_sanitize_context_t>
208 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500209 { return c->check_array (arrayZ, length); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500210
Behdad Esfahboda4354d22018-12-16 23:57:27 -0500211 /*
212 * Members
213 */
214
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500215 public:
216 Type *arrayZ;
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500217 unsigned int length;
David Corbettb854d4f2019-05-10 22:51:49 -0400218 unsigned int backwards_length;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500219};
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500220template <typename T> inline hb_array_t<T>
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500221hb_array (T *array, unsigned int length)
222{ return hb_array_t<T> (array, length); }
223template <typename T, unsigned int length_> inline hb_array_t<T>
224hb_array (T (&array_)[length_])
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500225{ return hb_array_t<T> (array_); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500226
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500227enum hb_bfind_not_found_t
228{
229 HB_BFIND_NOT_FOUND_DONT_STORE,
230 HB_BFIND_NOT_FOUND_STORE,
231 HB_BFIND_NOT_FOUND_STORE_CLOSEST,
232};
233
234template <typename Type>
Behdad Esfahbod25786f42018-12-21 19:29:00 -0500235struct hb_sorted_array_t :
Behdad Esfahbodb5d6fe12019-01-02 16:20:40 -0500236 hb_iter_t<hb_sorted_array_t<Type>, Type&>,
Behdad Esfahbod570473a2018-12-27 13:29:51 -0500237 hb_array_t<Type>
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500238{
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700239 typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
Behdad Esfahbod570473a2018-12-27 13:29:51 -0500240 HB_ITER_USING (iter_base_t);
Behdad Esfahbod090fe562019-01-25 15:34:03 +0100241 static constexpr bool is_random_access_iterator = true;
Behdad Esfahbod889dc1e2019-05-14 22:28:07 -0700242 static constexpr bool is_sorted_iterator = true;
Behdad Esfahbod570473a2018-12-27 13:29:51 -0500243
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330244 hb_sorted_array_t () : hb_array_t<Type> () {}
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500245 hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
Behdad Esfahbod322627a2019-05-09 16:08:10 -0700246 template <unsigned int length_>
247 hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500248
Behdad Esfahbodc51f15d2019-04-26 13:03:41 -0700249 template <typename U,
Behdad Esfahbod726002a2019-05-09 14:53:02 -0700250 hb_enable_if (hb_is_cr_convertible(U, Type))>
Behdad Esfahbodc51f15d2019-04-26 13:03:41 -0700251 hb_sorted_array_t (const hb_array_t<U> &o) :
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700252 hb_iter_t<hb_sorted_array_t, Type&> (),
Behdad Esfahbodc51f15d2019-04-26 13:03:41 -0700253 hb_array_t<Type> (o) {}
254 template <typename U,
Behdad Esfahbod726002a2019-05-09 14:53:02 -0700255 hb_enable_if (hb_is_cr_convertible(U, Type))>
Behdad Esfahbodc51f15d2019-04-26 13:03:41 -0700256 hb_sorted_array_t& operator = (const hb_array_t<U> &o)
257 { hb_array_t<Type> (*this) = o; return *this; }
258
Behdad Esfahbod4c2fd052019-05-06 19:57:15 -0700259 /* Iterator implementation. */
260 bool operator != (const hb_sorted_array_t& o) const
261 { return this->arrayZ != o.arrayZ || this->length != o.length; }
262
Behdad Esfahboda06edf12019-08-29 15:21:18 -0700263 hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
264 { return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
265 hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500266 { return sub_array (start_offset, &seg_count); }
267
Behdad Esfahbodd58e2482019-08-29 15:23:48 -0700268 hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); }
269
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500270 template <typename T>
271 Type *bsearch (const T &x, Type *not_found = nullptr)
272 {
273 unsigned int i;
274 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
275 }
276 template <typename T>
277 const Type *bsearch (const T &x, const Type *not_found = nullptr) const
278 {
279 unsigned int i;
280 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
281 }
282 template <typename T>
283 bool bfind (const T &x, unsigned int *i = nullptr,
Ebrahim Byagowi05584132019-10-01 13:49:55 +0330284 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
285 unsigned int to_store = (unsigned int) -1) const
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500286 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500287 int min = 0, max = (int) this->length - 1;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500288 const Type *array = this->arrayZ;
289 while (min <= max)
290 {
291 int mid = ((unsigned int) min + (unsigned int) max) / 2;
292 int c = array[mid].cmp (x);
293 if (c < 0)
Ebrahim Byagowia0b4ac42019-08-24 17:57:14 +0430294 max = mid - 1;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500295 else if (c > 0)
Ebrahim Byagowia0b4ac42019-08-24 17:57:14 +0430296 min = mid + 1;
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500297 else
298 {
299 if (i)
300 *i = mid;
301 return true;
302 }
303 }
304 if (i)
305 {
306 switch (not_found)
307 {
308 case HB_BFIND_NOT_FOUND_DONT_STORE:
309 break;
310
311 case HB_BFIND_NOT_FOUND_STORE:
312 *i = to_store;
313 break;
314
315 case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500316 if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500317 max++;
318 *i = max;
319 break;
320 }
321 }
322 return false;
323 }
324};
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500325template <typename T> inline hb_sorted_array_t<T>
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500326hb_sorted_array (T *array, unsigned int length)
327{ return hb_sorted_array_t<T> (array, length); }
328template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
329hb_sorted_array (T (&array_)[length_])
Behdad Esfahbod7b4eea82018-12-21 16:02:16 -0500330{ return hb_sorted_array_t<T> (array_); }
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500331
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700332template <typename T>
Behdad Esfahbod5b66b032019-04-02 19:27:02 -0700333bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
334{
335 return length == o.length &&
336 + hb_zip (*this, o)
Behdad Esfahbodd0df9962019-05-15 00:32:41 -0700337 | hb_map ([] (hb_pair_t<T&, T&> &&_) { return _.first == _.second; })
Behdad Esfahbod5b66b032019-04-02 19:27:02 -0700338 | hb_all
339 ;
340}
341template <typename T>
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700342uint32_t hb_array_t<T>::hash () const
343{
Behdad Esfahbodd0da5472019-04-02 18:22:39 -0700344 return
Behdad Esfahbod42ab32c2019-04-02 18:41:33 -0700345 + hb_iter (*this)
Behdad Esfahbodd0da5472019-04-02 18:22:39 -0700346 | hb_map (hb_hash)
Behdad Esfahbodd0df9962019-05-15 00:32:41 -0700347 | hb_reduce ([] (uint32_t a, uint32_t b) { return a * 31 + b; }, 0)
Behdad Esfahbodd0da5472019-04-02 18:22:39 -0700348 ;
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700349}
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500350
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500351typedef hb_array_t<const char> hb_bytes_t;
Behdad Esfahbod3d9d7dc2018-12-18 22:11:23 -0500352typedef hb_array_t<const unsigned char> hb_ubytes_t;
Behdad Esfahboddcfa4a82018-12-16 20:40:07 -0500353
Behdad Esfahbod5b66b032019-04-02 19:27:02 -0700354/* TODO Specialize opeator==/hash() for hb_bytes_t and hb_ubytes_t. */
Behdad Esfahbodb189bbc2019-03-30 19:41:48 -0700355//template <>
356//uint32_t hb_array_t<const char>::hash () const { return 0; }
Behdad Esfahbod92680362018-12-16 23:38:51 -0500357
Behdad Esfahbod5a552f72018-12-16 20:07:44 -0500358#endif /* HB_ARRAY_HH */