Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/fontconfig/src/fchash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2000 Keith Packard
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software and its
5
 * documentation for any purpose is hereby granted without fee, provided that
6
 * the above copyright notice appear in all copies and that both that
7
 * copyright notice and this permission notice appear in supporting
8
 * documentation, and that the name of the author(s) not be used in
9
 * advertising or publicity pertaining to distribution of the software without
10
 * specific, written prior permission.  The authors make no
11
 * representations about the suitability of this software for any purpose.  It
12
 * is provided "as is" without express or implied warranty.
13
 *
14
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16
 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20
 * PERFORMANCE OF THIS SOFTWARE.
21
 */
22
#include "fcint.h"
23
24
287k
#define FC_HASH_SIZE 227
25
26
typedef struct _FcHashBucket {
27
    struct _FcHashBucket *next;
28
    void                 *key;
29
    void                 *value;
30
} FcHashBucket;
31
32
struct _FcHashTable {
33
    FcHashBucket *buckets[FC_HASH_SIZE];
34
    FcHashFunc    hash_func;
35
    FcCompareFunc compare_func;
36
    FcCopyFunc    key_copy_func;
37
    FcCopyFunc    value_copy_func;
38
    FcDestroyFunc key_destroy_func;
39
    FcDestroyFunc value_destroy_func;
40
};
41
42
FcBool
43
FcHashStrCopy (const void *src,
44
               void      **dest)
45
0
{
46
0
    *dest = FcStrdup (src);
47
48
0
    return *dest != NULL;
49
0
}
50
51
FcHashTable *
52
FcHashTableCreate (FcHashFunc    hash_func,
53
                   FcCompareFunc compare_func,
54
                   FcCopyFunc    key_copy_func,
55
                   FcCopyFunc    value_copy_func,
56
                   FcDestroyFunc key_destroy_func,
57
                   FcDestroyFunc value_destroy_func)
58
1.23k
{
59
1.23k
    FcHashTable *ret = malloc (sizeof (FcHashTable));
60
61
1.23k
    if (ret) {
62
1.23k
  memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE);
63
1.23k
  ret->hash_func = hash_func;
64
1.23k
  ret->compare_func = compare_func;
65
1.23k
  ret->key_copy_func = key_copy_func;
66
1.23k
  ret->value_copy_func = value_copy_func;
67
1.23k
  ret->key_destroy_func = key_destroy_func;
68
1.23k
  ret->value_destroy_func = value_destroy_func;
69
1.23k
    }
70
1.23k
    return ret;
71
1.23k
}
72
73
void
74
FcHashTableDestroy (FcHashTable *table)
75
1.23k
{
76
1.23k
    int i;
77
78
280k
    for (i = 0; i < FC_HASH_SIZE; i++) {
79
279k
  FcHashBucket *bucket = table->buckets[i], *prev;
80
81
280k
  while (bucket) {
82
1.23k
      if (table->key_destroy_func)
83
990
    table->key_destroy_func (bucket->key);
84
1.23k
      if (table->value_destroy_func)
85
1.23k
    table->value_destroy_func (bucket->value);
86
1.23k
      prev = bucket;
87
1.23k
      bucket = bucket->next;
88
1.23k
      free (prev);
89
1.23k
  }
90
279k
  table->buckets[i] = NULL;
91
279k
    }
92
1.23k
    free (table);
93
1.23k
}
94
95
FcBool
96
FcHashTableFind (FcHashTable *table,
97
                 const void  *key,
98
                 void       **value)
99
4.12k
{
100
4.12k
    FcHashBucket *bucket;
101
4.12k
    FcChar32      hash = table->hash_func (key);
102
103
4.12k
    for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next) {
104
964
  if (!table->compare_func (bucket->key, key)) {
105
964
      if (table->value_copy_func) {
106
0
    if (!table->value_copy_func (bucket->value, value))
107
0
        return FcFalse;
108
0
      } else
109
964
    *value = bucket->value;
110
964
      return FcTrue;
111
964
  }
112
964
    }
