Coverage Report

Created: 2023-06-07 06:14

/src/harfbuzz/src/hb-set-digest.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2012  Google, Inc.
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 * Google Author(s): Behdad Esfahbod
25
 */
26
27
#ifndef HB_SET_DIGEST_HH
28
#define HB_SET_DIGEST_HH
29
30
#include "hb.hh"
31
#include "hb-machinery.hh"
32
33
/*
34
 * The set-digests here implement various "filters" that support
35
 * "approximate member query".  Conceptually these are like Bloom
36
 * Filter and Quotient Filter, however, much smaller, faster, and
37
 * designed to fit the requirements of our uses for glyph coverage
38
 * queries.
39
 *
40
 * Our filters are highly accurate if the lookup covers fairly local
41
 * set of glyphs, but fully flooded and ineffective if coverage is
42
 * all over the place.
43
 *
44
 * The way these are used is that the filter is first populated by
45
 * a lookup's or subtable's Coverage table(s), and then when we
46
 * want to apply the lookup or subtable to a glyph, before trying
47
 * to apply, we ask the filter if the glyph may be covered. If it's
48
 * not, we return early.  We can also match a digest against another
49
 * digest.
50
 *
51
 * We use these filters at three levels:
52
 *   - If the digest for all the glyphs in the buffer as a whole
53
 *     does not match the digest for the lookup, skip the lookup.
54
 *   - For each glyph, if it doesn't match the lookup digest,
55
 *     skip it.
56
 *   - For each glyph, if it doesn't match the subtable digest,
57
 *     skip it.
58
 *
59
 * The main filter we use is a combination of three bits-pattern
60
 * filters. A bits-pattern filter checks a number of bits (5 or 6)
61
 * of the input number (glyph-id in this case) and checks whether
62
 * its pattern is amongst the patterns of any of the accepted values.
63
 * The accepted patterns are represented as a "long" integer. The
64
 * check is done using four bitwise operations only.
65
 */
