hb-set-private.hh 14.7 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2012,2017  Google, Inc.
B
Behdad Esfahbod 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Google Author(s): Behdad Esfahbod
 */

#ifndef HB_SET_PRIVATE_HH
#define HB_SET_PRIVATE_HH

#include "hb-private.hh"
#include "hb-object-private.hh"


B
Behdad Esfahbod 已提交
34 35 36
/*
 * hb_set_t
 */
B
Behdad Esfahbod 已提交
37

38 39 40
/* TODO Keep a free-list so we can free pages that are completely zeroed.  At that
 * point maybe also use a sentinel value for "all-1" pages? */

41
struct hb_set_t
B
Behdad Esfahbod 已提交
42
{
B
Behdad Esfahbod 已提交
43 44 45 46 47 48 49 50 51 52
  struct page_map_t
  {
    inline int cmp (const page_map_t *o) const { return (int) o->major - (int) major; }

    uint32_t major;
    uint32_t index;
  };

  struct page_t
  {
B
Behdad Esfahbod 已提交
53 54
    inline void init0 (void) { memset (&v, 0, sizeof (v)); }
    inline void init1 (void) { memset (&v, 0xff, sizeof (v)); }
B
Behdad Esfahbod 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

    inline unsigned int len (void) const
    { return ARRAY_LENGTH_CONST (v); }

    inline bool is_empty (void) const
    {
      for (unsigned int i = 0; i < len (); i++)
        if (v[i])
	  return false;
      return true;
    }

    inline void add (hb_codepoint_t g) { elt (g) |= mask (g); }
    inline void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
    inline bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }

B
Behdad Esfahbod 已提交
71 72
    inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
    {
73 74 75 76 77 78 79 80
      elt_t *la = &elt (a);
      elt_t *lb = &elt (b);
      if (la == lb)
        *la |= (mask (b) << 1) - mask(a);
      else
      {
	*la |= ~(mask (a) - 1);
	la++;
81

82
	memset (la, 0xff, (char *) lb - (char *) la);
83

84 85
	*lb |= ((mask (b) << 1) - 1);
      }
B
Behdad Esfahbod 已提交
86 87
    }

B
Behdad Esfahbod 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    inline bool is_equal (const page_t *other) const
    {
      return 0 == memcmp (&v, &other->v, sizeof (v));
    }

    inline unsigned int get_population (void) const
    {
      unsigned int pop = 0;
      for (unsigned int i = 0; i < len (); i++)
        pop += _hb_popcount (v[i]);
      return pop;
    }

    inline bool next (hb_codepoint_t *codepoint) const
    {
      unsigned int m = (*codepoint + 1) & MASK;
      if (!m)
      {
	*codepoint = INVALID;
	return false;
      }
      unsigned int i = m / ELT_BITS;
      unsigned int j = m & ELT_MASK;

      for (; j < ELT_BITS; j++)
        if (v[i] & (elt_t (1) << j))
	  goto found;
      for (i++; i < len (); i++)
        if (v[i])
J
Jonathan Kew 已提交
117
	  for (j = 0; j < ELT_BITS; j++)
B
Behdad Esfahbod 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
	    if (v[i] & (elt_t (1) << j))
	      goto found;

      *codepoint = INVALID;
      return false;

    found:
      *codepoint = i * ELT_BITS + j;
      return true;
    }
    inline hb_codepoint_t get_min (void) const
    {
      for (unsigned int i = 0; i < len (); i++)
        if (v[i])
	{
	  elt_t e = v[i];
	  for (unsigned int j = 0; j < ELT_BITS; j++)
	    if (e & (elt_t (1) << j))
	      return i * ELT_BITS + j;
	}
      return INVALID;
    }
    inline hb_codepoint_t get_max (void) const
    {
      for (int i = len () - 1; i >= 0; i--)
        if (v[i])
	{
	  elt_t e = v[i];
	  for (int j = ELT_BITS - 1; j >= 0; j--)
	    if (e & (elt_t (1) << j))
	      return i * ELT_BITS + j;
	}
      return 0;
    }

153
    static const unsigned int PAGE_BITS = 8192; /* Use to tune. */
B
Behdad Esfahbod 已提交
154 155
    static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");

156 157
    typedef uint64_t elt_t;

B
Behdad Esfahbod 已提交
158 159
#if 0 && HAVE_VECTOR_SIZE
    /* The vectorized version does not work with clang as non-const
B
Ouch.  
Behdad Esfahbod 已提交
160
     * elt() errs "non-const reference cannot bind to vector element". */
B
Behdad Esfahbod 已提交
161 162
    typedef elt_t vector_t __attribute__((vector_size (PAGE_BITS / 8)));
#else
163
    typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
B
Behdad Esfahbod 已提交
164 165 166 167 168 169
#endif

    vector_t v;

    static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
    static const unsigned int ELT_MASK = ELT_BITS - 1;
B
Behdad Esfahbod 已提交
170
    static const unsigned int BITS = sizeof (vector_t) * 8;
B
Behdad Esfahbod 已提交
171 172 173 174 175 176 177
    static const unsigned int MASK = BITS - 1;
    static_assert (PAGE_BITS == BITS, "");

    elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
    elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
    elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & ELT_MASK); }
  };
