Imported Upstream version 2.3.1
[platform/upstream/harfbuzz.git] / src / hb-array.hh
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 */