Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/fontconfig/src/fchash.c
Line
Count
Source
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
769k
#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
3.29k
{
59
3.29k
    FcHashTable *ret = malloc (sizeof (FcHashTable));
60
61
3.29k
    if (ret) {
62
3.29k
  memset (ret->buckets, 0, sizeof (FcHashBucket *) * FC_HASH_SIZE);
63
3.29k
  ret->hash_func = hash_func;
64
3.29k
  ret->compare_func = compare_func;
65
3.29k
  ret->key_copy_func = key_copy_func;
66
3.29k
  ret->value_copy_func = value_copy_func;
67
3.29k
  ret->key_destroy_func = key_destroy_func;
68
3.29k
  ret->value_destroy_func = value_destroy_func;
69
3.29k
    }
70
3.29k
    return ret;
71
3.29k
}
72
73
void
74
FcHashTableDestroy (FcHashTable *table)
75
3.29k
{
76
3.29k
    int i;
77
78
751k
    for (i = 0; i < FC_HASH_SIZE; i++) {
79
748k
  FcHashBucket *bucket = table->buckets[i], *prev;
80
81
751k
  while (bucket) {
82
3.29k
      if (table->key_destroy_func)
83
2.64k
    table->key_destroy_func (bucket->key);
84
3.29k
      if (table->value_destroy_func)
85
3.29k
    table->value_destroy_func (bucket->value);
86
3.29k
      prev = bucket;
87
3.29k
      bucket = bucket->next;
88
3.29k
      free (prev);
89
3.29k
  }
90
748k
  table->buckets[i] = NULL;
91
748k
    }
92
3.29k
    free (table);
93
3.29k
}
94
95
FcBool
96
FcHashTableFind (FcHashTable *table,
97
                 const void  *key,
98
                 void       **value)
99
11.1k
{
100
11.1k
    FcHashBucket *bucket;
101
11.1k
    FcChar32      hash = table->hash_func (key);
102
103
11.1k
    for (bucket = table->buckets[hash % FC_HASH_SIZE]; bucket; bucket = bucket->next) {
104
2.61k
  if (!table->compare_func (bucket->key, key)) {
105
2.61k
      if (table->value_copy_func) {
106
0
    if (!table->value_copy_func (bucket->value, value))
107
0
        return FcFalse;
108
0
      } else
109
2.61k
    *value = bucket->value;
110
2.61k
      return FcTrue;
111
2.61k
  }
112
2.61k
    }
113
8.52k
    return FcFalse;
114
11.1k
}
115
116
static FcBool
117
FcHashTableAddInternal (FcHashTable *table,
118
                        void        *key,
119
                        void        *value,
120
                        FcBool       replace)
121
3.29k
{
122
3.29k
    FcHashBucket **prev, *bucket, *b;
123
3.29k
    FcChar32       hash = table->hash_func (key);
124
3.29k
    FcBool         ret = FcFalse;
125
126
3.29k
    bucket = (FcHashBucket *)malloc (sizeof (FcHashBucket));
127
3.29k
    if (!bucket)
128
0
  return FcFalse;
129
3.29k
    memset (bucket, 0, sizeof (FcHashBucket));
130
3.29k
    if (table->key_copy_func)
131
2.64k
  ret |= !table->key_copy_func (key, &bucket->key);
132
654
    else
133
654
  bucket->key = key;
134
3.29k
    if (table->value_copy_func)
135
0
  ret |= !table->value_copy_func (value, &bucket->value);
136
3.29k
    else
137
3.29k
  bucket->value = value;
138
3.29k
    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
3.29k
retry:
149
3.29k
    for (prev = &table->buckets[hash % FC_HASH_SIZE];
150
3.29k
         (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
3.29k
    bucket->next = NULL;
163
3.29k
    if (!fc_atomic_ptr_cmpexch (prev, b, bucket))
164
0
  goto retry;
165
166
3.29k
    return FcTrue;
167
3.29k
}
168
169
FcBool
170
FcHashTableAdd (FcHashTable *table,
171
                void        *key,
172
                void        *value)
173
3.29k
{
174
3.29k
    return FcHashTableAddInternal (table, key, value, FcFalse);
175
3.29k
}
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
}