B
Behdad Esfahbod 已提交
178
  static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
B
Behdad Esfahbod 已提交
179

180 181
  hb_object_header_t header;
  ASSERT_POD ();
182
  bool in_error;
B
Behdad Esfahbod 已提交
183
  hb_prealloced_array_t<page_map_t, 8> page_map;
184
  hb_prealloced_array_t<page_t, 1> pages;
B
Behdad Esfahbod 已提交
185

B
Minor  
Behdad Esfahbod 已提交
186 187 188 189 190 191 192 193 194 195 196
  inline void init (void)
  {
    page_map.init ();
    pages.init ();
  }
  inline void finish (void)
  {
    page_map.finish ();
    pages.finish ();
  }

B
Behdad Esfahbod 已提交
197 198 199 200 201 202 203 204 205 206 207
  inline bool resize (unsigned int count)
  {
    if (unlikely (in_error)) return false;
    if (!pages.resize (count) || !page_map.resize (count))
    {
      pages.resize (page_map.len);
      in_error = true;
      return false;
    }
    return true;
  }
208

B
Behdad Esfahbod 已提交
209
  inline void clear (void) {
210 211 212
    if (unlikely (hb_object_is_inert (this)))
      return;
    in_error = false;
B
Behdad Esfahbod 已提交
213 214
    page_map.resize (0);
    pages.resize (0);
B
Behdad Esfahbod 已提交
215
  }
B
Behdad Esfahbod 已提交
216
  inline bool is_empty (void) const {
B
Behdad Esfahbod 已提交
217 218 219
    unsigned int count = pages.len;
    for (unsigned int i = 0; i < count; i++)
      if (!pages[i].is_empty ())
B
Behdad Esfahbod 已提交
220 221 222
        return false;
    return true;
  }
B
Behdad Esfahbod 已提交
223

B
Behdad Esfahbod 已提交
224
  inline void add (hb_codepoint_t g)
B
Behdad Esfahbod 已提交
225
  {
226
    if (unlikely (in_error)) return;
227
    if (unlikely (g == INVALID)) return;
228
    page_t *page = page_for_insert (g); if (unlikely (!page)) return;
B
Behdad Esfahbod 已提交
229
    page->add (g);
B
Behdad Esfahbod 已提交
230
  }
231
  inline bool add_range (hb_codepoint_t a, hb_codepoint_t b)
232
  {
233
    if (unlikely (in_error || a > b || a == INVALID || b == INVALID)) return false;
B
Behdad Esfahbod 已提交
234 235 236 237
    unsigned int ma = get_major (a);
    unsigned int mb = get_major (b);
    if (ma == mb)
    {
238
      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
B
Behdad Esfahbod 已提交
239 240 241 242
      page->add_range (a, b);
    }
    else
    {
243
      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
B
Behdad Esfahbod 已提交
244 245 246 247
      page->add_range (a, major_start (ma + 1) - 1);

      for (unsigned int m = ma + 1; m < mb; m++)
      {
248
	page = page_for_insert (major_start (m)); if (unlikely (!page)) return false;
B
Behdad Esfahbod 已提交
249 250 251
	page->init1 ();
      }

252
      page = page_for_insert (b); if (unlikely (!page)) return false;
B
Behdad Esfahbod 已提交
253 254
      page->add_range (major_start (mb), b);
    }
255
    return true;
256
  }
B
Behdad Esfahbod 已提交
257

B
Behdad Esfahbod 已提交
258
  template <typename T>
B
Behdad Esfahbod 已提交
259
  inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
