1/*
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#include "hb-dsalgs.hh"
32#include "hb-iter.hh"
33#include "hb-null.hh"
34
35
36template <typename Type>
37struct hb_sorted_array_t;
38
39template <typename Type>
40struct hb_array_t :
41 hb_iter_t<hb_array_t<Type>, Type>,
42 hb_iter_mixin_t<hb_array_t<Type>, Type>
43{
44 /*
45 * Constructors.
46 */
47 hb_array_t () : arrayZ (nullptr), length (0) {}
48 hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
49 template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
50
51
52 /*
53 * Iterator implementation.
54 */
55 typedef Type __item_type__;
56 Type& __item_at__ (unsigned i) const
57 {
58 if (unlikely (i >= length)) return CrapOrNull (Type);
59 return arrayZ[i];
60 }
61 void __forward__ (unsigned n)
62 {
63 if (unlikely (n > length))
64 n = length;
65 length -= n;
66 arrayZ += n;
67 }
68 void __rewind__ (unsigned n)
69 {
70 if (unlikely (n > length))
71 n = length;
72 length -= n;
73 }
74 unsigned __len__ () const { return length; }
75 bool __random_access__ () const { return true; }
76
77 /* Extra operators.
78 */
79 Type * operator & () const { return arrayZ; }
80 operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
81 template <typename T> operator T * () const { return arrayZ; }
82
83 /*
84 * Compare, Sort, and Search.
85 */
86
87 /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
88 int cmp (const hb_array_t<Type> &a) const
89 {
90 if (length != a.length)
91 return (int) a.length - (int) length;
92 return hb_memcmp (a.arrayZ, arrayZ, get_size ());
93 }
94 static int cmp (const void *pa, const void *pb)
95 {
96 hb_array_t<Type> *a = (hb_array_t<Type> *) pa;
97 hb_array_t<Type> *b = (hb_array_t<Type> *) pb;
98 return b->cmp (*a);
99 }
100
101 template <typename T>
102 Type *lsearch (const T &x, Type *not_found = nullptr)
103 {
104 unsigned int count = length;
105 for (unsigned int i = 0; i < count; i++)
106 if (!this->arrayZ[i].cmp (x))
107 return &this->arrayZ[i];
108 return not_found;
109 }
110 template <typename T>
111 const Type *lsearch (const T &x, const Type *not_found = nullptr) const
112 {
113 unsigned int count = length;
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
120 hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
121 {
122 if (likely (length))
123 ::qsort (arrayZ, length, this->item_size, cmp_);
124 return hb_sorted_array_t<Type> (*this);
125 }
126 hb_sorted_array_t<Type> qsort ()
127 {
128 if (likely (length))
129 ::qsort (arrayZ, length, this->item_size, Type::cmp);
130 return hb_sorted_array_t<Type> (*this);
131 }
132 void qsort (unsigned int start, unsigned int end)
133 {
134 end = MIN (end, length);
135 assert (start <= end);
136 if (likely (start < end))
137 ::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
138 }
139
140 /*
141 * Other methods.
142 */
143
144 unsigned int get_size () const { return length * this->item_size; }
145
146 hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
147 {
148 if (!start_offset && !seg_count)
149 return *this;
150
151 unsigned int count = length;
152 if (unlikely (start_offset > count))
153 count = 0;
154 else
155 count -= start_offset;
156 if (seg_count)
157 count = *seg_count = MIN (count, *seg_count);
158 return hb_array_t<Type> (arrayZ + start_offset, count);
159 }
160 hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
161 { return sub_array (start_offset, &seg_count); }
162
163 /* Only call if you allocated the underlying array using malloc() or similar. */
164 void free ()
165 { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
166
167 template <typename hb_sanitize_context_t>
168 bool sanitize (hb_sanitize_context_t *c) const
169 { return c->check_array (arrayZ, length); }
170
171 /*
172 * Members
173 */
174
175 public:
176 Type *arrayZ;
177 unsigned int length;
178};
179template <typename T> inline hb_array_t<T>
180hb_array (T *array, unsigned int length)
181{ return hb_array_t<T> (array, length); }
182template <typename T, unsigned int length_> inline hb_array_t<T>
183hb_array (T (&array_)[length_])
184{ return hb_array_t<T> (array_); }
185
186
187enum hb_bfind_not_found_t
188{
189 HB_BFIND_NOT_FOUND_DONT_STORE,
190 HB_BFIND_NOT_FOUND_STORE,
191 HB_BFIND_NOT_FOUND_STORE_CLOSEST,
192};
193
194template <typename Type>
195struct hb_sorted_array_t :
196 hb_sorted_iter_t<hb_sorted_array_t<Type>, Type>,
197 hb_array_t<Type>,
198 hb_iter_mixin_t<hb_sorted_array_t<Type>, Type>
199{
200 hb_sorted_array_t () : hb_array_t<Type> () {}
201 hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
202 hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
203 template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
204
205 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
206 { return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
207 hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
208 { return sub_array (start_offset, &seg_count); }
209
210 template <typename T>
211 Type *bsearch (const T &x, Type *not_found = nullptr)
212 {
213 unsigned int i;
214 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
215 }
216 template <typename T>
217 const Type *bsearch (const T &x, const Type *not_found = nullptr) const
218 {
219 unsigned int i;
220 return bfind (x, &i) ? &this->arrayZ[i] : not_found;
221 }
222 template <typename T>
223 bool bfind (const T &x, unsigned int *i = nullptr,
224 hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
225 unsigned int to_store = (unsigned int) -1) const
226 {
227 int min = 0, max = (int) this->length - 1;
228 const Type *array = this->arrayZ;
229 while (min <= max)
230 {
231 int mid = ((unsigned int) min + (unsigned int) max) / 2;
232 int c = array[mid].cmp (x);
233 if (c < 0)
234 max = mid - 1;
235 else if (c > 0)
236 min = mid + 1;
237 else
238 {
239 if (i)
240 *i = mid;
241 return true;
242 }
243 }
244 if (i)
245 {
246 switch (not_found)
247 {
248 case HB_BFIND_NOT_FOUND_DONT_STORE:
249 break;
250
251 case HB_BFIND_NOT_FOUND_STORE:
252 *i = to_store;
253 break;
254
255 case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
256 if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
257 max++;
258 *i = max;
259 break;
260 }
261 }
262 return false;
263 }
264};
265template <typename T> inline hb_sorted_array_t<T>
266hb_sorted_array (T *array, unsigned int length)
267{ return hb_sorted_array_t<T> (array, length); }
268template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
269hb_sorted_array (T (&array_)[length_])
270{ return hb_sorted_array_t<T> (array_); }
271
272
273typedef hb_array_t<const char> hb_bytes_t;
274typedef hb_array_t<const unsigned char> hb_ubytes_t;
275
276
277#endif /* HB_ARRAY_HH */
278