113
3.15k
    return FcFalse;
114
4.12k
}
115
116
static FcBool
117
FcHashTableAddInternal (FcHashTable *table,
118
                        void        *key,
119
                        void        *value,
120
                        FcBool       replace)
121
1.23k
{
122
1.23k
    FcHashBucket **prev, *bucket, *b;
123
1.23k
    FcChar32       hash = table->hash_func (key);
124
1.23k
    FcBool         ret = FcFalse;
125
126
1.23k
    bucket = (FcHashBucket *)malloc (sizeof (FcHashBucket));
127
1.23k
    if (!bucket)
128
0
  return FcFalse;
129
1.23k
    memset (bucket, 0, sizeof (FcHashBucket));
130
1.23k
    if (table->key_copy_func)
131
990
  ret |= !table->key_copy_func (key, &bucket->key);
132
241
    else
133
241
  bucket->key = key;
134
1.23k
    if (table->value_copy_func)
135
0
  ret |= !table->value_copy_func (value, &bucket->value);
136
1.23k
    else
137
1.23k
  bucket->value = value;
138
1.23k
    if (ret) {
139
0
    destroy:
140
0
  if (bucket->key && table->key_destroy_func)
141
0
      table->key_destroy_func (bucket->key);
142
0
  if (bucket->value && table->value_destroy_func)
143
0
      table->value_destroy_func (bucket->value);
144
0
  free (bucket);
145
146
0
  return !ret;
147
0
    }
148
1.23k
retry:
149
1.23k
    for (prev = &table->buckets[hash % FC_HASH_SIZE];
150
1.23k
         (b = fc_atomic_ptr_get (prev)); prev = &(b->next)) {
151
0
  if (!table->compare_func (b->key, key)) {
152
0
      if (replace) {
153
0
    bucket->next = b->next;
154
0
    if (!fc_atomic_ptr_cmpexch (prev, b, bucket))
155
0
        goto retry;
156
0
    bucket = b;
157
0
      } else
158
0
    ret = FcTrue;
159
0
      goto destroy;
160
0
  }
161
0
    }
162
1.23k
    bucket->next = NULL;
163
1.23k
    if (!fc_atomic_ptr_cmpexch (prev, b, bucket))
164
0
  goto retry;
165
166
1.23k
    return FcTrue;
167
1.23k
}
168
169
FcBool
170
FcHashTableAdd (FcHashTable *table,
171
                void        *key,
172
                void        *value)
173
1.23k
{
174
1.23k
    return FcHashTableAddInternal (table, key, value, FcFalse);
175
1.23k
}
176
177
FcBool
178
FcHashTableReplace (FcHashTable *table,
179
                    void        *key,
180
                    void        *value)
181
0
{
182
0
    return FcHashTableAddInternal (table, key, value, FcTrue);
183
0
}
184
185
FcBool
186
FcHashTableRemove (FcHashTable *table,
187
                   void        *key)
188
0
{
189
0
    FcHashBucket **prev, *bucket;
190
0
    FcChar32       hash = table->hash_func (key);
191
0
    FcBool         ret = FcFalse;
192
193
0
retry:
194
0
    for (prev = &table->buckets[hash % FC_HASH_SIZE];
195
0
         (bucket = fc_atomic_ptr_get (prev)); prev = &(bucket->next)) {
196
0
  if (!table->compare_func (bucket->key, key)) {
197
0
      if (!fc_atomic_ptr_cmpexch (prev, bucket, bucket->next))
198
0
    goto retry;
199
0
      if (table->key_destroy_func)
200
0
    table->key_destroy_func (bucket->key);
201
0
      if (table->value_destroy_func)
202
0
    table->value_destroy_func (bucket->value);
203
0
      free (bucket);
204
0
      ret = FcTrue;
205
0
      break;
206
0
  }
207
0
    }
208
209
0
    return ret;
210
0
}