66
67
template <typename mask_t, unsigned int shift>
68
struct hb_set_digest_bits_pattern_t
69
{
70
  static constexpr unsigned mask_bytes = sizeof (mask_t);
71
  static constexpr unsigned mask_bits = sizeof (mask_t) * 8;
72
  static constexpr unsigned num_bits = 0
73
             + (mask_bytes >= 1 ? 3 : 0)
74
             + (mask_bytes >= 2 ? 1 : 0)
75
             + (mask_bytes >= 4 ? 1 : 0)
76
             + (mask_bytes >= 8 ? 1 : 0)
77
             + (mask_bytes >= 16? 1 : 0)
78
             + 0;
79
80
  static_assert ((shift < sizeof (hb_codepoint_t) * 8), "");
81
  static_assert ((shift + num_bits <= sizeof (hb_codepoint_t) * 8), "");
82
83
1.22M
  void init () { mask = 0; }
hb_set_digest_bits_pattern_t<unsigned long, 4u>::init()
Line
Count
Source
83
409k
  void init () { mask = 0; }
hb_set_digest_bits_pattern_t<unsigned long, 0u>::init()
Line
Count
Source
83
409k
  void init () { mask = 0; }
hb_set_digest_bits_pattern_t<unsigned long, 9u>::init()
Line
Count
Source
83
409k
  void init () { mask = 0; }
84
85
24
  void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
hb_set_digest_bits_pattern_t<unsigned long, 4u>::add(hb_set_digest_bits_pattern_t<unsigned long, 4u> const&)
Line
Count
Source
85
8
  void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
hb_set_digest_bits_pattern_t<unsigned long, 0u>::add(hb_set_digest_bits_pattern_t<unsigned long, 0u> const&)
Line
Count
Source
85
8
  void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
hb_set_digest_bits_pattern_t<unsigned long, 9u>::add(hb_set_digest_bits_pattern_t<unsigned long, 9u> const&)
Line
Count
Source
85
8
  void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
86
87
17.6M
  void add (hb_codepoint_t g) { mask |= mask_for (g); }
hb_set_digest_bits_pattern_t<unsigned long, 4u>::add(unsigned int)
Line
Count
Source
87
5.86M
  void add (hb_codepoint_t g) { mask |= mask_for (g); }
hb_set_digest_bits_pattern_t<unsigned long, 0u>::add(unsigned int)
Line
Count
Source
87
5.86M
  void add (hb_codepoint_t g) { mask |= mask_for (g); }
hb_set_digest_bits_pattern_t<unsigned long, 9u>::add(unsigned int)
Line
Count
Source
87
5.86M
  void add (hb_codepoint_t g) { mask |= mask_for (g); }
88
89
  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
90
72
  {
91
72
    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
92
0
      mask = (mask_t) -1;
93
72
    else {
94
72
      mask_t ma = mask_for (a);
95
72
      mask_t mb = mask_for (b);
96
72
      mask |= mb + (mb - ma) - (mb < ma);
97
72
    }
98
72
    return true;
99
72
  }
hb_set_digest_bits_pattern_t<unsigned long, 4u>::add_range(unsigned int, unsigned int)
Line
Count
Source
90
24
  {
91
24
    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
92
0
      mask = (mask_t) -1;
93
24
    else {
94
24
      mask_t ma = mask_for (a);
95
24
      mask_t mb = mask_for (b);
96
24
      mask |= mb + (mb - ma) - (mb < ma);
97
24
    }
98
24
    return true;
99
24
  }
hb_set_digest_bits_pattern_t<unsigned long, 0u>::add_range(unsigned int, unsigned int)
Line
Count
Source
90
24
  {
91
24
    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
92
0
      mask = (mask_t) -1;
93
24
    else {
94
24
      mask_t ma = mask_for (a);
95
24
      mask_t mb = mask_for (b);
96
24
      mask |= mb + (mb - ma) - (mb < ma);
97
24
    }
98
24
    return true;
99
24
  }
hb_set_digest_bits_pattern_t<unsigned long, 9u>::add_range(unsigned int, unsigned int)
Line
Count
Source
90
24
  {
91
24
    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
92
0
      mask = (mask_t) -1;
93
24
    else {
94
24
      mask_t ma = mask_for (a);
95
24
      mask_t mb = mask_for (b);
96
24
      mask |= mb + (mb - ma) - (mb < ma);
97
24
    }
98
24
    return true;
99
24
  }
100
101
  template <typename T>
102
  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
103
1.22M
  {
104
18.8M
    for (unsigned int i = 0; i < count; i++)
105
17.6M
    {
106
17.6M
      add (*array);
107
17.6M
      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
108
17.6M
    }
109
1.22M
  }
void hb_set_digest_bits_pattern_t<unsigned long, 4u>::add_array<unsigned int>(unsigned int const*, unsigned int, unsigned int)
Line
Count
Source
103
409k
  {
104
6.27M
    for (unsigned int i = 0; i < count; i++)
105
5.86M
    {
106
5.86M
      add (*array);
107
5.86M
      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
108
5.86M
    }
109
409k
  }
void hb_set_digest_bits_pattern_t<unsigned long, 0u>::add_array<unsigned int>(unsigned int const*, unsigned int, unsigned int)
Line
Count
Source
103
409k
  {
104
6.27M
    for (unsigned int i = 0; i < count; i++)
105
5.86M
    {
106
5.86M
      add (*array);
107
5.86M
      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
108
5.86M
    }
109
409k
  }
void hb_set_digest_bits_pattern_t<unsigned long, 9u>::add_array<unsigned int>(unsigned int const*, unsigned int, unsigned int)
Line
Count
Source
103
409k
  {
104
6.27M
    for (unsigned int i = 0; i < count; i++)
105
5.86M
    {
106
5.86M
      add (*array);
107
5.86M
      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
108
5.86M
    }
109
409k
  }
void hb_set_digest_bits_pattern_t<unsigned long, 4u>::add_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
103
3
  {
104
7
    for (unsigned int i = 0; i < count; i++)
105
4
    {
106
4
      add (*array);
107
4
      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
108
4
    }
109
3
  }
void hb_set_digest_bits_pattern_t<unsigned long, 0u>::add_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
103
3
  {
104
7
    for (unsigned int i = 0; i < count; i++)
105
4
    {
106
4
      add (*array);
107
4
      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
108
4
    }
109
3
  }
void hb_set_digest_bits_pattern_t<unsigned long, 9u>::add_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
103
3
  {
104
7
    for (unsigned int i = 0; i < count; i++)
105
4
    {
106
4
      add (*array);
107
4
      array = &StructAtOffsetUnaligned<T> ((const void *) array, stride);
108
4
    }
109
3
  }
110
  template <typename T>
111
  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
112
  template <typename T>
113
  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
114
9
  {
115
9
    add_array (array, count, stride);
116
9
    return true;
117
9
  }
bool hb_set_digest_bits_pattern_t<unsigned long, 4u>::add_sorted_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
114
3
  {
115
3
    add_array (array, count, stride);
116
3
    return true;
117
3
  }
bool hb_set_digest_bits_pattern_t<unsigned long, 0u>::add_sorted_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
114
3
  {
115
3
    add_array (array, count, stride);
116
3
    return true;
117
3
  }
bool hb_set_digest_bits_pattern_t<unsigned long, 9u>::add_sorted_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
114
3
  {
115
3
    add_array (array, count, stride);
116
3
    return true;
117
3
  }
118
  template <typename T>
119
  bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
120
121
  bool may_have (const hb_set_digest_bits_pattern_t &o) const
122
45
  { return mask & o.mask; }
hb_set_digest_bits_pattern_t<unsigned long, 4u>::may_have(hb_set_digest_bits_pattern_t<unsigned long, 4u> const&) const
Line
Count
Source
122
45
  { return mask & o.mask; }
Unexecuted instantiation: hb_set_digest_bits_pattern_t<unsigned long, 0u>::may_have(hb_set_digest_bits_pattern_t<unsigned long, 0u> const&) const
Unexecuted instantiation: hb_set_digest_bits_pattern_t<unsigned long, 9u>::may_have(hb_set_digest_bits_pattern_t<unsigned long, 9u> const&) const
123
124
  bool may_have (hb_codepoint_t g) const
125
0
  { return mask & mask_for (g); }
Unexecuted instantiation: hb_set_digest_bits_pattern_t<unsigned long, 4u>::may_have(unsigned int) const
Unexecuted instantiation: hb_set_digest_bits_pattern_t<unsigned long, 0u>::may_have(unsigned int) const
Unexecuted instantiation: hb_set_digest_bits_pattern_t<unsigned long, 9u>::may_have(unsigned int) const
126
127
  private:
128
129
  static mask_t mask_for (hb_codepoint_t g)
130
17.6M
  { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
hb_set_digest_bits_pattern_t<unsigned long, 4u>::mask_for(unsigned int)
Line
Count
Source
130
5.86M
  { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
hb_set_digest_bits_pattern_t<unsigned long, 0u>::mask_for(unsigned int)
Line
Count
Source
130
5.86M
  { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
hb_set_digest_bits_pattern_t<unsigned long, 9u>::mask_for(unsigned int)
Line
Count
Source
130
5.86M
  { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
131
  mask_t mask;
132
};
133
134
template <typename head_t, typename tail_t>
135
struct hb_set_digest_combiner_t
136
{
137
  void init ()
138
819k
  {
139
819k
    head.init ();
140
819k
    tail.init ();
141
819k
  }
hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::init()
Line
Count
Source
138
409k
  {
139
409k
    head.init ();
140
409k
    tail.init ();
141
409k
  }
hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::init()
Line
Count
Source
138
409k
  {
139
409k
    head.init ();
140
409k
    tail.init ();
141
409k
  }
142
143
  void add (const hb_set_digest_combiner_t &o)
144
16
  {
145
16
    head.add (o.head);
146
16
    tail.add (o.tail);
147
16
  }
hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::add(hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > > const&)
Line
Count
Source
144
8
  {
145
8
    head.add (o.head);
146
8
    tail.add (o.tail);
147
8
  }
hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::add(hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > const&)
Line
Count
Source
144
8
  {
145
8
    head.add (o.head);
146
8
    tail.add (o.tail);
147
8
  }
148
149
  void add (hb_codepoint_t g)
150
0
  {
151
0
    head.add (g);
152
0
    tail.add (g);
153
0
  }
Unexecuted instantiation: hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::add(unsigned int)
Unexecuted instantiation: hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::add(unsigned int)
154
155
  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
156
48
  {
157
48
    return head.add_range (a, b) &&
158
48
     tail.add_range (a, b);
159
48
  }
hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::add_range(unsigned int, unsigned int)
Line
Count
Source
156
24
  {
157
24
    return head.add_range (a, b) &&
158
24
     tail.add_range (a, b);
159
24
  }
hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::add_range(unsigned int, unsigned int)
Line
Count
Source
156
24
  {
157
24
    return head.add_range (a, b) &&
158
24
     tail.add_range (a, b);
159
24
  }
160
  template <typename T>
161
  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
162
819k
  {
163
819k
    head.add_array (array, count, stride);
164
819k
    tail.add_array (array, count, stride);
165
819k
  }
void hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::add_array<unsigned int>(unsigned int const*, unsigned int, unsigned int)
Line
Count
Source
162
409k
  {
163
409k
    head.add_array (array, count, stride);
164
409k
    tail.add_array (array, count, stride);
165
409k
  }
void hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::add_array<unsigned int>(unsigned int const*, unsigned int, unsigned int)
Line
Count
Source
162
409k
  {
163
409k
    head.add_array (array, count, stride);
164
409k
    tail.add_array (array, count, stride);
165
409k
  }
166
  template <typename T>
167
  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
168
  template <typename T>
169
  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
170
6
  {
171
6
    return head.add_sorted_array (array, count, stride) &&
172
6
     tail.add_sorted_array (array, count, stride);
173
6
  }
bool hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::add_sorted_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
170
3
  {
171
3
    return head.add_sorted_array (array, count, stride) &&
172
3
     tail.add_sorted_array (array, count, stride);
173
3
  }
bool hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::add_sorted_array<OT::HBGlyphID16>(OT::HBGlyphID16 const*, unsigned int, unsigned int)
Line
Count
Source
170
3
  {
171
3
    return head.add_sorted_array (array, count, stride) &&
172
3
     tail.add_sorted_array (array, count, stride);
173
3
  }
174
  template <typename T>
175
3
  bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
176
177
  bool may_have (const hb_set_digest_combiner_t &o) const
178
45
  {
179
45
    return head.may_have (o.head) && tail.may_have (o.tail);
180
45
  }
hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::may_have(hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > > const&) const
Line
Count
Source
178
45
  {
179
45
    return head.may_have (o.head) && tail.may_have (o.tail);
180
45
  }
Unexecuted instantiation: hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::may_have(hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > const&) const
181
182
  bool may_have (hb_codepoint_t g) const
183
0
  {
184
0
    return head.may_have (g) && tail.may_have (g);
185
0
  }
Unexecuted instantiation: hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> > >::may_have(unsigned int) const
Unexecuted instantiation: hb_set_digest_combiner_t<hb_set_digest_bits_pattern_t<unsigned long, 0u>, hb_set_digest_bits_pattern_t<unsigned long, 9u> >::may_have(unsigned int) const
186
187
  private:
188
  head_t head;
189
  tail_t tail;
190
};
191
192
193
/*
194
 * hb_set_digest_t
195
 *
196
 * This is a combination of digests that performs "best".
197
 * There is not much science to this: it's a result of intuition
198
 * and testing.
199
 */
200
using hb_set_digest_t =
201
  hb_set_digest_combiner_t
202
  <
203
    hb_set_digest_bits_pattern_t<unsigned long, 4>,
204
    hb_set_digest_combiner_t
205
    <
206
      hb_set_digest_bits_pattern_t<unsigned long, 0>,
207
      hb_set_digest_bits_pattern_t<unsigned long, 9>
208
    >
209
  >
210
;
211
212
213
#endif /* HB_SET_DIGEST_HH */