B
Behdad Esfahbod 已提交
260
  {
261 262 263 264
    if (unlikely (in_error)) return;
    if (!count) return;
    hb_codepoint_t g = *array;
    while (count)
B
Behdad Esfahbod 已提交
265
    {
266 267 268 269 270 271 272 273 274 275 276 277
      unsigned int m = get_major (g);
      page_t *page = page_for_insert (g); if (unlikely (!page)) return;
      unsigned int start = major_start (m);
      unsigned int end = major_start (m + 1);
      do
      {
	page->add (g);

	array++;
	count--;
      }
      while (count && (g = *array, start <= g && g < end));
B
Behdad Esfahbod 已提交
278
    }
B
Behdad Esfahbod 已提交
279
  }
280

B
Behdad Esfahbod 已提交
281 282 283 284 285
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
  template <typename T>
  inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
  {
286
    if (unlikely (in_error)) return false;
287 288
    if (!count) return true;
    hb_codepoint_t g = *array;
289
    hb_codepoint_t last_g = g;
290
    while (count)
B
Behdad Esfahbod 已提交
291
    {
292 293 294 295 296
      unsigned int m = get_major (g);
      page_t *page = page_for_insert (g); if (unlikely (!page)) return false;
      unsigned int end = major_start (m + 1);
      do
      {
297 298 299 300
        /* If we try harder we can change the following comparison to <=;
	 * Not sure if it's worth it. */
        if (g < last_g) return false;
	last_g = g;
301 302 303 304 305
	page->add (g);

	array++;
	count--;
      }
306
      while (count && (g = *array, g < end));
B
Behdad Esfahbod 已提交
307 308 309 310
    }
    return true;
  }

B
Behdad Esfahbod 已提交
311
  inline void del (hb_codepoint_t g)
B
Behdad Esfahbod 已提交
312
  {
313
    if (unlikely (in_error)) return;
B
Behdad Esfahbod 已提交
314 315 316 317
    page_t *p = page_for (g);
    if (!p)
      return;
    p->del (g);
B
Behdad Esfahbod 已提交
318
  }
B
Behdad Esfahbod 已提交
319 320
  inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
  {
321
    /* TODO Optimize, like add_range(). */
322
    if (unlikely (in_error)) return;
B
Behdad Esfahbod 已提交
323 324 325
    for (unsigned int i = a; i < b + 1; i++)
      del (i);
  }
B
Behdad Esfahbod 已提交
326 327
  inline bool has (hb_codepoint_t g) const
  {
B
Behdad Esfahbod 已提交
328 329 330 331
    const page_t *p = page_for (g);
    if (!p)
      return false;
    return p->has (g);
B
Behdad Esfahbod 已提交
332 333 334 335
  }
  inline bool intersects (hb_codepoint_t first,
			  hb_codepoint_t last) const
  {
B
Behdad Esfahbod 已提交
336 337
    hb_codepoint_t c = first - 1;
    return next (&c) && c <= last;
B
Behdad Esfahbod 已提交
338
  }
B
Behdad Esfahbod 已提交
339 340 341 342 343 344 345 346 347 348 349
  inline void set (const hb_set_t *other)
  {
    if (unlikely (in_error)) return;
    unsigned int count = other->pages.len;
    if (!resize (count))
      return;

    memcpy (pages.array, other->pages.array, count * sizeof (pages.array[0]));
    memcpy (page_map.array, other->page_map.array, count * sizeof (page_map.array[0]));
  }

B
Behdad Esfahbod 已提交
350
  inline bool is_equal (const hb_set_t *other) const
B
Behdad Esfahbod 已提交
351
  {
B
Behdad Esfahbod 已提交
352 353 354 355 356 357 358 359 360 361
    unsigned int na = pages.len;
    unsigned int nb = other->pages.len;

    unsigned int a = 0, b = 0;
    for (; a < na && b < nb; )
    {
      if (page_at (a).is_empty ()) { a++; continue; }
      if (other->page_at (b).is_empty ()) { b++; continue; }
      if (page_map[a].major != other->page_map[b].major ||
	  !page_at (a).is_equal (&other->page_at (b)))
B
Behdad Esfahbod 已提交
362
        return false;
B
Behdad Esfahbod 已提交
363 364 365 366 367 368 369 370
      a++;
      b++;
    }
    for (; a < na; a++)
      if (!page_at (a).is_empty ()) { return false; }
    for (; b < nb; b++)
      if (!other->page_at (b).is_empty ()) { return false; }

B
Behdad Esfahbod 已提交
371 372
    return true;
  }
