Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/harfbuzz/src/hb-map.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2018  Google, Inc.
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 * Google Author(s): Behdad Esfahbod
25
 */
26
27
#ifndef HB_MAP_HH
28
#define HB_MAP_HH
29
30
#include "hb.hh"
31
32
33
template <typename T>
34
inline uint32_t Hash (const T &v)
35
0
{
36
0
  /* Knuth's multiplicative method: */
37
0
  return (uint32_t) v * 2654435761u;
38
0
}
39
40
41
/*
42
 * hb_map_t
43
 */
44
45
struct hb_map_t
46
{
47
  struct item_t
48
  {
49
    hb_codepoint_t key;
50
    hb_codepoint_t value;
51
52
0
    inline bool is_unused (void) const { return key == INVALID; }
53
0
    inline bool is_tombstone (void) const { return key != INVALID && value == INVALID; }
54
  };
55
56
  hb_object_header_t header;
57
  bool successful; /* Allocations successful */
58
  unsigned int population; /* Not including tombstones. */
59
  unsigned int occupancy; /* Including tombstones. */
60
  unsigned int mask;
61
  unsigned int prime;
62
  item_t *items;
63
64
  inline void init_shallow (void)
65
0
  {
66
0
    successful = true;
67
0
    population = occupancy = 0;
68
0
    mask = 0;
69
0
    prime = 0;
70
0
    items = nullptr;
71
0
  }
72
  inline void init (void)
73
0
  {
74
0
    hb_object_init (this);
75
0
    init_shallow ();
76
0
  }
77
  inline void fini_shallow (void)
78
0
  {
79
0
    free (items);
80
0
  }
81
  inline void fini (void)
82
0
  {
83
0
    hb_object_fini (this);
84
0
    fini_shallow ();
85
0
  }
86
87
  inline bool resize (void)
88
0
  {
89
0
    if (unlikely (!successful)) return false;
90
0
91
0
    unsigned int power = hb_bit_storage (population * 2 + 8);
92
0
    unsigned int new_size = 1u << power;
93
0
    item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
94
0
    if (unlikely (!new_items))
95
0
    {
96
0
      successful = false;
97
0
      return false;
98
0
    }
99
0
    memset (new_items, 0xFF, (size_t) new_size * sizeof (item_t));
100
0
101
0
    unsigned int old_size = mask + 1;
102
0
    item_t *old_items = items;
103
0
104
0
    /* Switch to new, empty, array. */
105
0
    population = occupancy = 0;
106
0
    mask = new_size - 1;
107
0
    prime = prime_for (power);
108
0
    items = new_items;
109
0
110
0
    /* Insert back old items. */
111
0
    if (old_items)
112
0
      for (unsigned int i = 0; i < old_size; i++)
113
0
  if (old_items[i].key != INVALID && old_items[i].value != INVALID)
114
0
    set (old_items[i].key, old_items[i].value);
115
0
116
0
    free (old_items);
117
0
118
0
    return true;
119
0
  }
120
121
  inline void set (hb_codepoint_t key, hb_codepoint_t value)
122
0
  {
123
0
    if (unlikely (!successful)) return;
124
0
    if (unlikely (key == INVALID)) return;
125
0
    if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
126
0
    unsigned int i = bucket_for (key);
127
0
128
0
    if (value == INVALID && items[i].key != key)
129
0
      return; /* Trying to delete non-existent key. */
130
0
131
0
    if (!items[i].is_unused ())
132
0
    {
133
0
      occupancy--;
134
0
      if (items[i].is_tombstone ())
135
0
  population--;
136
0
    }
137
0
138
0
    items[i].key = key;
139
0
    items[i].value = value;
140
0
141
0
    occupancy++;
142
0
    if (!items[i].is_tombstone ())
143
0
      population++;
144
0
145
0
  }
146
  inline hb_codepoint_t get (hb_codepoint_t key) const
147
0
  {
148
0
    if (unlikely (!items)) return INVALID;
149
0
    unsigned int i = bucket_for (key);
150
0
    return items[i].key == key ? items[i].value : INVALID;
151
0
  }
152
153
  inline void del (hb_codepoint_t key)
154
0
  {
155
0
    set (key, INVALID);
156
0
  }
157
  inline bool has (hb_codepoint_t key) const
158
0
  {
159
0
    return get (key) != INVALID;
160
0
  }
161
162
  inline hb_codepoint_t operator [] (unsigned int key) const
163
0
  { return get (key); }
164
165
  static const hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
166
167
  inline void clear (void)
168
0
  {
169
0
    memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t));
170
0
    population = occupancy = 0;
171
0
  }
172
173
  inline bool is_empty (void) const
174
0
  {
175
0
    return population != 0;
176
0
  }
177
178
  inline unsigned int get_population () const
179
0
  {
180
0
    return population;
181
0
  }
182
183
  protected:
184
185
  inline unsigned int bucket_for (hb_codepoint_t key) const
186
0
  {
187
0
    unsigned int i = Hash (key) % prime;
188
0
    unsigned int step = 0;
189
0
    unsigned int tombstone = INVALID;
190
0
    while (!items[i].is_unused ())
191
0
    {
192
0
      if (items[i].key == key)
193
0
        return i;
194
0
      if (tombstone == INVALID && items[i].is_tombstone ())
195
0
        tombstone = i;
196
0
      i = (i + ++step) & mask;
197
0
    }
198
0
    return tombstone == INVALID ? i : tombstone;
199
0
  }
200
201
  static inline unsigned int prime_for (unsigned int shift)
202
0
  {
203
0
    /* Following comment and table copied from glib. */
204
0
    /* Each table size has an associated prime modulo (the first prime
205
0
     * lower than the table size) used to find the initial bucket. Probing
206
0
     * then works modulo 2^n. The prime modulo is necessary to get a
207
0
     * good distribution with poor hash functions.
208
0
     */
209
0
    /* Not declaring static to make all kinds of compilers happy... */
210
0
    /*static*/ const unsigned int prime_mod [32] =
211
0
    {
212
0
      1,          /* For 1 << 0 */
213
0
      2,
214
0
      3,
215
0
      7,
216
0
      13,
217
0
      31,
218
0
      61,
219
0
      127,
220
0
      251,
221
0
      509,
222
0
      1021,
223
0
      2039,
224
0
      4093,
225
0
      8191,
226
0
      16381,
227
0
      32749,
228
0
      65521,      /* For 1 << 16 */
229
0
      131071,
230
0
      262139,
231
0
      524287,
232
0
      1048573,
233
0
      2097143,
234
0
      4194301,
235
0
      8388593,
236
0
      16777213,
237
0
      33554393,
238
0
      67108859,
239
0
      134217689,
240
0
      268435399,
241
0
      536870909,
242
0
      1073741789,
243
0
      2147483647  /* For 1 << 31 */
244
0
    };
245
0
246
0
    if (unlikely (shift >= ARRAY_LENGTH (prime_mod)))
247
0
      return prime_mod[ARRAY_LENGTH (prime_mod) - 1];
248
0
249
0
    return prime_mod[shift];
250
0
  }
251
};
252
253
254
#endif /* HB_MAP_HH */