xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-bit-set.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2012,2017  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2021 Behdad Esfahbod
4*2d1272b8SAndroid Build Coastguard Worker  *
5*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
6*2d1272b8SAndroid Build Coastguard Worker  *
7*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
8*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
9*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
10*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
11*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
12*2d1272b8SAndroid Build Coastguard Worker  *
13*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
18*2d1272b8SAndroid Build Coastguard Worker  *
19*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24*2d1272b8SAndroid Build Coastguard Worker  *
25*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
26*2d1272b8SAndroid Build Coastguard Worker  */
27*2d1272b8SAndroid Build Coastguard Worker 
28*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_BIT_SET_HH
29*2d1272b8SAndroid Build Coastguard Worker #define HB_BIT_SET_HH
30*2d1272b8SAndroid Build Coastguard Worker 
31*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-bit-page.hh"
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker 
35*2d1272b8SAndroid Build Coastguard Worker struct hb_bit_set_t
36*2d1272b8SAndroid Build Coastguard Worker {
37*2d1272b8SAndroid Build Coastguard Worker   hb_bit_set_t () = default;
38*2d1272b8SAndroid Build Coastguard Worker   ~hb_bit_set_t () = default;
39*2d1272b8SAndroid Build Coastguard Worker 
hb_bit_set_thb_bit_set_t40*2d1272b8SAndroid Build Coastguard Worker   hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
hb_bit_set_thb_bit_set_t41*2d1272b8SAndroid Build Coastguard Worker   hb_bit_set_t ( hb_bit_set_t&& other)  noexcept : hb_bit_set_t () { hb_swap (*this, other); }
operator =hb_bit_set_t42*2d1272b8SAndroid Build Coastguard Worker   hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
operator =hb_bit_set_t43*2d1272b8SAndroid Build Coastguard Worker   hb_bit_set_t& operator= (hb_bit_set_t&& other)  noexcept { hb_swap (*this, other); return *this; }
swap(hb_bit_set_t & a,hb_bit_set_t & b)44*2d1272b8SAndroid Build Coastguard Worker   friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) noexcept
45*2d1272b8SAndroid Build Coastguard Worker   {
46*2d1272b8SAndroid Build Coastguard Worker     if (likely (!a.successful || !b.successful))
47*2d1272b8SAndroid Build Coastguard Worker       return;
48*2d1272b8SAndroid Build Coastguard Worker     hb_swap (a.population, b.population);
49*2d1272b8SAndroid Build Coastguard Worker     hb_swap (a.last_page_lookup, b.last_page_lookup);
50*2d1272b8SAndroid Build Coastguard Worker     hb_swap (a.page_map, b.page_map);
51*2d1272b8SAndroid Build Coastguard Worker     hb_swap (a.pages, b.pages);
52*2d1272b8SAndroid Build Coastguard Worker   }
53*2d1272b8SAndroid Build Coastguard Worker 
inithb_bit_set_t54*2d1272b8SAndroid Build Coastguard Worker   void init ()
55*2d1272b8SAndroid Build Coastguard Worker   {
56*2d1272b8SAndroid Build Coastguard Worker     successful = true;
57*2d1272b8SAndroid Build Coastguard Worker     population = 0;
58*2d1272b8SAndroid Build Coastguard Worker     last_page_lookup = 0;
59*2d1272b8SAndroid Build Coastguard Worker     page_map.init ();
60*2d1272b8SAndroid Build Coastguard Worker     pages.init ();
61*2d1272b8SAndroid Build Coastguard Worker   }
finihb_bit_set_t62*2d1272b8SAndroid Build Coastguard Worker   void fini ()
63*2d1272b8SAndroid Build Coastguard Worker   {
64*2d1272b8SAndroid Build Coastguard Worker     page_map.fini ();
65*2d1272b8SAndroid Build Coastguard Worker     pages.fini ();
66*2d1272b8SAndroid Build Coastguard Worker   }
67*2d1272b8SAndroid Build Coastguard Worker 
68*2d1272b8SAndroid Build Coastguard Worker   using page_t = hb_bit_page_t;
69*2d1272b8SAndroid Build Coastguard Worker   struct page_map_t
70*2d1272b8SAndroid Build Coastguard Worker   {
cmphb_bit_set_t::page_map_t71*2d1272b8SAndroid Build Coastguard Worker     int cmp (const page_map_t &o) const { return cmp (o.major); }
cmphb_bit_set_t::page_map_t72*2d1272b8SAndroid Build Coastguard Worker     int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
73*2d1272b8SAndroid Build Coastguard Worker 
74*2d1272b8SAndroid Build Coastguard Worker     uint32_t major;
75*2d1272b8SAndroid Build Coastguard Worker     uint32_t index;
76*2d1272b8SAndroid Build Coastguard Worker   };
77*2d1272b8SAndroid Build Coastguard Worker 
78*2d1272b8SAndroid Build Coastguard Worker   bool successful = true; /* Allocations successful */
79*2d1272b8SAndroid Build Coastguard Worker   mutable unsigned int population = 0;
80*2d1272b8SAndroid Build Coastguard Worker   mutable hb_atomic_int_t last_page_lookup = 0;
81*2d1272b8SAndroid Build Coastguard Worker   hb_sorted_vector_t<page_map_t> page_map;
82*2d1272b8SAndroid Build Coastguard Worker   hb_vector_t<page_t> pages;
83*2d1272b8SAndroid Build Coastguard Worker 
errhb_bit_set_t84*2d1272b8SAndroid Build Coastguard Worker   void err () { if (successful) successful = false; } /* TODO Remove */
in_errorhb_bit_set_t85*2d1272b8SAndroid Build Coastguard Worker   bool in_error () const { return !successful; }
86*2d1272b8SAndroid Build Coastguard Worker 
resizehb_bit_set_t87*2d1272b8SAndroid Build Coastguard Worker   bool resize (unsigned int count, bool clear = true, bool exact_size = false)
88*2d1272b8SAndroid Build Coastguard Worker   {
89*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return false;
90*2d1272b8SAndroid Build Coastguard Worker 
91*2d1272b8SAndroid Build Coastguard Worker     if (pages.length == 0 && count == 1)
92*2d1272b8SAndroid Build Coastguard Worker       exact_size = true; // Most sets are small and local
93*2d1272b8SAndroid Build Coastguard Worker 
94*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size)))
95*2d1272b8SAndroid Build Coastguard Worker     {
96*2d1272b8SAndroid Build Coastguard Worker       pages.resize (page_map.length, clear, exact_size);
97*2d1272b8SAndroid Build Coastguard Worker       successful = false;
98*2d1272b8SAndroid Build Coastguard Worker       return false;
99*2d1272b8SAndroid Build Coastguard Worker     }
100*2d1272b8SAndroid Build Coastguard Worker     return true;
101*2d1272b8SAndroid Build Coastguard Worker   }
102*2d1272b8SAndroid Build Coastguard Worker 
allochb_bit_set_t103*2d1272b8SAndroid Build Coastguard Worker   void alloc (unsigned sz)
104*2d1272b8SAndroid Build Coastguard Worker   {
105*2d1272b8SAndroid Build Coastguard Worker     sz >>= (page_t::PAGE_BITS_LOG_2 - 1);
106*2d1272b8SAndroid Build Coastguard Worker     pages.alloc (sz);
107*2d1272b8SAndroid Build Coastguard Worker     page_map.alloc (sz);
108*2d1272b8SAndroid Build Coastguard Worker   }
109*2d1272b8SAndroid Build Coastguard Worker 
resethb_bit_set_t110*2d1272b8SAndroid Build Coastguard Worker   void reset ()
111*2d1272b8SAndroid Build Coastguard Worker   {
112*2d1272b8SAndroid Build Coastguard Worker     successful = true;
113*2d1272b8SAndroid Build Coastguard Worker     clear ();
114*2d1272b8SAndroid Build Coastguard Worker   }
115*2d1272b8SAndroid Build Coastguard Worker 
clearhb_bit_set_t116*2d1272b8SAndroid Build Coastguard Worker   void clear ()
117*2d1272b8SAndroid Build Coastguard Worker   {
118*2d1272b8SAndroid Build Coastguard Worker     resize (0);
119*2d1272b8SAndroid Build Coastguard Worker     if (likely (successful))
120*2d1272b8SAndroid Build Coastguard Worker       population = 0;
121*2d1272b8SAndroid Build Coastguard Worker   }
is_emptyhb_bit_set_t122*2d1272b8SAndroid Build Coastguard Worker   bool is_empty () const
123*2d1272b8SAndroid Build Coastguard Worker   {
124*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = pages.length;
125*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
126*2d1272b8SAndroid Build Coastguard Worker       if (!pages[i].is_empty ())
127*2d1272b8SAndroid Build Coastguard Worker 	return false;
128*2d1272b8SAndroid Build Coastguard Worker     return true;
129*2d1272b8SAndroid Build Coastguard Worker   }
operator boolhb_bit_set_t130*2d1272b8SAndroid Build Coastguard Worker   explicit operator bool () const { return !is_empty (); }
131*2d1272b8SAndroid Build Coastguard Worker 
hashhb_bit_set_t132*2d1272b8SAndroid Build Coastguard Worker   uint32_t hash () const
133*2d1272b8SAndroid Build Coastguard Worker   {
134*2d1272b8SAndroid Build Coastguard Worker     uint32_t h = 0;
135*2d1272b8SAndroid Build Coastguard Worker     for (auto &map : page_map)
136*2d1272b8SAndroid Build Coastguard Worker     {
137*2d1272b8SAndroid Build Coastguard Worker       auto &page = pages.arrayZ[map.index];
138*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (page.is_empty ())) continue;
139*2d1272b8SAndroid Build Coastguard Worker       h = h * 31 + hb_hash (map.major) + hb_hash (page);
140*2d1272b8SAndroid Build Coastguard Worker     }
141*2d1272b8SAndroid Build Coastguard Worker     return h;
142*2d1272b8SAndroid Build Coastguard Worker   }
143*2d1272b8SAndroid Build Coastguard Worker 
144*2d1272b8SAndroid Build Coastguard Worker   private:
dirtyhb_bit_set_t145*2d1272b8SAndroid Build Coastguard Worker   void dirty () { population = UINT_MAX; }
146*2d1272b8SAndroid Build Coastguard Worker   public:
147*2d1272b8SAndroid Build Coastguard Worker 
addhb_bit_set_t148*2d1272b8SAndroid Build Coastguard Worker   void add (hb_codepoint_t g)
149*2d1272b8SAndroid Build Coastguard Worker   {
150*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return;
151*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (g == INVALID)) return;
152*2d1272b8SAndroid Build Coastguard Worker     dirty ();
153*2d1272b8SAndroid Build Coastguard Worker     page_t *page = page_for (g, true); if (unlikely (!page)) return;
154*2d1272b8SAndroid Build Coastguard Worker     page->add (g);
155*2d1272b8SAndroid Build Coastguard Worker   }
add_rangehb_bit_set_t156*2d1272b8SAndroid Build Coastguard Worker   bool add_range (hb_codepoint_t a, hb_codepoint_t b)
157*2d1272b8SAndroid Build Coastguard Worker   {
158*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
159*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
160*2d1272b8SAndroid Build Coastguard Worker     dirty ();
161*2d1272b8SAndroid Build Coastguard Worker     unsigned int ma = get_major (a);
162*2d1272b8SAndroid Build Coastguard Worker     unsigned int mb = get_major (b);
163*2d1272b8SAndroid Build Coastguard Worker     if (ma == mb)
164*2d1272b8SAndroid Build Coastguard Worker     {
165*2d1272b8SAndroid Build Coastguard Worker       page_t *page = page_for (a, true); if (unlikely (!page)) return false;
166*2d1272b8SAndroid Build Coastguard Worker       page->add_range (a, b);
167*2d1272b8SAndroid Build Coastguard Worker     }
168*2d1272b8SAndroid Build Coastguard Worker     else
169*2d1272b8SAndroid Build Coastguard Worker     {
170*2d1272b8SAndroid Build Coastguard Worker       page_t *page = page_for (a, true); if (unlikely (!page)) return false;
171*2d1272b8SAndroid Build Coastguard Worker       page->add_range (a, major_start (ma + 1) - 1);
172*2d1272b8SAndroid Build Coastguard Worker 
173*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int m = ma + 1; m < mb; m++)
174*2d1272b8SAndroid Build Coastguard Worker       {
175*2d1272b8SAndroid Build Coastguard Worker 	page = page_for (major_start (m), true); if (unlikely (!page)) return false;
176*2d1272b8SAndroid Build Coastguard Worker 	page->init1 ();
177*2d1272b8SAndroid Build Coastguard Worker       }
178*2d1272b8SAndroid Build Coastguard Worker 
179*2d1272b8SAndroid Build Coastguard Worker       page = page_for (b, true); if (unlikely (!page)) return false;
180*2d1272b8SAndroid Build Coastguard Worker       page->add_range (major_start (mb), b);
181*2d1272b8SAndroid Build Coastguard Worker     }
182*2d1272b8SAndroid Build Coastguard Worker     return true;
183*2d1272b8SAndroid Build Coastguard Worker   }
184*2d1272b8SAndroid Build Coastguard Worker 
185*2d1272b8SAndroid Build Coastguard Worker   /* Duplicated here from hb-machinery.hh to avoid including it. */
186*2d1272b8SAndroid Build Coastguard Worker   template<typename Type>
StructAtOffsetUnalignedhb_bit_set_t187*2d1272b8SAndroid Build Coastguard Worker   static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
188*2d1272b8SAndroid Build Coastguard Worker   {
189*2d1272b8SAndroid Build Coastguard Worker #pragma GCC diagnostic push
190*2d1272b8SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wcast-align"
191*2d1272b8SAndroid Build Coastguard Worker     return * reinterpret_cast<const Type*> ((const char *) P + offset);
192*2d1272b8SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
193*2d1272b8SAndroid Build Coastguard Worker   }
194*2d1272b8SAndroid Build Coastguard Worker 
195*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
set_arrayhb_bit_set_t196*2d1272b8SAndroid Build Coastguard Worker   void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
197*2d1272b8SAndroid Build Coastguard Worker   {
198*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return;
199*2d1272b8SAndroid Build Coastguard Worker     if (!count) return;
200*2d1272b8SAndroid Build Coastguard Worker     dirty ();
201*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t g = *array;
202*2d1272b8SAndroid Build Coastguard Worker     while (count)
203*2d1272b8SAndroid Build Coastguard Worker     {
204*2d1272b8SAndroid Build Coastguard Worker       unsigned int m = get_major (g);
205*2d1272b8SAndroid Build Coastguard Worker       page_t *page = page_for (g, v); if (unlikely (v && !page)) return;
206*2d1272b8SAndroid Build Coastguard Worker       unsigned int start = major_start (m);
207*2d1272b8SAndroid Build Coastguard Worker       unsigned int end = major_start (m + 1);
208*2d1272b8SAndroid Build Coastguard Worker       do
209*2d1272b8SAndroid Build Coastguard Worker       {
210*2d1272b8SAndroid Build Coastguard Worker         if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
211*2d1272b8SAndroid Build Coastguard Worker 	  page->set (g, v);
212*2d1272b8SAndroid Build Coastguard Worker 
213*2d1272b8SAndroid Build Coastguard Worker 	array = &StructAtOffsetUnaligned<T> (array, stride);
214*2d1272b8SAndroid Build Coastguard Worker 	count--;
215*2d1272b8SAndroid Build Coastguard Worker       }
216*2d1272b8SAndroid Build Coastguard Worker       while (count && (g = *array, start <= g && g < end));
217*2d1272b8SAndroid Build Coastguard Worker     }
218*2d1272b8SAndroid Build Coastguard Worker   }
219*2d1272b8SAndroid Build Coastguard Worker 
220*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
add_arrayhb_bit_set_t221*2d1272b8SAndroid Build Coastguard Worker   void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
222*2d1272b8SAndroid Build Coastguard Worker   { set_array (true, array, count, stride); }
223*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
add_arrayhb_bit_set_t224*2d1272b8SAndroid Build Coastguard Worker   void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
225*2d1272b8SAndroid Build Coastguard Worker 
226*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
del_arrayhb_bit_set_t227*2d1272b8SAndroid Build Coastguard Worker   void del_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
228*2d1272b8SAndroid Build Coastguard Worker   { set_array (false, array, count, stride); }
229*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
del_arrayhb_bit_set_t230*2d1272b8SAndroid Build Coastguard Worker   void del_array (const hb_array_t<const T>& arr) { del_array (&arr, arr.len ()); }
231*2d1272b8SAndroid Build Coastguard Worker 
232*2d1272b8SAndroid Build Coastguard Worker   /* Might return false if array looks unsorted.
233*2d1272b8SAndroid Build Coastguard Worker    * Used for faster rejection of corrupt data. */
234*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
set_sorted_arrayhb_bit_set_t235*2d1272b8SAndroid Build Coastguard Worker   bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
236*2d1272b8SAndroid Build Coastguard Worker   {
237*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
238*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!count)) return true;
239*2d1272b8SAndroid Build Coastguard Worker     dirty ();
240*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t g = *array;
241*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t last_g = g;
242*2d1272b8SAndroid Build Coastguard Worker     while (count)
243*2d1272b8SAndroid Build Coastguard Worker     {
244*2d1272b8SAndroid Build Coastguard Worker       unsigned int m = get_major (g);
245*2d1272b8SAndroid Build Coastguard Worker       page_t *page = page_for (g, v); if (unlikely (v && !page)) return false;
246*2d1272b8SAndroid Build Coastguard Worker       unsigned int end = major_start (m + 1);
247*2d1272b8SAndroid Build Coastguard Worker       do
248*2d1272b8SAndroid Build Coastguard Worker       {
249*2d1272b8SAndroid Build Coastguard Worker 	/* If we try harder we can change the following comparison to <=;
250*2d1272b8SAndroid Build Coastguard Worker 	 * Not sure if it's worth it. */
251*2d1272b8SAndroid Build Coastguard Worker 	if (g < last_g) return false;
252*2d1272b8SAndroid Build Coastguard Worker 	last_g = g;
253*2d1272b8SAndroid Build Coastguard Worker 
254*2d1272b8SAndroid Build Coastguard Worker         if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
255*2d1272b8SAndroid Build Coastguard Worker 	  page->add (g);
256*2d1272b8SAndroid Build Coastguard Worker 
257*2d1272b8SAndroid Build Coastguard Worker 	array = &StructAtOffsetUnaligned<T> (array, stride);
258*2d1272b8SAndroid Build Coastguard Worker 	count--;
259*2d1272b8SAndroid Build Coastguard Worker       }
260*2d1272b8SAndroid Build Coastguard Worker       while (count && (g = *array, g < end));
261*2d1272b8SAndroid Build Coastguard Worker     }
262*2d1272b8SAndroid Build Coastguard Worker     return true;
263*2d1272b8SAndroid Build Coastguard Worker   }
264*2d1272b8SAndroid Build Coastguard Worker 
265*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
add_sorted_arrayhb_bit_set_t266*2d1272b8SAndroid Build Coastguard Worker   bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
267*2d1272b8SAndroid Build Coastguard Worker   { return set_sorted_array (true, array, count, stride); }
268*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
add_sorted_arrayhb_bit_set_t269*2d1272b8SAndroid Build Coastguard Worker   bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
270*2d1272b8SAndroid Build Coastguard Worker 
271*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
del_sorted_arrayhb_bit_set_t272*2d1272b8SAndroid Build Coastguard Worker   bool del_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
273*2d1272b8SAndroid Build Coastguard Worker   { return set_sorted_array (false, array, count, stride); }
274*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
del_sorted_arrayhb_bit_set_t275*2d1272b8SAndroid Build Coastguard Worker   bool del_sorted_array (const hb_sorted_array_t<const T>& arr) { return del_sorted_array (&arr, arr.len ()); }
276*2d1272b8SAndroid Build Coastguard Worker 
delhb_bit_set_t277*2d1272b8SAndroid Build Coastguard Worker   void del (hb_codepoint_t g)
278*2d1272b8SAndroid Build Coastguard Worker   {
279*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return;
280*2d1272b8SAndroid Build Coastguard Worker     page_t *page = page_for (g);
281*2d1272b8SAndroid Build Coastguard Worker     if (!page)
282*2d1272b8SAndroid Build Coastguard Worker       return;
283*2d1272b8SAndroid Build Coastguard Worker     dirty ();
284*2d1272b8SAndroid Build Coastguard Worker     page->del (g);
285*2d1272b8SAndroid Build Coastguard Worker   }
286*2d1272b8SAndroid Build Coastguard Worker 
287*2d1272b8SAndroid Build Coastguard Worker   private:
del_pageshb_bit_set_t288*2d1272b8SAndroid Build Coastguard Worker   void del_pages (int ds, int de)
289*2d1272b8SAndroid Build Coastguard Worker   {
290*2d1272b8SAndroid Build Coastguard Worker     if (ds <= de)
291*2d1272b8SAndroid Build Coastguard Worker     {
292*2d1272b8SAndroid Build Coastguard Worker       // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
293*2d1272b8SAndroid Build Coastguard Worker       // before attempting to rewrite the page map.
294*2d1272b8SAndroid Build Coastguard Worker       hb_vector_t<unsigned> compact_workspace;
295*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
296*2d1272b8SAndroid Build Coastguard Worker 
297*2d1272b8SAndroid Build Coastguard Worker       unsigned int write_index = 0;
298*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int i = 0; i < page_map.length; i++)
299*2d1272b8SAndroid Build Coastguard Worker       {
300*2d1272b8SAndroid Build Coastguard Worker 	int m = (int) page_map[i].major;
301*2d1272b8SAndroid Build Coastguard Worker 	if (m < ds || de < m)
302*2d1272b8SAndroid Build Coastguard Worker 	  page_map[write_index++] = page_map[i];
303*2d1272b8SAndroid Build Coastguard Worker       }
304*2d1272b8SAndroid Build Coastguard Worker       compact (compact_workspace, write_index);
305*2d1272b8SAndroid Build Coastguard Worker       resize (write_index);
306*2d1272b8SAndroid Build Coastguard Worker     }
307*2d1272b8SAndroid Build Coastguard Worker   }
308*2d1272b8SAndroid Build Coastguard Worker 
309*2d1272b8SAndroid Build Coastguard Worker 
310*2d1272b8SAndroid Build Coastguard Worker   public:
del_rangehb_bit_set_t311*2d1272b8SAndroid Build Coastguard Worker   void del_range (hb_codepoint_t a, hb_codepoint_t b)
312*2d1272b8SAndroid Build Coastguard Worker   {
313*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return;
314*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (a > b || a == INVALID)) return;
315*2d1272b8SAndroid Build Coastguard Worker     dirty ();
316*2d1272b8SAndroid Build Coastguard Worker     unsigned int ma = get_major (a);
317*2d1272b8SAndroid Build Coastguard Worker     unsigned int mb = get_major (b);
318*2d1272b8SAndroid Build Coastguard Worker     /* Delete pages from ds through de if ds <= de. */
319*2d1272b8SAndroid Build Coastguard Worker     int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
320*2d1272b8SAndroid Build Coastguard Worker     int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
321*2d1272b8SAndroid Build Coastguard Worker     if (ds > de || (int) ma < ds)
322*2d1272b8SAndroid Build Coastguard Worker     {
323*2d1272b8SAndroid Build Coastguard Worker       page_t *page = page_for (a);
324*2d1272b8SAndroid Build Coastguard Worker       if (page)
325*2d1272b8SAndroid Build Coastguard Worker       {
326*2d1272b8SAndroid Build Coastguard Worker 	if (ma == mb)
327*2d1272b8SAndroid Build Coastguard Worker 	  page->del_range (a, b);
328*2d1272b8SAndroid Build Coastguard Worker 	else
329*2d1272b8SAndroid Build Coastguard Worker 	  page->del_range (a, major_start (ma + 1) - 1);
330*2d1272b8SAndroid Build Coastguard Worker       }
331*2d1272b8SAndroid Build Coastguard Worker     }
332*2d1272b8SAndroid Build Coastguard Worker     if (de < (int) mb && ma != mb)
333*2d1272b8SAndroid Build Coastguard Worker     {
334*2d1272b8SAndroid Build Coastguard Worker       page_t *page = page_for (b);
335*2d1272b8SAndroid Build Coastguard Worker       if (page)
336*2d1272b8SAndroid Build Coastguard Worker 	page->del_range (major_start (mb), b);
337*2d1272b8SAndroid Build Coastguard Worker     }
338*2d1272b8SAndroid Build Coastguard Worker     del_pages (ds, de);
339*2d1272b8SAndroid Build Coastguard Worker   }
340*2d1272b8SAndroid Build Coastguard Worker 
gethb_bit_set_t341*2d1272b8SAndroid Build Coastguard Worker   bool get (hb_codepoint_t g) const
342*2d1272b8SAndroid Build Coastguard Worker   {
343*2d1272b8SAndroid Build Coastguard Worker     const page_t *page = page_for (g);
344*2d1272b8SAndroid Build Coastguard Worker     if (!page)
345*2d1272b8SAndroid Build Coastguard Worker       return false;
346*2d1272b8SAndroid Build Coastguard Worker     return page->get (g);
347*2d1272b8SAndroid Build Coastguard Worker   }
348*2d1272b8SAndroid Build Coastguard Worker 
349*2d1272b8SAndroid Build Coastguard Worker   /* Has interface. */
operator []hb_bit_set_t350*2d1272b8SAndroid Build Coastguard Worker   bool operator [] (hb_codepoint_t k) const { return get (k); }
hashb_bit_set_t351*2d1272b8SAndroid Build Coastguard Worker   bool has (hb_codepoint_t k) const { return (*this)[k]; }
352*2d1272b8SAndroid Build Coastguard Worker   /* Predicate. */
operator ()hb_bit_set_t353*2d1272b8SAndroid Build Coastguard Worker   bool operator () (hb_codepoint_t k) const { return has (k); }
354*2d1272b8SAndroid Build Coastguard Worker 
355*2d1272b8SAndroid Build Coastguard Worker   /* Sink interface. */
operator <<hb_bit_set_t356*2d1272b8SAndroid Build Coastguard Worker   hb_bit_set_t& operator << (hb_codepoint_t v)
357*2d1272b8SAndroid Build Coastguard Worker   { add (v); return *this; }
operator <<hb_bit_set_t358*2d1272b8SAndroid Build Coastguard Worker   hb_bit_set_t& operator << (const hb_codepoint_pair_t& range)
359*2d1272b8SAndroid Build Coastguard Worker   { add_range (range.first, range.second); return *this; }
360*2d1272b8SAndroid Build Coastguard Worker 
intersectshb_bit_set_t361*2d1272b8SAndroid Build Coastguard Worker   bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
362*2d1272b8SAndroid Build Coastguard Worker   {
363*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t c = first - 1;
364*2d1272b8SAndroid Build Coastguard Worker     return next (&c) && c <= last;
365*2d1272b8SAndroid Build Coastguard Worker   }
sethb_bit_set_t366*2d1272b8SAndroid Build Coastguard Worker   void set (const hb_bit_set_t &other, bool exact_size = false)
367*2d1272b8SAndroid Build Coastguard Worker   {
368*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return;
369*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = other.pages.length;
370*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!resize (count, false, exact_size)))
371*2d1272b8SAndroid Build Coastguard Worker       return;
372*2d1272b8SAndroid Build Coastguard Worker     population = other.population;
373*2d1272b8SAndroid Build Coastguard Worker 
374*2d1272b8SAndroid Build Coastguard Worker     page_map = other.page_map;
375*2d1272b8SAndroid Build Coastguard Worker     pages = other.pages;
376*2d1272b8SAndroid Build Coastguard Worker   }
377*2d1272b8SAndroid Build Coastguard Worker 
is_equalhb_bit_set_t378*2d1272b8SAndroid Build Coastguard Worker   bool is_equal (const hb_bit_set_t &other) const
379*2d1272b8SAndroid Build Coastguard Worker   {
380*2d1272b8SAndroid Build Coastguard Worker     if (has_population () && other.has_population () &&
381*2d1272b8SAndroid Build Coastguard Worker 	population != other.population)
382*2d1272b8SAndroid Build Coastguard Worker       return false;
383*2d1272b8SAndroid Build Coastguard Worker 
384*2d1272b8SAndroid Build Coastguard Worker     unsigned int na = pages.length;
385*2d1272b8SAndroid Build Coastguard Worker     unsigned int nb = other.pages.length;
386*2d1272b8SAndroid Build Coastguard Worker 
387*2d1272b8SAndroid Build Coastguard Worker     unsigned int a = 0, b = 0;
388*2d1272b8SAndroid Build Coastguard Worker     for (; a < na && b < nb; )
389*2d1272b8SAndroid Build Coastguard Worker     {
390*2d1272b8SAndroid Build Coastguard Worker       if (page_at (a).is_empty ()) { a++; continue; }
391*2d1272b8SAndroid Build Coastguard Worker       if (other.page_at (b).is_empty ()) { b++; continue; }
392*2d1272b8SAndroid Build Coastguard Worker       if (page_map[a].major != other.page_map[b].major ||
393*2d1272b8SAndroid Build Coastguard Worker 	  !page_at (a).is_equal (other.page_at (b)))
394*2d1272b8SAndroid Build Coastguard Worker 	return false;
395*2d1272b8SAndroid Build Coastguard Worker       a++;
396*2d1272b8SAndroid Build Coastguard Worker       b++;
397*2d1272b8SAndroid Build Coastguard Worker     }
398*2d1272b8SAndroid Build Coastguard Worker     for (; a < na; a++)
399*2d1272b8SAndroid Build Coastguard Worker       if (!page_at (a).is_empty ()) { return false; }
400*2d1272b8SAndroid Build Coastguard Worker     for (; b < nb; b++)
401*2d1272b8SAndroid Build Coastguard Worker       if (!other.page_at (b).is_empty ()) { return false; }
402*2d1272b8SAndroid Build Coastguard Worker 
403*2d1272b8SAndroid Build Coastguard Worker     return true;
404*2d1272b8SAndroid Build Coastguard Worker   }
405*2d1272b8SAndroid Build Coastguard Worker 
is_subsethb_bit_set_t406*2d1272b8SAndroid Build Coastguard Worker   bool is_subset (const hb_bit_set_t &larger_set) const
407*2d1272b8SAndroid Build Coastguard Worker   {
408*2d1272b8SAndroid Build Coastguard Worker     if (has_population () && larger_set.has_population () &&
409*2d1272b8SAndroid Build Coastguard Worker 	population > larger_set.population)
410*2d1272b8SAndroid Build Coastguard Worker       return false;
411*2d1272b8SAndroid Build Coastguard Worker 
412*2d1272b8SAndroid Build Coastguard Worker     uint32_t spi = 0;
413*2d1272b8SAndroid Build Coastguard Worker     for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
414*2d1272b8SAndroid Build Coastguard Worker     {
415*2d1272b8SAndroid Build Coastguard Worker       uint32_t spm = page_map[spi].major;
416*2d1272b8SAndroid Build Coastguard Worker       uint32_t lpm = larger_set.page_map[lpi].major;
417*2d1272b8SAndroid Build Coastguard Worker       auto sp = page_at (spi);
418*2d1272b8SAndroid Build Coastguard Worker 
419*2d1272b8SAndroid Build Coastguard Worker       if (spm < lpm && !sp.is_empty ())
420*2d1272b8SAndroid Build Coastguard Worker         return false;
421*2d1272b8SAndroid Build Coastguard Worker 
422*2d1272b8SAndroid Build Coastguard Worker       if (lpm < spm)
423*2d1272b8SAndroid Build Coastguard Worker         continue;
424*2d1272b8SAndroid Build Coastguard Worker 
425*2d1272b8SAndroid Build Coastguard Worker       auto lp = larger_set.page_at (lpi);
426*2d1272b8SAndroid Build Coastguard Worker       if (!sp.is_subset (lp))
427*2d1272b8SAndroid Build Coastguard Worker         return false;
428*2d1272b8SAndroid Build Coastguard Worker 
429*2d1272b8SAndroid Build Coastguard Worker       spi++;
430*2d1272b8SAndroid Build Coastguard Worker     }
431*2d1272b8SAndroid Build Coastguard Worker 
432*2d1272b8SAndroid Build Coastguard Worker     while (spi < page_map.length)
433*2d1272b8SAndroid Build Coastguard Worker       if (!page_at (spi++).is_empty ())
434*2d1272b8SAndroid Build Coastguard Worker         return false;
435*2d1272b8SAndroid Build Coastguard Worker 
436*2d1272b8SAndroid Build Coastguard Worker     return true;
437*2d1272b8SAndroid Build Coastguard Worker   }
438*2d1272b8SAndroid Build Coastguard Worker 
439*2d1272b8SAndroid Build Coastguard Worker   private:
allocate_compact_workspacehb_bit_set_t440*2d1272b8SAndroid Build Coastguard Worker   bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
441*2d1272b8SAndroid Build Coastguard Worker   {
442*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!workspace.resize_exact (pages.length)))
443*2d1272b8SAndroid Build Coastguard Worker     {
444*2d1272b8SAndroid Build Coastguard Worker       successful = false;
445*2d1272b8SAndroid Build Coastguard Worker       return false;
446*2d1272b8SAndroid Build Coastguard Worker     }
447*2d1272b8SAndroid Build Coastguard Worker 
448*2d1272b8SAndroid Build Coastguard Worker     return true;
449*2d1272b8SAndroid Build Coastguard Worker   }
450*2d1272b8SAndroid Build Coastguard Worker 
451*2d1272b8SAndroid Build Coastguard Worker   /*
452*2d1272b8SAndroid Build Coastguard Worker    * workspace should be a pre-sized vector allocated to hold at exactly pages.length
453*2d1272b8SAndroid Build Coastguard Worker    * elements.
454*2d1272b8SAndroid Build Coastguard Worker    */
compacthb_bit_set_t455*2d1272b8SAndroid Build Coastguard Worker   void compact (hb_vector_t<unsigned>& workspace,
456*2d1272b8SAndroid Build Coastguard Worker                 unsigned int length)
457*2d1272b8SAndroid Build Coastguard Worker   {
458*2d1272b8SAndroid Build Coastguard Worker     assert(workspace.length == pages.length);
459*2d1272b8SAndroid Build Coastguard Worker     hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
460*2d1272b8SAndroid Build Coastguard Worker 
461*2d1272b8SAndroid Build Coastguard Worker     hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
462*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < length; i++)
463*2d1272b8SAndroid Build Coastguard Worker       old_index_to_page_map_index[page_map[i].index] =  i;
464*2d1272b8SAndroid Build Coastguard Worker 
465*2d1272b8SAndroid Build Coastguard Worker     compact_pages (old_index_to_page_map_index);
466*2d1272b8SAndroid Build Coastguard Worker   }
compact_pageshb_bit_set_t467*2d1272b8SAndroid Build Coastguard Worker   void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
468*2d1272b8SAndroid Build Coastguard Worker   {
469*2d1272b8SAndroid Build Coastguard Worker     unsigned int write_index = 0;
470*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < pages.length; i++)
471*2d1272b8SAndroid Build Coastguard Worker     {
472*2d1272b8SAndroid Build Coastguard Worker       if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
473*2d1272b8SAndroid Build Coastguard Worker 
474*2d1272b8SAndroid Build Coastguard Worker       if (write_index < i)
475*2d1272b8SAndroid Build Coastguard Worker 	pages[write_index] = pages[i];
476*2d1272b8SAndroid Build Coastguard Worker 
477*2d1272b8SAndroid Build Coastguard Worker       page_map[old_index_to_page_map_index[i]].index = write_index;
478*2d1272b8SAndroid Build Coastguard Worker       write_index++;
479*2d1272b8SAndroid Build Coastguard Worker     }
480*2d1272b8SAndroid Build Coastguard Worker   }
481*2d1272b8SAndroid Build Coastguard Worker   public:
482*2d1272b8SAndroid Build Coastguard Worker 
process_hb_bit_set_t483*2d1272b8SAndroid Build Coastguard Worker   void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &),
484*2d1272b8SAndroid Build Coastguard Worker 		 bool passthru_left, bool passthru_right,
485*2d1272b8SAndroid Build Coastguard Worker 		 const hb_bit_set_t &other)
486*2d1272b8SAndroid Build Coastguard Worker   {
487*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!successful)) return;
488*2d1272b8SAndroid Build Coastguard Worker 
489*2d1272b8SAndroid Build Coastguard Worker     dirty ();
490*2d1272b8SAndroid Build Coastguard Worker 
491*2d1272b8SAndroid Build Coastguard Worker     unsigned int na = pages.length;
492*2d1272b8SAndroid Build Coastguard Worker     unsigned int nb = other.pages.length;
493*2d1272b8SAndroid Build Coastguard Worker     unsigned int next_page = na;
494*2d1272b8SAndroid Build Coastguard Worker 
495*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = 0, newCount = 0;
496*2d1272b8SAndroid Build Coastguard Worker     unsigned int a = 0, b = 0;
497*2d1272b8SAndroid Build Coastguard Worker     unsigned int write_index = 0;
498*2d1272b8SAndroid Build Coastguard Worker 
499*2d1272b8SAndroid Build Coastguard Worker     // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
500*2d1272b8SAndroid Build Coastguard Worker     // before attempting to rewrite the page map.
501*2d1272b8SAndroid Build Coastguard Worker     hb_vector_t<unsigned> compact_workspace;
502*2d1272b8SAndroid Build Coastguard Worker     if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
503*2d1272b8SAndroid Build Coastguard Worker 
504*2d1272b8SAndroid Build Coastguard Worker     for (; a < na && b < nb; )
505*2d1272b8SAndroid Build Coastguard Worker     {
506*2d1272b8SAndroid Build Coastguard Worker       if (page_map[a].major == other.page_map[b].major)
507*2d1272b8SAndroid Build Coastguard Worker       {
508*2d1272b8SAndroid Build Coastguard Worker 	if (!passthru_left)
509*2d1272b8SAndroid Build Coastguard Worker 	{
510*2d1272b8SAndroid Build Coastguard Worker 	  // Move page_map entries that we're keeping from the left side set
511*2d1272b8SAndroid Build Coastguard Worker 	  // to the front of the page_map vector. This isn't necessary if
512*2d1272b8SAndroid Build Coastguard Worker 	  // passthru_left is set since no left side pages will be removed
513*2d1272b8SAndroid Build Coastguard Worker 	  // in that case.
514*2d1272b8SAndroid Build Coastguard Worker 	  if (write_index < a)
515*2d1272b8SAndroid Build Coastguard Worker 	    page_map[write_index] = page_map[a];
516*2d1272b8SAndroid Build Coastguard Worker 	  write_index++;
517*2d1272b8SAndroid Build Coastguard Worker 	}
518*2d1272b8SAndroid Build Coastguard Worker 
519*2d1272b8SAndroid Build Coastguard Worker 	count++;
520*2d1272b8SAndroid Build Coastguard Worker 	a++;
521*2d1272b8SAndroid Build Coastguard Worker 	b++;
522*2d1272b8SAndroid Build Coastguard Worker       }
523*2d1272b8SAndroid Build Coastguard Worker       else if (page_map[a].major < other.page_map[b].major)
524*2d1272b8SAndroid Build Coastguard Worker       {
525*2d1272b8SAndroid Build Coastguard Worker 	if (passthru_left)
526*2d1272b8SAndroid Build Coastguard Worker 	  count++;
527*2d1272b8SAndroid Build Coastguard Worker 	a++;
528*2d1272b8SAndroid Build Coastguard Worker       }
529*2d1272b8SAndroid Build Coastguard Worker       else
530*2d1272b8SAndroid Build Coastguard Worker       {
531*2d1272b8SAndroid Build Coastguard Worker 	if (passthru_right)
532*2d1272b8SAndroid Build Coastguard Worker 	  count++;
533*2d1272b8SAndroid Build Coastguard Worker 	b++;
534*2d1272b8SAndroid Build Coastguard Worker       }
535*2d1272b8SAndroid Build Coastguard Worker     }
536*2d1272b8SAndroid Build Coastguard Worker     if (passthru_left)
537*2d1272b8SAndroid Build Coastguard Worker       count += na - a;
538*2d1272b8SAndroid Build Coastguard Worker     if (passthru_right)
539*2d1272b8SAndroid Build Coastguard Worker       count += nb - b;
540*2d1272b8SAndroid Build Coastguard Worker 
541*2d1272b8SAndroid Build Coastguard Worker     if (!passthru_left)
542*2d1272b8SAndroid Build Coastguard Worker     {
543*2d1272b8SAndroid Build Coastguard Worker       na  = write_index;
544*2d1272b8SAndroid Build Coastguard Worker       next_page = write_index;
545*2d1272b8SAndroid Build Coastguard Worker       compact (compact_workspace, write_index);
546*2d1272b8SAndroid Build Coastguard Worker     }
547*2d1272b8SAndroid Build Coastguard Worker 
548*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!resize (count)))
549*2d1272b8SAndroid Build Coastguard Worker       return;
550*2d1272b8SAndroid Build Coastguard Worker 
551*2d1272b8SAndroid Build Coastguard Worker     newCount = count;
552*2d1272b8SAndroid Build Coastguard Worker 
553*2d1272b8SAndroid Build Coastguard Worker     /* Process in-place backward. */
554*2d1272b8SAndroid Build Coastguard Worker     a = na;
555*2d1272b8SAndroid Build Coastguard Worker     b = nb;
556*2d1272b8SAndroid Build Coastguard Worker     for (; a && b; )
557*2d1272b8SAndroid Build Coastguard Worker     {
558*2d1272b8SAndroid Build Coastguard Worker       if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major)
559*2d1272b8SAndroid Build Coastguard Worker       {
560*2d1272b8SAndroid Build Coastguard Worker 	a--;
561*2d1272b8SAndroid Build Coastguard Worker 	b--;
562*2d1272b8SAndroid Build Coastguard Worker 	count--;
563*2d1272b8SAndroid Build Coastguard Worker 	page_map.arrayZ[count] = page_map.arrayZ[a];
564*2d1272b8SAndroid Build Coastguard Worker 	page_at (count).v = op (page_at (a).v, other.page_at (b).v);
565*2d1272b8SAndroid Build Coastguard Worker 	page_at (count).dirty ();
566*2d1272b8SAndroid Build Coastguard Worker       }
567*2d1272b8SAndroid Build Coastguard Worker       else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major)
568*2d1272b8SAndroid Build Coastguard Worker       {
569*2d1272b8SAndroid Build Coastguard Worker 	a--;
570*2d1272b8SAndroid Build Coastguard Worker 	if (passthru_left)
571*2d1272b8SAndroid Build Coastguard Worker 	{
572*2d1272b8SAndroid Build Coastguard Worker 	  count--;
573*2d1272b8SAndroid Build Coastguard Worker 	  page_map.arrayZ[count] = page_map.arrayZ[a];
574*2d1272b8SAndroid Build Coastguard Worker 	}
575*2d1272b8SAndroid Build Coastguard Worker       }
576*2d1272b8SAndroid Build Coastguard Worker       else
577*2d1272b8SAndroid Build Coastguard Worker       {
578*2d1272b8SAndroid Build Coastguard Worker 	b--;
579*2d1272b8SAndroid Build Coastguard Worker 	if (passthru_right)
580*2d1272b8SAndroid Build Coastguard Worker 	{
581*2d1272b8SAndroid Build Coastguard Worker 	  count--;
582*2d1272b8SAndroid Build Coastguard Worker 	  page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
583*2d1272b8SAndroid Build Coastguard Worker 	  page_map.arrayZ[count].index = next_page++;
584*2d1272b8SAndroid Build Coastguard Worker 	  page_at (count) = other.page_at (b);
585*2d1272b8SAndroid Build Coastguard Worker 	}
586*2d1272b8SAndroid Build Coastguard Worker       }
587*2d1272b8SAndroid Build Coastguard Worker     }
588*2d1272b8SAndroid Build Coastguard Worker     if (passthru_left)
589*2d1272b8SAndroid Build Coastguard Worker       while (a)
590*2d1272b8SAndroid Build Coastguard Worker       {
591*2d1272b8SAndroid Build Coastguard Worker 	a--;
592*2d1272b8SAndroid Build Coastguard Worker 	count--;
593*2d1272b8SAndroid Build Coastguard Worker 	page_map.arrayZ[count] = page_map.arrayZ[a];
594*2d1272b8SAndroid Build Coastguard Worker       }
595*2d1272b8SAndroid Build Coastguard Worker     if (passthru_right)
596*2d1272b8SAndroid Build Coastguard Worker       while (b)
597*2d1272b8SAndroid Build Coastguard Worker       {
598*2d1272b8SAndroid Build Coastguard Worker 	b--;
599*2d1272b8SAndroid Build Coastguard Worker 	count--;
600*2d1272b8SAndroid Build Coastguard Worker 	page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
601*2d1272b8SAndroid Build Coastguard Worker 	page_map.arrayZ[count].index = next_page++;
602*2d1272b8SAndroid Build Coastguard Worker 	page_at (count) = other.page_at (b);
603*2d1272b8SAndroid Build Coastguard Worker       }
604*2d1272b8SAndroid Build Coastguard Worker     assert (!count);
605*2d1272b8SAndroid Build Coastguard Worker     resize (newCount);
606*2d1272b8SAndroid Build Coastguard Worker   }
607*2d1272b8SAndroid Build Coastguard Worker   template <typename Op>
608*2d1272b8SAndroid Build Coastguard Worker   static hb_bit_page_t::vector_t
op_hb_bit_set_t609*2d1272b8SAndroid Build Coastguard Worker   op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b)
610*2d1272b8SAndroid Build Coastguard Worker   { return Op{} (a, b); }
611*2d1272b8SAndroid Build Coastguard Worker   template <typename Op>
processhb_bit_set_t612*2d1272b8SAndroid Build Coastguard Worker   void process (const Op& op, const hb_bit_set_t &other)
613*2d1272b8SAndroid Build Coastguard Worker   {
614*2d1272b8SAndroid Build Coastguard Worker     process_ (op_<Op>, op (1, 0), op (0, 1), other);
615*2d1272b8SAndroid Build Coastguard Worker   }
616*2d1272b8SAndroid Build Coastguard Worker 
union_hb_bit_set_t617*2d1272b8SAndroid Build Coastguard Worker   void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
intersecthb_bit_set_t618*2d1272b8SAndroid Build Coastguard Worker   void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
subtracthb_bit_set_t619*2d1272b8SAndroid Build Coastguard Worker   void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); }
symmetric_differencehb_bit_set_t620*2d1272b8SAndroid Build Coastguard Worker   void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); }
621*2d1272b8SAndroid Build Coastguard Worker 
nexthb_bit_set_t622*2d1272b8SAndroid Build Coastguard Worker   bool next (hb_codepoint_t *codepoint) const
623*2d1272b8SAndroid Build Coastguard Worker   {
624*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (*codepoint == INVALID)) {
625*2d1272b8SAndroid Build Coastguard Worker       *codepoint = get_min ();
626*2d1272b8SAndroid Build Coastguard Worker       return *codepoint != INVALID;
627*2d1272b8SAndroid Build Coastguard Worker     }
628*2d1272b8SAndroid Build Coastguard Worker 
629*2d1272b8SAndroid Build Coastguard Worker     const auto* page_map_array = page_map.arrayZ;
630*2d1272b8SAndroid Build Coastguard Worker     unsigned int major = get_major (*codepoint);
631*2d1272b8SAndroid Build Coastguard Worker     unsigned int i = last_page_lookup;
632*2d1272b8SAndroid Build Coastguard Worker 
633*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (i >= page_map.length || page_map_array[i].major != major))
634*2d1272b8SAndroid Build Coastguard Worker     {
635*2d1272b8SAndroid Build Coastguard Worker       page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
636*2d1272b8SAndroid Build Coastguard Worker       if (i >= page_map.length) {
637*2d1272b8SAndroid Build Coastguard Worker         *codepoint = INVALID;
638*2d1272b8SAndroid Build Coastguard Worker         return false;
639*2d1272b8SAndroid Build Coastguard Worker       }
640*2d1272b8SAndroid Build Coastguard Worker       last_page_lookup = i;
641*2d1272b8SAndroid Build Coastguard Worker     }
642*2d1272b8SAndroid Build Coastguard Worker 
643*2d1272b8SAndroid Build Coastguard Worker     const auto* pages_array = pages.arrayZ;
644*2d1272b8SAndroid Build Coastguard Worker     const page_map_t &current = page_map_array[i];
645*2d1272b8SAndroid Build Coastguard Worker     if (likely (current.major == major))
646*2d1272b8SAndroid Build Coastguard Worker     {
647*2d1272b8SAndroid Build Coastguard Worker       if (pages_array[current.index].next (codepoint))
648*2d1272b8SAndroid Build Coastguard Worker       {
649*2d1272b8SAndroid Build Coastguard Worker         *codepoint += current.major * page_t::PAGE_BITS;
650*2d1272b8SAndroid Build Coastguard Worker         return true;
651*2d1272b8SAndroid Build Coastguard Worker       }
652*2d1272b8SAndroid Build Coastguard Worker       i++;
653*2d1272b8SAndroid Build Coastguard Worker     }
654*2d1272b8SAndroid Build Coastguard Worker 
655*2d1272b8SAndroid Build Coastguard Worker     for (; i < page_map.length; i++)
656*2d1272b8SAndroid Build Coastguard Worker     {
657*2d1272b8SAndroid Build Coastguard Worker       const page_map_t &current = page_map_array[i];
658*2d1272b8SAndroid Build Coastguard Worker       hb_codepoint_t m = pages_array[current.index].get_min ();
659*2d1272b8SAndroid Build Coastguard Worker       if (m != INVALID)
660*2d1272b8SAndroid Build Coastguard Worker       {
661*2d1272b8SAndroid Build Coastguard Worker 	*codepoint = current.major * page_t::PAGE_BITS + m;
662*2d1272b8SAndroid Build Coastguard Worker         last_page_lookup = i;
663*2d1272b8SAndroid Build Coastguard Worker 	return true;
664*2d1272b8SAndroid Build Coastguard Worker       }
665*2d1272b8SAndroid Build Coastguard Worker     }
666*2d1272b8SAndroid Build Coastguard Worker     *codepoint = INVALID;
667*2d1272b8SAndroid Build Coastguard Worker     return false;
668*2d1272b8SAndroid Build Coastguard Worker   }
previoushb_bit_set_t669*2d1272b8SAndroid Build Coastguard Worker   bool previous (hb_codepoint_t *codepoint) const
670*2d1272b8SAndroid Build Coastguard Worker   {
671*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (*codepoint == INVALID)) {
672*2d1272b8SAndroid Build Coastguard Worker       *codepoint = get_max ();
673*2d1272b8SAndroid Build Coastguard Worker       return *codepoint != INVALID;
674*2d1272b8SAndroid Build Coastguard Worker     }
675*2d1272b8SAndroid Build Coastguard Worker 
676*2d1272b8SAndroid Build Coastguard Worker     page_map_t map = {get_major (*codepoint), 0};
677*2d1272b8SAndroid Build Coastguard Worker     unsigned int i;
678*2d1272b8SAndroid Build Coastguard Worker     page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
679*2d1272b8SAndroid Build Coastguard Worker     if (i < page_map.length && page_map.arrayZ[i].major == map.major)
680*2d1272b8SAndroid Build Coastguard Worker     {
681*2d1272b8SAndroid Build Coastguard Worker       if (pages[page_map.arrayZ[i].index].previous (codepoint))
682*2d1272b8SAndroid Build Coastguard Worker       {
683*2d1272b8SAndroid Build Coastguard Worker 	*codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS;
684*2d1272b8SAndroid Build Coastguard Worker 	return true;
685*2d1272b8SAndroid Build Coastguard Worker       }
686*2d1272b8SAndroid Build Coastguard Worker     }
687*2d1272b8SAndroid Build Coastguard Worker     i--;
688*2d1272b8SAndroid Build Coastguard Worker     for (; (int) i >= 0; i--)
689*2d1272b8SAndroid Build Coastguard Worker     {
690*2d1272b8SAndroid Build Coastguard Worker       hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max ();
691*2d1272b8SAndroid Build Coastguard Worker       if (m != INVALID)
692*2d1272b8SAndroid Build Coastguard Worker       {
693*2d1272b8SAndroid Build Coastguard Worker 	*codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m;
694*2d1272b8SAndroid Build Coastguard Worker 	return true;
695*2d1272b8SAndroid Build Coastguard Worker       }
696*2d1272b8SAndroid Build Coastguard Worker     }
697*2d1272b8SAndroid Build Coastguard Worker     *codepoint = INVALID;
698*2d1272b8SAndroid Build Coastguard Worker     return false;
699*2d1272b8SAndroid Build Coastguard Worker   }
next_rangehb_bit_set_t700*2d1272b8SAndroid Build Coastguard Worker   bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
701*2d1272b8SAndroid Build Coastguard Worker   {
702*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t i;
703*2d1272b8SAndroid Build Coastguard Worker 
704*2d1272b8SAndroid Build Coastguard Worker     i = *last;
705*2d1272b8SAndroid Build Coastguard Worker     if (!next (&i))
706*2d1272b8SAndroid Build Coastguard Worker     {
707*2d1272b8SAndroid Build Coastguard Worker       *last = *first = INVALID;
708*2d1272b8SAndroid Build Coastguard Worker       return false;
709*2d1272b8SAndroid Build Coastguard Worker     }
710*2d1272b8SAndroid Build Coastguard Worker 
711*2d1272b8SAndroid Build Coastguard Worker     /* TODO Speed up. */
712*2d1272b8SAndroid Build Coastguard Worker     *last = *first = i;
713*2d1272b8SAndroid Build Coastguard Worker     while (next (&i) && i == *last + 1)
714*2d1272b8SAndroid Build Coastguard Worker       (*last)++;
715*2d1272b8SAndroid Build Coastguard Worker 
716*2d1272b8SAndroid Build Coastguard Worker     return true;
717*2d1272b8SAndroid Build Coastguard Worker   }
previous_rangehb_bit_set_t718*2d1272b8SAndroid Build Coastguard Worker   bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
719*2d1272b8SAndroid Build Coastguard Worker   {
720*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t i;
721*2d1272b8SAndroid Build Coastguard Worker 
722*2d1272b8SAndroid Build Coastguard Worker     i = *first;
723*2d1272b8SAndroid Build Coastguard Worker     if (!previous (&i))
724*2d1272b8SAndroid Build Coastguard Worker     {
725*2d1272b8SAndroid Build Coastguard Worker       *last = *first = INVALID;
726*2d1272b8SAndroid Build Coastguard Worker       return false;
727*2d1272b8SAndroid Build Coastguard Worker     }
728*2d1272b8SAndroid Build Coastguard Worker 
729*2d1272b8SAndroid Build Coastguard Worker     /* TODO Speed up. */
730*2d1272b8SAndroid Build Coastguard Worker     *last = *first = i;
731*2d1272b8SAndroid Build Coastguard Worker     while (previous (&i) && i == *first - 1)
732*2d1272b8SAndroid Build Coastguard Worker       (*first)--;
733*2d1272b8SAndroid Build Coastguard Worker 
734*2d1272b8SAndroid Build Coastguard Worker     return true;
735*2d1272b8SAndroid Build Coastguard Worker   }
736*2d1272b8SAndroid Build Coastguard Worker 
next_manyhb_bit_set_t737*2d1272b8SAndroid Build Coastguard Worker   unsigned int next_many (hb_codepoint_t  codepoint,
738*2d1272b8SAndroid Build Coastguard Worker 			  hb_codepoint_t *out,
739*2d1272b8SAndroid Build Coastguard Worker 			  unsigned int    size) const
740*2d1272b8SAndroid Build Coastguard Worker   {
741*2d1272b8SAndroid Build Coastguard Worker     // By default, start at the first bit of the first page of values.
742*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_page = 0;
743*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_page_value = 0;
744*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (codepoint != INVALID))
745*2d1272b8SAndroid Build Coastguard Worker     {
746*2d1272b8SAndroid Build Coastguard Worker       const auto* page_map_array = page_map.arrayZ;
747*2d1272b8SAndroid Build Coastguard Worker       unsigned int major = get_major (codepoint);
748*2d1272b8SAndroid Build Coastguard Worker       unsigned int i = last_page_lookup;
749*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (i >= page_map.length || page_map_array[i].major != major))
750*2d1272b8SAndroid Build Coastguard Worker       {
751*2d1272b8SAndroid Build Coastguard Worker 	page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
752*2d1272b8SAndroid Build Coastguard Worker 	if (i >= page_map.length)
753*2d1272b8SAndroid Build Coastguard Worker 	  return 0;  // codepoint is greater than our max element.
754*2d1272b8SAndroid Build Coastguard Worker       }
755*2d1272b8SAndroid Build Coastguard Worker       start_page = i;
756*2d1272b8SAndroid Build Coastguard Worker       start_page_value = page_remainder (codepoint + 1);
757*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (start_page_value == 0))
758*2d1272b8SAndroid Build Coastguard Worker       {
759*2d1272b8SAndroid Build Coastguard Worker         // The export-after value was last in the page. Start on next page.
760*2d1272b8SAndroid Build Coastguard Worker         start_page++;
761*2d1272b8SAndroid Build Coastguard Worker         start_page_value = 0;
762*2d1272b8SAndroid Build Coastguard Worker       }
763*2d1272b8SAndroid Build Coastguard Worker     }
764*2d1272b8SAndroid Build Coastguard Worker 
765*2d1272b8SAndroid Build Coastguard Worker     unsigned int initial_size = size;
766*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = start_page; i < page_map.length && size; i++)
767*2d1272b8SAndroid Build Coastguard Worker     {
768*2d1272b8SAndroid Build Coastguard Worker       uint32_t base = major_start (page_map[i].major);
769*2d1272b8SAndroid Build Coastguard Worker       unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
770*2d1272b8SAndroid Build Coastguard Worker       out += n;
771*2d1272b8SAndroid Build Coastguard Worker       size -= n;
772*2d1272b8SAndroid Build Coastguard Worker       start_page_value = 0;
773*2d1272b8SAndroid Build Coastguard Worker     }
774*2d1272b8SAndroid Build Coastguard Worker     return initial_size - size;
775*2d1272b8SAndroid Build Coastguard Worker   }
776*2d1272b8SAndroid Build Coastguard Worker 
next_many_invertedhb_bit_set_t777*2d1272b8SAndroid Build Coastguard Worker   unsigned int next_many_inverted (hb_codepoint_t  codepoint,
778*2d1272b8SAndroid Build Coastguard Worker 				   hb_codepoint_t *out,
779*2d1272b8SAndroid Build Coastguard Worker 				   unsigned int    size) const
780*2d1272b8SAndroid Build Coastguard Worker   {
781*2d1272b8SAndroid Build Coastguard Worker     unsigned int initial_size = size;
782*2d1272b8SAndroid Build Coastguard Worker     // By default, start at the first bit of the first page of values.
783*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_page = 0;
784*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_page_value = 0;
785*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (codepoint != INVALID))
786*2d1272b8SAndroid Build Coastguard Worker     {
787*2d1272b8SAndroid Build Coastguard Worker       const auto* page_map_array = page_map.arrayZ;
788*2d1272b8SAndroid Build Coastguard Worker       unsigned int major = get_major (codepoint);
789*2d1272b8SAndroid Build Coastguard Worker       unsigned int i = last_page_lookup;
790*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (i >= page_map.length || page_map_array[i].major != major))
791*2d1272b8SAndroid Build Coastguard Worker       {
792*2d1272b8SAndroid Build Coastguard Worker         page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST);
793*2d1272b8SAndroid Build Coastguard Worker         if (unlikely (i >= page_map.length))
794*2d1272b8SAndroid Build Coastguard Worker         {
795*2d1272b8SAndroid Build Coastguard Worker           // codepoint is greater than our max element.
796*2d1272b8SAndroid Build Coastguard Worker           while (++codepoint != INVALID && size)
797*2d1272b8SAndroid Build Coastguard Worker           {
798*2d1272b8SAndroid Build Coastguard Worker             *out++ = codepoint;
799*2d1272b8SAndroid Build Coastguard Worker             size--;
800*2d1272b8SAndroid Build Coastguard Worker           }
801*2d1272b8SAndroid Build Coastguard Worker           return initial_size - size;
802*2d1272b8SAndroid Build Coastguard Worker         }
803*2d1272b8SAndroid Build Coastguard Worker       }
804*2d1272b8SAndroid Build Coastguard Worker       start_page = i;
805*2d1272b8SAndroid Build Coastguard Worker       start_page_value = page_remainder (codepoint + 1);
806*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (start_page_value == 0))
807*2d1272b8SAndroid Build Coastguard Worker       {
808*2d1272b8SAndroid Build Coastguard Worker         // The export-after value was last in the page. Start on next page.
809*2d1272b8SAndroid Build Coastguard Worker         start_page++;
810*2d1272b8SAndroid Build Coastguard Worker         start_page_value = 0;
811*2d1272b8SAndroid Build Coastguard Worker       }
812*2d1272b8SAndroid Build Coastguard Worker     }
813*2d1272b8SAndroid Build Coastguard Worker 
814*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t next_value = codepoint + 1;
815*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i=start_page; i<page_map.length && size; i++)
816*2d1272b8SAndroid Build Coastguard Worker     {
817*2d1272b8SAndroid Build Coastguard Worker       uint32_t base = major_start (page_map[i].major);
818*2d1272b8SAndroid Build Coastguard Worker       unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
819*2d1272b8SAndroid Build Coastguard Worker       out += n;
820*2d1272b8SAndroid Build Coastguard Worker       size -= n;
821*2d1272b8SAndroid Build Coastguard Worker       start_page_value = 0;
822*2d1272b8SAndroid Build Coastguard Worker     }
823*2d1272b8SAndroid Build Coastguard Worker     while (next_value < HB_SET_VALUE_INVALID && size) {
824*2d1272b8SAndroid Build Coastguard Worker       *out++ = next_value++;
825*2d1272b8SAndroid Build Coastguard Worker       size--;
826*2d1272b8SAndroid Build Coastguard Worker     }
827*2d1272b8SAndroid Build Coastguard Worker     return initial_size - size;
828*2d1272b8SAndroid Build Coastguard Worker   }
829*2d1272b8SAndroid Build Coastguard Worker 
has_populationhb_bit_set_t830*2d1272b8SAndroid Build Coastguard Worker   bool has_population () const { return population != UINT_MAX; }
get_populationhb_bit_set_t831*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_population () const
832*2d1272b8SAndroid Build Coastguard Worker   {
833*2d1272b8SAndroid Build Coastguard Worker     if (has_population ())
834*2d1272b8SAndroid Build Coastguard Worker       return population;
835*2d1272b8SAndroid Build Coastguard Worker 
836*2d1272b8SAndroid Build Coastguard Worker     unsigned int pop = 0;
837*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = pages.length;
838*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < count; i++)
839*2d1272b8SAndroid Build Coastguard Worker       pop += pages[i].get_population ();
840*2d1272b8SAndroid Build Coastguard Worker 
841*2d1272b8SAndroid Build Coastguard Worker     population = pop;
842*2d1272b8SAndroid Build Coastguard Worker     return pop;
843*2d1272b8SAndroid Build Coastguard Worker   }
get_minhb_bit_set_t844*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t get_min () const
845*2d1272b8SAndroid Build Coastguard Worker   {
846*2d1272b8SAndroid Build Coastguard Worker     unsigned count = pages.length;
847*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
848*2d1272b8SAndroid Build Coastguard Worker     {
849*2d1272b8SAndroid Build Coastguard Worker       const auto& map = page_map[i];
850*2d1272b8SAndroid Build Coastguard Worker       const auto& page = pages[map.index];
851*2d1272b8SAndroid Build Coastguard Worker 
852*2d1272b8SAndroid Build Coastguard Worker       if (!page.is_empty ())
853*2d1272b8SAndroid Build Coastguard Worker 	return map.major * page_t::PAGE_BITS + page.get_min ();
854*2d1272b8SAndroid Build Coastguard Worker     }
855*2d1272b8SAndroid Build Coastguard Worker     return INVALID;
856*2d1272b8SAndroid Build Coastguard Worker   }
get_maxhb_bit_set_t857*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t get_max () const
858*2d1272b8SAndroid Build Coastguard Worker   {
859*2d1272b8SAndroid Build Coastguard Worker     unsigned count = pages.length;
860*2d1272b8SAndroid Build Coastguard Worker     for (signed i = count - 1; i >= 0; i--)
861*2d1272b8SAndroid Build Coastguard Worker     {
862*2d1272b8SAndroid Build Coastguard Worker       const auto& map = page_map[(unsigned) i];
863*2d1272b8SAndroid Build Coastguard Worker       const auto& page = pages[map.index];
864*2d1272b8SAndroid Build Coastguard Worker 
865*2d1272b8SAndroid Build Coastguard Worker       if (!page.is_empty ())
866*2d1272b8SAndroid Build Coastguard Worker 	return map.major * page_t::PAGE_BITS + page.get_max ();
867*2d1272b8SAndroid Build Coastguard Worker     }
868*2d1272b8SAndroid Build Coastguard Worker     return INVALID;
869*2d1272b8SAndroid Build Coastguard Worker   }
870*2d1272b8SAndroid Build Coastguard Worker 
871*2d1272b8SAndroid Build Coastguard Worker   static constexpr hb_codepoint_t INVALID = page_t::INVALID;
872*2d1272b8SAndroid Build Coastguard Worker 
873*2d1272b8SAndroid Build Coastguard Worker   /*
874*2d1272b8SAndroid Build Coastguard Worker    * Iterator implementation.
875*2d1272b8SAndroid Build Coastguard Worker    */
876*2d1272b8SAndroid Build Coastguard Worker   struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
877*2d1272b8SAndroid Build Coastguard Worker   {
878*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool is_sorted_iterator = true;
879*2d1272b8SAndroid Build Coastguard Worker     static constexpr bool has_fast_len = true;
iter_thb_bit_set_t::iter_t880*2d1272b8SAndroid Build Coastguard Worker     iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
881*2d1272b8SAndroid Build Coastguard Worker 	    bool init = true) : s (&s_), v (INVALID), l(0)
882*2d1272b8SAndroid Build Coastguard Worker     {
883*2d1272b8SAndroid Build Coastguard Worker       if (init)
884*2d1272b8SAndroid Build Coastguard Worker       {
885*2d1272b8SAndroid Build Coastguard Worker 	l = s->get_population () + 1;
886*2d1272b8SAndroid Build Coastguard Worker 	__next__ ();
887*2d1272b8SAndroid Build Coastguard Worker       }
888*2d1272b8SAndroid Build Coastguard Worker     }
889*2d1272b8SAndroid Build Coastguard Worker 
890*2d1272b8SAndroid Build Coastguard Worker     typedef hb_codepoint_t __item_t__;
__item__hb_bit_set_t::iter_t891*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t __item__ () const { return v; }
__more__hb_bit_set_t::iter_t892*2d1272b8SAndroid Build Coastguard Worker     bool __more__ () const { return v != INVALID; }
__next__hb_bit_set_t::iter_t893*2d1272b8SAndroid Build Coastguard Worker     void __next__ () { s->next (&v); if (l) l--; }
__prev__hb_bit_set_t::iter_t894*2d1272b8SAndroid Build Coastguard Worker     void __prev__ () { s->previous (&v); }
__len__hb_bit_set_t::iter_t895*2d1272b8SAndroid Build Coastguard Worker     unsigned __len__ () const { return l; }
endhb_bit_set_t::iter_t896*2d1272b8SAndroid Build Coastguard Worker     iter_t end () const { return iter_t (*s, false); }
operator !=hb_bit_set_t::iter_t897*2d1272b8SAndroid Build Coastguard Worker     bool operator != (const iter_t& o) const
898*2d1272b8SAndroid Build Coastguard Worker     { return s != o.s || v != o.v; }
899*2d1272b8SAndroid Build Coastguard Worker 
900*2d1272b8SAndroid Build Coastguard Worker     protected:
901*2d1272b8SAndroid Build Coastguard Worker     const hb_bit_set_t *s;
902*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t v;
903*2d1272b8SAndroid Build Coastguard Worker     unsigned l;
904*2d1272b8SAndroid Build Coastguard Worker   };
iterhb_bit_set_t905*2d1272b8SAndroid Build Coastguard Worker   iter_t iter () const { return iter_t (*this); }
operator iter_thb_bit_set_t906*2d1272b8SAndroid Build Coastguard Worker   operator iter_t () const { return iter (); }
907*2d1272b8SAndroid Build Coastguard Worker 
908*2d1272b8SAndroid Build Coastguard Worker   protected:
909*2d1272b8SAndroid Build Coastguard Worker 
page_forhb_bit_set_t910*2d1272b8SAndroid Build Coastguard Worker   page_t *page_for (hb_codepoint_t g, bool insert = false)
911*2d1272b8SAndroid Build Coastguard Worker   {
912*2d1272b8SAndroid Build Coastguard Worker     unsigned major = get_major (g);
913*2d1272b8SAndroid Build Coastguard Worker 
914*2d1272b8SAndroid Build Coastguard Worker     /* The extra page_map length is necessary; can't just rely on vector here,
915*2d1272b8SAndroid Build Coastguard Worker      * since the next check would be tricked because a null page also has
916*2d1272b8SAndroid Build Coastguard Worker      * major==0, which we can't distinguish from an actually major==0 page... */
917*2d1272b8SAndroid Build Coastguard Worker     unsigned i = last_page_lookup;
918*2d1272b8SAndroid Build Coastguard Worker     if (likely (i < page_map.length))
919*2d1272b8SAndroid Build Coastguard Worker     {
920*2d1272b8SAndroid Build Coastguard Worker       auto &cached_page = page_map.arrayZ[i];
921*2d1272b8SAndroid Build Coastguard Worker       if (cached_page.major == major)
922*2d1272b8SAndroid Build Coastguard Worker 	return &pages.arrayZ[cached_page.index];
923*2d1272b8SAndroid Build Coastguard Worker     }
924*2d1272b8SAndroid Build Coastguard Worker 
925*2d1272b8SAndroid Build Coastguard Worker     page_map_t map = {major, pages.length};
926*2d1272b8SAndroid Build Coastguard Worker     if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
927*2d1272b8SAndroid Build Coastguard Worker     {
928*2d1272b8SAndroid Build Coastguard Worker       if (!insert)
929*2d1272b8SAndroid Build Coastguard Worker         return nullptr;
930*2d1272b8SAndroid Build Coastguard Worker 
931*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!resize (pages.length + 1)))
932*2d1272b8SAndroid Build Coastguard Worker 	return nullptr;
933*2d1272b8SAndroid Build Coastguard Worker 
934*2d1272b8SAndroid Build Coastguard Worker       pages.arrayZ[map.index].init0 ();
935*2d1272b8SAndroid Build Coastguard Worker       memmove (page_map.arrayZ + i + 1,
936*2d1272b8SAndroid Build Coastguard Worker 	       page_map.arrayZ + i,
937*2d1272b8SAndroid Build Coastguard Worker 	       (page_map.length - 1 - i) * page_map.item_size);
938*2d1272b8SAndroid Build Coastguard Worker       page_map.arrayZ[i] = map;
939*2d1272b8SAndroid Build Coastguard Worker     }
940*2d1272b8SAndroid Build Coastguard Worker 
941*2d1272b8SAndroid Build Coastguard Worker     last_page_lookup = i;
942*2d1272b8SAndroid Build Coastguard Worker     return &pages.arrayZ[page_map.arrayZ[i].index];
943*2d1272b8SAndroid Build Coastguard Worker   }
page_forhb_bit_set_t944*2d1272b8SAndroid Build Coastguard Worker   const page_t *page_for (hb_codepoint_t g) const
945*2d1272b8SAndroid Build Coastguard Worker   {
946*2d1272b8SAndroid Build Coastguard Worker     unsigned major = get_major (g);
947*2d1272b8SAndroid Build Coastguard Worker 
948*2d1272b8SAndroid Build Coastguard Worker     /* The extra page_map length is necessary; can't just rely on vector here,
949*2d1272b8SAndroid Build Coastguard Worker      * since the next check would be tricked because a null page also has
950*2d1272b8SAndroid Build Coastguard Worker      * major==0, which we can't distinguish from an actually major==0 page... */
951*2d1272b8SAndroid Build Coastguard Worker     unsigned i = last_page_lookup;
952*2d1272b8SAndroid Build Coastguard Worker     if (likely (i < page_map.length))
953*2d1272b8SAndroid Build Coastguard Worker     {
954*2d1272b8SAndroid Build Coastguard Worker       auto &cached_page = page_map.arrayZ[i];
955*2d1272b8SAndroid Build Coastguard Worker       if (cached_page.major == major)
956*2d1272b8SAndroid Build Coastguard Worker 	return &pages.arrayZ[cached_page.index];
957*2d1272b8SAndroid Build Coastguard Worker     }
958*2d1272b8SAndroid Build Coastguard Worker 
959*2d1272b8SAndroid Build Coastguard Worker     page_map_t key = {major};
960*2d1272b8SAndroid Build Coastguard Worker     if (!page_map.bfind (key, &i))
961*2d1272b8SAndroid Build Coastguard Worker       return nullptr;
962*2d1272b8SAndroid Build Coastguard Worker 
963*2d1272b8SAndroid Build Coastguard Worker     last_page_lookup = i;
964*2d1272b8SAndroid Build Coastguard Worker     return &pages.arrayZ[page_map[i].index];
965*2d1272b8SAndroid Build Coastguard Worker   }
page_athb_bit_set_t966*2d1272b8SAndroid Build Coastguard Worker   page_t &page_at (unsigned int i)
967*2d1272b8SAndroid Build Coastguard Worker   {
968*2d1272b8SAndroid Build Coastguard Worker     assert (i < page_map.length);
969*2d1272b8SAndroid Build Coastguard Worker     return pages.arrayZ[page_map.arrayZ[i].index];
970*2d1272b8SAndroid Build Coastguard Worker   }
page_athb_bit_set_t971*2d1272b8SAndroid Build Coastguard Worker   const page_t &page_at (unsigned int i) const
972*2d1272b8SAndroid Build Coastguard Worker   {
973*2d1272b8SAndroid Build Coastguard Worker     assert (i < page_map.length);
974*2d1272b8SAndroid Build Coastguard Worker     return pages.arrayZ[page_map.arrayZ[i].index];
975*2d1272b8SAndroid Build Coastguard Worker   }
get_majorhb_bit_set_t976*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; }
page_remainderhb_bit_set_t977*2d1272b8SAndroid Build Coastguard Worker   unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; }
major_starthb_bit_set_t978*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; }
979*2d1272b8SAndroid Build Coastguard Worker };
980*2d1272b8SAndroid Build Coastguard Worker 
981*2d1272b8SAndroid Build Coastguard Worker 
982*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_BIT_SET_HH */
983