B
Behdad Esfahbod 已提交
373 374 375

  template <class Op>
  inline void process (const hb_set_t *other)
B
Behdad Esfahbod 已提交
376
  {
377
    if (unlikely (in_error)) return;
B
Behdad Esfahbod 已提交
378

B
Behdad Esfahbod 已提交
379 380
    unsigned int na = pages.len;
    unsigned int nb = other->pages.len;
B
Behdad Esfahbod 已提交
381 382

    unsigned int count = 0;
B
Behdad Esfahbod 已提交
383
    unsigned int a = 0, b = 0;
B
Behdad Esfahbod 已提交
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
    for (; a < na && b < nb; )
    {
      if (page_map[a].major == other->page_map[b].major)
      {
        count++;
	a++;
	b++;
      }
      else if (page_map[a].major < other->page_map[b].major)
      {
        if (Op::passthru_left)
	  count++;
        a++;
      }
      else
      {
        if (Op::passthru_right)
	  count++;
        b++;
      }
    }
    if (Op::passthru_left)
      count += na - a;
    if (Op::passthru_right)
      count += nb - b;

    if (!resize (count))
      return;

    /* Process in-place backward. */
B
Behdad Esfahbod 已提交
414 415 416
    a = na;
    b = nb;
    for (; a && b; )
B
Behdad Esfahbod 已提交
417
    {
418
      if (page_map[a - 1].major == other->page_map[b - 1].major)
B
Behdad Esfahbod 已提交
419 420 421
      {
	a--;
	b--;
B
Behdad Esfahbod 已提交
422
        Op::process (page_at (--count).v, page_at (a).v, other->page_at (b).v);
B
Behdad Esfahbod 已提交
423
      }
424
      else if (page_map[a - 1].major > other->page_map[b - 1].major)
B
Behdad Esfahbod 已提交
425
      {
B
Behdad Esfahbod 已提交
426
        a--;
B
Behdad Esfahbod 已提交
427 428 429 430 431
        if (Op::passthru_left)
	  page_at (--count).v = page_at (a).v;
      }
      else
      {
B
Behdad Esfahbod 已提交
432
        b--;
B
Behdad Esfahbod 已提交
433 434 435 436
        if (Op::passthru_right)
	  page_at (--count).v = other->page_at (b).v;
      }
    }
B
Behdad Esfahbod 已提交
437
    if (Op::passthru_left)
B
Behdad Esfahbod 已提交
438 439
      while (a)
	page_at (--count).v = page_at (--a).v;
B
Behdad Esfahbod 已提交
440
    if (Op::passthru_right)
B
Behdad Esfahbod 已提交
441 442
      while (b)
	page_at (--count).v = other->page_at (--b).v;
B
Behdad Esfahbod 已提交
443
    assert (!count);
B
Behdad Esfahbod 已提交
444
  }
B
Behdad Esfahbod 已提交
445

B
Behdad Esfahbod 已提交
446 447
  inline void union_ (const hb_set_t *other)
  {
448
    process<HbOpOr> (other);
B
Behdad Esfahbod 已提交
449 450 451
  }
  inline void intersect (const hb_set_t *other)
  {
452
    process<HbOpAnd> (other);
B
Behdad Esfahbod 已提交
453 454 455
  }
  inline void subtract (const hb_set_t *other)
  {
456
    process<HbOpMinus> (other);
B
Behdad Esfahbod 已提交
457
  }
B
Behdad Esfahbod 已提交
458 459
  inline void symmetric_difference (const hb_set_t *other)
  {
460
    process<HbOpXor> (other);
461
  }
B
Behdad Esfahbod 已提交
462
  inline bool next (hb_codepoint_t *codepoint) const
B
Behdad Esfahbod 已提交
463
  {
464
    if (unlikely (*codepoint == INVALID)) {
B
Behdad Esfahbod 已提交
465 466 467 468
      *codepoint = get_min ();
      return *codepoint != INVALID;
    }

B
Behdad Esfahbod 已提交
469
    page_map_t map = {get_major (*codepoint), 0};
B
Behdad Esfahbod 已提交
470 471 472 473 474 475
    unsigned int i;
    page_map.bfind (&map, &i);
    if (i < page_map.len)
    {
      if (pages[page_map[i].index].next (codepoint))
      {
B
Behdad Esfahbod 已提交
476
	*codepoint += page_map[i].major * page_t::PAGE_BITS;
B
Behdad Esfahbod 已提交
477
        return true;
478
      }
B
Behdad Esfahbod 已提交
479
      i++;
B
Behdad Esfahbod 已提交
480
    }
B
Behdad Esfahbod 已提交
481 482 483 484 485
    for (; i < page_map.len; i++)
    {
      hb_codepoint_t m = pages[page_map[i].index].get_min ();
      if (m != INVALID)
      {
B
Behdad Esfahbod 已提交
486
	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
B
Behdad Esfahbod 已提交
487 488
	return true;
      }
B
Behdad Esfahbod 已提交
489
    }
490
    *codepoint = INVALID;
B
Behdad Esfahbod 已提交
491 492
    return false;
  }
