xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-bit-page.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_PAGE_HH
29*2d1272b8SAndroid Build Coastguard Worker #define HB_BIT_PAGE_HH
30*2d1272b8SAndroid Build Coastguard Worker 
31*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
32*2d1272b8SAndroid Build Coastguard Worker 
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker /* Compiler-assisted vectorization. */
35*2d1272b8SAndroid Build Coastguard Worker 
36*2d1272b8SAndroid Build Coastguard Worker /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
37*2d1272b8SAndroid Build Coastguard Worker  * basically a fixed-size bitset. We can't use the compiler type because hb_vector_t cannot
38*2d1272b8SAndroid Build Coastguard Worker  * guarantee alignment requirements. */
39*2d1272b8SAndroid Build Coastguard Worker template <typename elt_t, unsigned int byte_size>
40*2d1272b8SAndroid Build Coastguard Worker struct hb_vector_size_t
41*2d1272b8SAndroid Build Coastguard Worker {
operator []hb_vector_size_t42*2d1272b8SAndroid Build Coastguard Worker   elt_t& operator [] (unsigned int i) { return v[i]; }
operator []hb_vector_size_t43*2d1272b8SAndroid Build Coastguard Worker   const elt_t& operator [] (unsigned int i) const { return v[i]; }
44*2d1272b8SAndroid Build Coastguard Worker 
init0hb_vector_size_t45*2d1272b8SAndroid Build Coastguard Worker   void init0 ()
46*2d1272b8SAndroid Build Coastguard Worker   {
47*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
48*2d1272b8SAndroid Build Coastguard Worker       v[i] = 0;
49*2d1272b8SAndroid Build Coastguard Worker   }
init1hb_vector_size_t50*2d1272b8SAndroid Build Coastguard Worker   void init1 ()
51*2d1272b8SAndroid Build Coastguard Worker   {
52*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
53*2d1272b8SAndroid Build Coastguard Worker       v[i] = (elt_t) -1;
54*2d1272b8SAndroid Build Coastguard Worker   }
55*2d1272b8SAndroid Build Coastguard Worker 
56*2d1272b8SAndroid Build Coastguard Worker   template <typename Op>
processhb_vector_size_t57*2d1272b8SAndroid Build Coastguard Worker   hb_vector_size_t process (const Op& op) const
58*2d1272b8SAndroid Build Coastguard Worker   {
59*2d1272b8SAndroid Build Coastguard Worker     hb_vector_size_t r;
60*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
61*2d1272b8SAndroid Build Coastguard Worker       r.v[i] = op (v[i]);
62*2d1272b8SAndroid Build Coastguard Worker     return r;
63*2d1272b8SAndroid Build Coastguard Worker   }
64*2d1272b8SAndroid Build Coastguard Worker   template <typename Op>
processhb_vector_size_t65*2d1272b8SAndroid Build Coastguard Worker   hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
66*2d1272b8SAndroid Build Coastguard Worker   {
67*2d1272b8SAndroid Build Coastguard Worker     hb_vector_size_t r;
68*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
69*2d1272b8SAndroid Build Coastguard Worker       r.v[i] = op (v[i], o.v[i]);
70*2d1272b8SAndroid Build Coastguard Worker     return r;
71*2d1272b8SAndroid Build Coastguard Worker   }
operator |hb_vector_size_t72*2d1272b8SAndroid Build Coastguard Worker   hb_vector_size_t operator | (const hb_vector_size_t &o) const
73*2d1272b8SAndroid Build Coastguard Worker   { return process (hb_bitwise_or, o); }
operator &hb_vector_size_t74*2d1272b8SAndroid Build Coastguard Worker   hb_vector_size_t operator & (const hb_vector_size_t &o) const
75*2d1272b8SAndroid Build Coastguard Worker   { return process (hb_bitwise_and, o); }
operator ^hb_vector_size_t76*2d1272b8SAndroid Build Coastguard Worker   hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
77*2d1272b8SAndroid Build Coastguard Worker   { return process (hb_bitwise_xor, o); }
operator ~hb_vector_size_t78*2d1272b8SAndroid Build Coastguard Worker   hb_vector_size_t operator ~ () const
79*2d1272b8SAndroid Build Coastguard Worker   { return process (hb_bitwise_neg); }
80*2d1272b8SAndroid Build Coastguard Worker 
iterhb_vector_size_t81*2d1272b8SAndroid Build Coastguard Worker   hb_array_t<const elt_t> iter () const
82*2d1272b8SAndroid Build Coastguard Worker   { return hb_array (v); }
83*2d1272b8SAndroid Build Coastguard Worker 
84*2d1272b8SAndroid Build Coastguard Worker   private:
85*2d1272b8SAndroid Build Coastguard Worker   static_assert (0 == byte_size % sizeof (elt_t), "");
86*2d1272b8SAndroid Build Coastguard Worker   elt_t v[byte_size / sizeof (elt_t)];
87*2d1272b8SAndroid Build Coastguard Worker };
88*2d1272b8SAndroid Build Coastguard Worker 
89*2d1272b8SAndroid Build Coastguard Worker 
90*2d1272b8SAndroid Build Coastguard Worker struct hb_bit_page_t
91*2d1272b8SAndroid Build Coastguard Worker {
init0hb_bit_page_t92*2d1272b8SAndroid Build Coastguard Worker   void init0 () { v.init0 (); population = 0; }
init1hb_bit_page_t93*2d1272b8SAndroid Build Coastguard Worker   void init1 () { v.init1 (); population = PAGE_BITS; }
94*2d1272b8SAndroid Build Coastguard Worker 
dirtyhb_bit_page_t95*2d1272b8SAndroid Build Coastguard Worker   void dirty () { population = UINT_MAX; }
96*2d1272b8SAndroid Build Coastguard Worker 
lenhb_bit_page_t97*2d1272b8SAndroid Build Coastguard Worker   static inline constexpr unsigned len ()
98*2d1272b8SAndroid Build Coastguard Worker   { return ARRAY_LENGTH_CONST (v); }
99*2d1272b8SAndroid Build Coastguard Worker 
operator boolhb_bit_page_t100*2d1272b8SAndroid Build Coastguard Worker   operator bool () const { return !is_empty (); }
is_emptyhb_bit_page_t101*2d1272b8SAndroid Build Coastguard Worker   bool is_empty () const
102*2d1272b8SAndroid Build Coastguard Worker   {
103*2d1272b8SAndroid Build Coastguard Worker     if (has_population ()) return !population;
104*2d1272b8SAndroid Build Coastguard Worker     return
105*2d1272b8SAndroid Build Coastguard Worker     + hb_iter (v)
106*2d1272b8SAndroid Build Coastguard Worker     | hb_none
107*2d1272b8SAndroid Build Coastguard Worker     ;
108*2d1272b8SAndroid Build Coastguard Worker   }
hashhb_bit_page_t109*2d1272b8SAndroid Build Coastguard Worker   uint32_t hash () const
110*2d1272b8SAndroid Build Coastguard Worker   {
111*2d1272b8SAndroid Build Coastguard Worker     return hb_bytes_t ((const char *) &v, sizeof (v)).hash ();
112*2d1272b8SAndroid Build Coastguard Worker   }
113*2d1272b8SAndroid Build Coastguard Worker 
addhb_bit_page_t114*2d1272b8SAndroid Build Coastguard Worker   void add (hb_codepoint_t g) { elt (g) |= mask (g); dirty (); }
delhb_bit_page_t115*2d1272b8SAndroid Build Coastguard Worker   void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); }
sethb_bit_page_t116*2d1272b8SAndroid Build Coastguard Worker   void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
gethb_bit_page_t117*2d1272b8SAndroid Build Coastguard Worker   bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
118*2d1272b8SAndroid Build Coastguard Worker 
add_rangehb_bit_page_t119*2d1272b8SAndroid Build Coastguard Worker   void add_range (hb_codepoint_t a, hb_codepoint_t b)
120*2d1272b8SAndroid Build Coastguard Worker   {
121*2d1272b8SAndroid Build Coastguard Worker     elt_t *la = &elt (a);
122*2d1272b8SAndroid Build Coastguard Worker     elt_t *lb = &elt (b);
123*2d1272b8SAndroid Build Coastguard Worker     if (la == lb)
124*2d1272b8SAndroid Build Coastguard Worker       *la |= (mask (b) << 1) - mask(a);
125*2d1272b8SAndroid Build Coastguard Worker     else
126*2d1272b8SAndroid Build Coastguard Worker     {
127*2d1272b8SAndroid Build Coastguard Worker       *la |= ~(mask (a) - 1llu);
128*2d1272b8SAndroid Build Coastguard Worker       la++;
129*2d1272b8SAndroid Build Coastguard Worker 
130*2d1272b8SAndroid Build Coastguard Worker       hb_memset (la, 0xff, (char *) lb - (char *) la);
131*2d1272b8SAndroid Build Coastguard Worker 
132*2d1272b8SAndroid Build Coastguard Worker       *lb |= ((mask (b) << 1) - 1llu);
133*2d1272b8SAndroid Build Coastguard Worker     }
134*2d1272b8SAndroid Build Coastguard Worker     dirty ();
135*2d1272b8SAndroid Build Coastguard Worker   }
del_rangehb_bit_page_t136*2d1272b8SAndroid Build Coastguard Worker   void del_range (hb_codepoint_t a, hb_codepoint_t b)
137*2d1272b8SAndroid Build Coastguard Worker   {
138*2d1272b8SAndroid Build Coastguard Worker     elt_t *la = &elt (a);
139*2d1272b8SAndroid Build Coastguard Worker     elt_t *lb = &elt (b);
140*2d1272b8SAndroid Build Coastguard Worker     if (la == lb)
141*2d1272b8SAndroid Build Coastguard Worker       *la &= ~((mask (b) << 1llu) - mask(a));
142*2d1272b8SAndroid Build Coastguard Worker     else
143*2d1272b8SAndroid Build Coastguard Worker     {
144*2d1272b8SAndroid Build Coastguard Worker       *la &= mask (a) - 1;
145*2d1272b8SAndroid Build Coastguard Worker       la++;
146*2d1272b8SAndroid Build Coastguard Worker 
147*2d1272b8SAndroid Build Coastguard Worker       hb_memset (la, 0, (char *) lb - (char *) la);
148*2d1272b8SAndroid Build Coastguard Worker 
149*2d1272b8SAndroid Build Coastguard Worker       *lb &= ~((mask (b) << 1) - 1llu);
150*2d1272b8SAndroid Build Coastguard Worker     }
151*2d1272b8SAndroid Build Coastguard Worker     dirty ();
152*2d1272b8SAndroid Build Coastguard Worker   }
set_rangehb_bit_page_t153*2d1272b8SAndroid Build Coastguard Worker   void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
154*2d1272b8SAndroid Build Coastguard Worker   { if (v) add_range (a, b); else del_range (a, b); }
155*2d1272b8SAndroid Build Coastguard Worker 
156*2d1272b8SAndroid Build Coastguard Worker 
157*2d1272b8SAndroid Build Coastguard Worker   // Writes out page values to the array p. Returns the number of values
158*2d1272b8SAndroid Build Coastguard Worker   // written. At most size codepoints will be written.
writehb_bit_page_t159*2d1272b8SAndroid Build Coastguard Worker   unsigned int write (uint32_t        base,
160*2d1272b8SAndroid Build Coastguard Worker 		      unsigned int    start_value,
161*2d1272b8SAndroid Build Coastguard Worker 		      hb_codepoint_t *p,
162*2d1272b8SAndroid Build Coastguard Worker 		      unsigned int    size) const
163*2d1272b8SAndroid Build Coastguard Worker   {
164*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_v = start_value / ELT_BITS;
165*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_bit = start_value & ELT_MASK;
166*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = 0;
167*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = start_v; i < len () && count < size; i++)
168*2d1272b8SAndroid Build Coastguard Worker     {
169*2d1272b8SAndroid Build Coastguard Worker       elt_t bits = v[i];
170*2d1272b8SAndroid Build Coastguard Worker       uint32_t v_base = base | (i * ELT_BITS);
171*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
172*2d1272b8SAndroid Build Coastguard Worker       {
173*2d1272b8SAndroid Build Coastguard Worker 	if ((elt_t(1) << j) & bits) {
174*2d1272b8SAndroid Build Coastguard Worker 	  *p++ = v_base | j;
175*2d1272b8SAndroid Build Coastguard Worker 	  count++;
176*2d1272b8SAndroid Build Coastguard Worker 	}
177*2d1272b8SAndroid Build Coastguard Worker       }
178*2d1272b8SAndroid Build Coastguard Worker       start_bit = 0;
179*2d1272b8SAndroid Build Coastguard Worker     }
180*2d1272b8SAndroid Build Coastguard Worker     return count;
181*2d1272b8SAndroid Build Coastguard Worker   }
182*2d1272b8SAndroid Build Coastguard Worker 
183*2d1272b8SAndroid Build Coastguard Worker   // Writes out the values NOT in this page to the array p. Returns the
184*2d1272b8SAndroid Build Coastguard Worker   // number of values written. At most size codepoints will be written.
185*2d1272b8SAndroid Build Coastguard Worker   // Returns the number of codepoints written. next_value holds the next value
186*2d1272b8SAndroid Build Coastguard Worker   // that should be written (if not present in this page). This is used to fill
187*2d1272b8SAndroid Build Coastguard Worker   // any missing value gaps between this page and the previous page, if any.
188*2d1272b8SAndroid Build Coastguard Worker   // next_value is updated to one more than the last value present in this page.
write_invertedhb_bit_page_t189*2d1272b8SAndroid Build Coastguard Worker   unsigned int write_inverted (uint32_t        base,
190*2d1272b8SAndroid Build Coastguard Worker 			       unsigned int    start_value,
191*2d1272b8SAndroid Build Coastguard Worker 			       hb_codepoint_t *p,
192*2d1272b8SAndroid Build Coastguard Worker 			       unsigned int    size,
193*2d1272b8SAndroid Build Coastguard Worker 			       hb_codepoint_t *next_value) const
194*2d1272b8SAndroid Build Coastguard Worker   {
195*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_v = start_value / ELT_BITS;
196*2d1272b8SAndroid Build Coastguard Worker     unsigned int start_bit = start_value & ELT_MASK;
197*2d1272b8SAndroid Build Coastguard Worker     unsigned int count = 0;
198*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = start_v; i < len () && count < size; i++)
199*2d1272b8SAndroid Build Coastguard Worker     {
200*2d1272b8SAndroid Build Coastguard Worker       elt_t bits = v[i];
201*2d1272b8SAndroid Build Coastguard Worker       uint32_t v_offset = i * ELT_BITS;
202*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++)
203*2d1272b8SAndroid Build Coastguard Worker       {
204*2d1272b8SAndroid Build Coastguard Worker 	if ((elt_t(1) << j) & bits)
205*2d1272b8SAndroid Build Coastguard Worker 	{
206*2d1272b8SAndroid Build Coastguard Worker 	  hb_codepoint_t value = base | v_offset | j;
207*2d1272b8SAndroid Build Coastguard Worker 	  // Emit all the missing values from next_value up to value - 1.
208*2d1272b8SAndroid Build Coastguard Worker 	  for (hb_codepoint_t k = *next_value; k < value && count < size; k++)
209*2d1272b8SAndroid Build Coastguard Worker 	  {
210*2d1272b8SAndroid Build Coastguard Worker 	    *p++ = k;
211*2d1272b8SAndroid Build Coastguard Worker 	    count++;
212*2d1272b8SAndroid Build Coastguard Worker 	  }
213*2d1272b8SAndroid Build Coastguard Worker 	  // Skip over this value;
214*2d1272b8SAndroid Build Coastguard Worker 	  *next_value = value + 1;
215*2d1272b8SAndroid Build Coastguard Worker 	}
216*2d1272b8SAndroid Build Coastguard Worker       }
217*2d1272b8SAndroid Build Coastguard Worker       start_bit = 0;
218*2d1272b8SAndroid Build Coastguard Worker     }
219*2d1272b8SAndroid Build Coastguard Worker     return count;
220*2d1272b8SAndroid Build Coastguard Worker   }
221*2d1272b8SAndroid Build Coastguard Worker 
operator ==hb_bit_page_t222*2d1272b8SAndroid Build Coastguard Worker   bool operator == (const hb_bit_page_t &other) const { return is_equal (other); }
is_equalhb_bit_page_t223*2d1272b8SAndroid Build Coastguard Worker   bool is_equal (const hb_bit_page_t &other) const
224*2d1272b8SAndroid Build Coastguard Worker   {
225*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < len (); i++)
226*2d1272b8SAndroid Build Coastguard Worker       if (v[i] != other.v[i])
227*2d1272b8SAndroid Build Coastguard Worker 	return false;
228*2d1272b8SAndroid Build Coastguard Worker     return true;
229*2d1272b8SAndroid Build Coastguard Worker   }
operator <=hb_bit_page_t230*2d1272b8SAndroid Build Coastguard Worker   bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); }
is_subsethb_bit_page_t231*2d1272b8SAndroid Build Coastguard Worker   bool is_subset (const hb_bit_page_t &larger_page) const
232*2d1272b8SAndroid Build Coastguard Worker   {
233*2d1272b8SAndroid Build Coastguard Worker     if (has_population () && larger_page.has_population () &&
234*2d1272b8SAndroid Build Coastguard Worker 	population > larger_page.population)
235*2d1272b8SAndroid Build Coastguard Worker       return false;
236*2d1272b8SAndroid Build Coastguard Worker 
237*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < len (); i++)
238*2d1272b8SAndroid Build Coastguard Worker       if (~larger_page.v[i] & v[i])
239*2d1272b8SAndroid Build Coastguard Worker 	return false;
240*2d1272b8SAndroid Build Coastguard Worker     return true;
241*2d1272b8SAndroid Build Coastguard Worker   }
242*2d1272b8SAndroid Build Coastguard Worker 
has_populationhb_bit_page_t243*2d1272b8SAndroid Build Coastguard Worker   bool has_population () const { return population != UINT_MAX; }
get_populationhb_bit_page_t244*2d1272b8SAndroid Build Coastguard Worker   unsigned int get_population () const
245*2d1272b8SAndroid Build Coastguard Worker   {
246*2d1272b8SAndroid Build Coastguard Worker     if (has_population ()) return population;
247*2d1272b8SAndroid Build Coastguard Worker     population =
248*2d1272b8SAndroid Build Coastguard Worker     + hb_iter (v)
249*2d1272b8SAndroid Build Coastguard Worker     | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
250*2d1272b8SAndroid Build Coastguard Worker     ;
251*2d1272b8SAndroid Build Coastguard Worker     return population;
252*2d1272b8SAndroid Build Coastguard Worker   }
253*2d1272b8SAndroid Build Coastguard Worker 
nexthb_bit_page_t254*2d1272b8SAndroid Build Coastguard Worker   bool next (hb_codepoint_t *codepoint) const
255*2d1272b8SAndroid Build Coastguard Worker   {
256*2d1272b8SAndroid Build Coastguard Worker     unsigned int m = (*codepoint + 1) & MASK;
257*2d1272b8SAndroid Build Coastguard Worker     if (!m)
258*2d1272b8SAndroid Build Coastguard Worker     {
259*2d1272b8SAndroid Build Coastguard Worker       *codepoint = INVALID;
260*2d1272b8SAndroid Build Coastguard Worker       return false;
261*2d1272b8SAndroid Build Coastguard Worker     }
262*2d1272b8SAndroid Build Coastguard Worker     unsigned int i = m / ELT_BITS;
263*2d1272b8SAndroid Build Coastguard Worker     unsigned int j = m & ELT_MASK;
264*2d1272b8SAndroid Build Coastguard Worker 
265*2d1272b8SAndroid Build Coastguard Worker     const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
266*2d1272b8SAndroid Build Coastguard Worker     for (const elt_t *p = &vv; i < len (); p = &v[++i])
267*2d1272b8SAndroid Build Coastguard Worker       if (*p)
268*2d1272b8SAndroid Build Coastguard Worker       {
269*2d1272b8SAndroid Build Coastguard Worker 	*codepoint = i * ELT_BITS + elt_get_min (*p);
270*2d1272b8SAndroid Build Coastguard Worker 	return true;
271*2d1272b8SAndroid Build Coastguard Worker       }
272*2d1272b8SAndroid Build Coastguard Worker 
273*2d1272b8SAndroid Build Coastguard Worker     *codepoint = INVALID;
274*2d1272b8SAndroid Build Coastguard Worker     return false;
275*2d1272b8SAndroid Build Coastguard Worker   }
previoushb_bit_page_t276*2d1272b8SAndroid Build Coastguard Worker   bool previous (hb_codepoint_t *codepoint) const
277*2d1272b8SAndroid Build Coastguard Worker   {
278*2d1272b8SAndroid Build Coastguard Worker     unsigned int m = (*codepoint - 1) & MASK;
279*2d1272b8SAndroid Build Coastguard Worker     if (m == MASK)
280*2d1272b8SAndroid Build Coastguard Worker     {
281*2d1272b8SAndroid Build Coastguard Worker       *codepoint = INVALID;
282*2d1272b8SAndroid Build Coastguard Worker       return false;
283*2d1272b8SAndroid Build Coastguard Worker     }
284*2d1272b8SAndroid Build Coastguard Worker     unsigned int i = m / ELT_BITS;
285*2d1272b8SAndroid Build Coastguard Worker     unsigned int j = m & ELT_MASK;
286*2d1272b8SAndroid Build Coastguard Worker 
287*2d1272b8SAndroid Build Coastguard Worker     /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
288*2d1272b8SAndroid Build Coastguard Worker     const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
289*2d1272b8SAndroid Build Coastguard Worker 		       ((elt_t (1) << (j + 1)) - 1) :
290*2d1272b8SAndroid Build Coastguard Worker 		       (elt_t) -1;
291*2d1272b8SAndroid Build Coastguard Worker     const elt_t vv = v[i] & mask;
292*2d1272b8SAndroid Build Coastguard Worker     const elt_t *p = &vv;
293*2d1272b8SAndroid Build Coastguard Worker     while (true)
294*2d1272b8SAndroid Build Coastguard Worker     {
295*2d1272b8SAndroid Build Coastguard Worker       if (*p)
296*2d1272b8SAndroid Build Coastguard Worker       {
297*2d1272b8SAndroid Build Coastguard Worker 	*codepoint = i * ELT_BITS + elt_get_max (*p);
298*2d1272b8SAndroid Build Coastguard Worker 	return true;
299*2d1272b8SAndroid Build Coastguard Worker       }
300*2d1272b8SAndroid Build Coastguard Worker       if ((int) i <= 0) break;
301*2d1272b8SAndroid Build Coastguard Worker       p = &v[--i];
302*2d1272b8SAndroid Build Coastguard Worker     }
303*2d1272b8SAndroid Build Coastguard Worker 
304*2d1272b8SAndroid Build Coastguard Worker     *codepoint = INVALID;
305*2d1272b8SAndroid Build Coastguard Worker     return false;
306*2d1272b8SAndroid Build Coastguard Worker   }
get_minhb_bit_page_t307*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t get_min () const
308*2d1272b8SAndroid Build Coastguard Worker   {
309*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < len (); i++)
310*2d1272b8SAndroid Build Coastguard Worker       if (v[i])
311*2d1272b8SAndroid Build Coastguard Worker 	return i * ELT_BITS + elt_get_min (v[i]);
312*2d1272b8SAndroid Build Coastguard Worker     return INVALID;
313*2d1272b8SAndroid Build Coastguard Worker   }
get_maxhb_bit_page_t314*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t get_max () const
315*2d1272b8SAndroid Build Coastguard Worker   {
316*2d1272b8SAndroid Build Coastguard Worker     for (int i = len () - 1; i >= 0; i--)
317*2d1272b8SAndroid Build Coastguard Worker       if (v[i])
318*2d1272b8SAndroid Build Coastguard Worker 	return i * ELT_BITS + elt_get_max (v[i]);
319*2d1272b8SAndroid Build Coastguard Worker     return 0;
320*2d1272b8SAndroid Build Coastguard Worker   }
321*2d1272b8SAndroid Build Coastguard Worker 
322*2d1272b8SAndroid Build Coastguard Worker   static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
323*2d1272b8SAndroid Build Coastguard Worker 
324*2d1272b8SAndroid Build Coastguard Worker   typedef unsigned long long elt_t;
325*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits
326*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2;
327*2d1272b8SAndroid Build Coastguard Worker   static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
328*2d1272b8SAndroid Build Coastguard Worker   static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
329*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1;
330*2d1272b8SAndroid Build Coastguard Worker 
elt_get_minhb_bit_page_t331*2d1272b8SAndroid Build Coastguard Worker   static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
elt_get_maxhb_bit_page_t332*2d1272b8SAndroid Build Coastguard Worker   static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
333*2d1272b8SAndroid Build Coastguard Worker 
334*2d1272b8SAndroid Build Coastguard Worker   typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
335*2d1272b8SAndroid Build Coastguard Worker 
336*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
337*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned ELT_MASK = ELT_BITS - 1;
338*2d1272b8SAndroid Build Coastguard Worker 
339*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned BITS = sizeof (vector_t) * 8;
340*2d1272b8SAndroid Build Coastguard Worker   static constexpr unsigned MASK = BITS - 1;
341*2d1272b8SAndroid Build Coastguard Worker   static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
342*2d1272b8SAndroid Build Coastguard Worker 
elthb_bit_page_t343*2d1272b8SAndroid Build Coastguard Worker   elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
elthb_bit_page_t344*2d1272b8SAndroid Build Coastguard Worker   const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
maskhb_bit_page_t345*2d1272b8SAndroid Build Coastguard Worker   static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
346*2d1272b8SAndroid Build Coastguard Worker 
347*2d1272b8SAndroid Build Coastguard Worker   mutable unsigned population;
348*2d1272b8SAndroid Build Coastguard Worker   vector_t v;
349*2d1272b8SAndroid Build Coastguard Worker };
350*2d1272b8SAndroid Build Coastguard Worker 
351*2d1272b8SAndroid Build Coastguard Worker 
352*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_BIT_PAGE_HH */
353