54232
|
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 |
|
|
36 |
template <typename Type>
|
|
37 |
struct hb_sorted_array_t;
|
|
38 |
|
|
39 |
template <typename Type>
|
|
40 |
struct 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 |
};
|
|
179 |
template <typename T> inline hb_array_t<T>
|
|
180 |
hb_array (T *array, unsigned int length)
|
|
181 |
{ return hb_array_t<T> (array, length); }
|
|
182 |
template <typename T, unsigned int length_> inline hb_array_t<T>
|
|
183 |
hb_array (T (&array_)[length_])
|
|
184 |
{ return hb_array_t<T> (array_); }
|
|
185 |
|
|
186 |
|
|
187 |
enum 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 |
|
|
194 |
template <typename Type>
|
|
195 |
struct 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 |
};
|
|
265 |
template <typename T> inline hb_sorted_array_t<T>
|
|
266 |
hb_sorted_array (T *array, unsigned int length)
|
|
267 |
{ return hb_sorted_array_t<T> (array, length); }
|
|
268 |
template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
|
|
269 |
hb_sorted_array (T (&array_)[length_])
|
|
270 |
{ return hb_sorted_array_t<T> (array_); }
|
|
271 |
|
|
272 |
|
|
273 |
typedef hb_array_t<const char> hb_bytes_t;
|
|
274 |
typedef hb_array_t<const unsigned char> hb_ubytes_t;
|
|
275 |
|
|
276 |
|
|
277 |
#endif /* HB_ARRAY_HH */
|