B
Behdad Esfahbod 已提交
493 494 495 496 497 498
  inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
  {
    hb_codepoint_t i;

    i = *last;
    if (!next (&i))
499 500
    {
      *last = *first = INVALID;
B
Behdad Esfahbod 已提交
501
      return false;
502
    }
B
Behdad Esfahbod 已提交
503 504 505 506 507 508 509 510 511 512

    *last = *first = i;
    while (next (&i) && i == *last + 1)
      (*last)++;

    return true;
  }

  inline unsigned int get_population (void) const
  {
B
Behdad Esfahbod 已提交
513 514 515 516 517
    unsigned int pop = 0;
    unsigned int count = pages.len;
    for (unsigned int i = 0; i < count; i++)
      pop += pages[i].get_population ();
    return pop;
B
Behdad Esfahbod 已提交
518
  }
519
  inline hb_codepoint_t get_min (void) const
B
Behdad Esfahbod 已提交
520
  {
B
Behdad Esfahbod 已提交
521 522 523
    unsigned int count = pages.len;
    for (unsigned int i = 0; i < count; i++)
      if (!page_at (i).is_empty ())
B
Behdad Esfahbod 已提交
524
        return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min ();
525
    return INVALID;
B
Behdad Esfahbod 已提交
526
  }
527
  inline hb_codepoint_t get_max (void) const
B
Behdad Esfahbod 已提交
528
  {
B
Behdad Esfahbod 已提交
529 530 531
    unsigned int count = pages.len;
    for (int i = count - 1; i >= 0; i++)
      if (!page_at (i).is_empty ())
B
Behdad Esfahbod 已提交
532
        return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_max ();
533
    return INVALID;
B
Behdad Esfahbod 已提交
534
  }
B
Behdad Esfahbod 已提交
535

536
  static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
B
Behdad Esfahbod 已提交
537

B
Behdad Esfahbod 已提交
538
  inline page_t *page_for_insert (hb_codepoint_t g)
B
Behdad Esfahbod 已提交
539
  {
B
Behdad Esfahbod 已提交
540
    page_map_t map = {get_major (g), pages.len};
B
Behdad Esfahbod 已提交
541 542 543 544 545
    unsigned int i;
    if (!page_map.bfind (&map, &i))
    {
      if (!resize (pages.len + 1))
	return nullptr;
B
Behdad Esfahbod 已提交
546

B
Behdad Esfahbod 已提交
547
      pages[map.index].init0 ();
B
Behdad Esfahbod 已提交
548 549 550 551 552
      memmove (&page_map[i + 1], &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0]));
      page_map[i] = map;
    }
    return &pages[page_map[i].index];
  }
B
Behdad Esfahbod 已提交
553
  inline page_t *page_for (hb_codepoint_t g)
B
Behdad Esfahbod 已提交
554
  {
B
Behdad Esfahbod 已提交
555
    page_map_t key = {get_major (g)};
B
Behdad Esfahbod 已提交
556 557 558 559 560
    const page_map_t *found = page_map.bsearch (&key);
    if (found)
      return &pages[found->index];
    return nullptr;
  }
B
Behdad Esfahbod 已提交
561
  inline const page_t *page_for (hb_codepoint_t g) const
B
Behdad Esfahbod 已提交
562
  {
B
Behdad Esfahbod 已提交
563
    page_map_t key = {get_major (g)};
B
Behdad Esfahbod 已提交
564 565 566 567 568
    const page_map_t *found = page_map.bsearch (&key);
    if (found)
      return &pages[found->index];
    return nullptr;
  }
B
Behdad Esfahbod 已提交
569 570 571 572
  inline page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
  inline const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
  inline unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
  inline hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
B
Behdad Esfahbod 已提交
573 574 575 576
};


#endif /* HB_SET_PRIVATE_HH */