/work/workdir/UnpackedTarball/fontconfig/src/fcserialize.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2006 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 copyright |
7 | | * notice and this permission notice appear in supporting documentation, and |
8 | | * that the name of the copyright holders not be used in advertising or |
9 | | * publicity pertaining to distribution of the software without specific, |
10 | | * written prior permission. The copyright holders make no representations |
11 | | * about the suitability of this software for any purpose. It is provided "as |
12 | | * is" without express or implied warranty. |
13 | | * |
14 | | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
15 | | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
16 | | * EVENT SHALL THE COPYRIGHT HOLDERS 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 PERFORMANCE |
20 | | * OF THIS SOFTWARE. |
21 | | */ |
22 | | |
23 | | #include "fcint.h" |
24 | | |
25 | | intptr_t |
26 | | FcAlignSize (intptr_t size) |
27 | 632 | { |
28 | 632 | intptr_t rem = size % sizeof (FcAlign); |
29 | 632 | if (rem) |
30 | 144 | size += sizeof (FcAlign) - rem; |
31 | 632 | return size; |
32 | 632 | } |
33 | | |
34 | | /* |
35 | | * Serialization helper object -- allocate space in the |
36 | | * yet-to-be-created linear array for a serialized font set |
37 | | */ |
38 | | |
39 | | FcSerialize * |
40 | | FcSerializeCreate (void) |
41 | 1 | { |
42 | 1 | FcSerialize *serialize; |
43 | | |
44 | 1 | serialize = malloc (sizeof (FcSerialize)); |
45 | 1 | if (!serialize) |
46 | 0 | return NULL; |
47 | 1 | serialize->size = 0; |
48 | 1 | serialize->linear = NULL; |
49 | 1 | serialize->cs_freezer = NULL; |
50 | 1 | serialize->buckets = NULL; |
51 | 1 | serialize->buckets_count = 0; |
52 | 1 | serialize->buckets_used = 0; |
53 | 1 | serialize->buckets_used_max = 0; |
54 | 1 | return serialize; |
55 | 1 | } |
56 | | |
57 | | void |
58 | | FcSerializeDestroy (FcSerialize *serialize) |
59 | 1 | { |
60 | 1 | free (serialize->buckets); |
61 | 1 | if (serialize->cs_freezer) |
62 | 1 | FcCharSetFreezerDestroy (serialize->cs_freezer); |
63 | 1 | free (serialize); |
64 | 1 | } |
65 | | |
66 | | static size_t |
67 | | FcSerializeNextBucketIndex (const FcSerialize *serialize, size_t index) |
68 | 3.79k | { |
69 | 3.79k | if (index == 0) |
70 | 26 | index = serialize->buckets_count; |
71 | 3.79k | --index; |
72 | 3.79k | return index; |
73 | 3.79k | } |
74 | | |
75 | | #if ((SIZEOF_VOID_P) * (CHAR_BIT)) == 32 |
76 | | |
77 | | /* |
78 | | * Based on triple32 |
79 | | * https://github.com/skeeto/hash-prospector |
80 | | */ |
81 | | static uintptr_t |
82 | | FcSerializeHashPtr (const void *object) |
83 | | { |
84 | | uintptr_t x = (uintptr_t)object; |
85 | | x ^= x >> 17; |
86 | | x *= 0xed5ad4bbU; |
87 | | x ^= x >> 11; |
88 | | x *= 0xac4c1b51U; |
89 | | x ^= x >> 15; |
90 | | x *= 0x31848babU; |
91 | | x ^= x >> 14; |
92 | | return x ? x : 1; /* 0 reserved to mark empty, x starts out 0 */ |
93 | | } |
94 | | |
95 | | #elif ((SIZEOF_VOID_P) * (CHAR_BIT)) == 64 |
96 | | |
97 | | /* |
98 | | * Based on splittable64/splitmix64 from Mix13 |
99 | | * https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html |
100 | | * https://prng.di.unimi.it/splitmix64.c |
101 | | */ |
102 | | static uintptr_t |
103 | | FcSerializeHashPtr (const void *object) |
104 | 2.38k | { |
105 | 2.38k | uintptr_t x = (uintptr_t)object; |
106 | 2.38k | x ^= x >> 30; |
107 | 2.38k | x *= 0xbf58476d1ce4e5b9U; |
108 | 2.38k | x ^= x >> 27; |
109 | 2.38k | x *= 0x94d049bb133111ebU; |
110 | 2.38k | x ^= x >> 31; |
111 | 2.38k | return x ? x : 1; /* 0 reserved to mark empty, x starts out 0 */ |
112 | 2.38k | } |
113 | | |
114 | | #endif |
115 | | |
116 | | static FcSerializeBucket * |
117 | | FcSerializeFind (const FcSerialize *serialize, const void *object) |
118 | 1.75k | { |
119 | 1.75k | uintptr_t hash = FcSerializeHashPtr (object); |
120 | 1.75k | size_t buckets_count = serialize->buckets_count; |
121 | 1.75k | size_t index = hash & (buckets_count - 1); |
122 | 3.89k | for (size_t n = 0; n < buckets_count; ++n) { |
123 | 3.89k | FcSerializeBucket *bucket = &serialize->buckets[index]; |
124 | 3.89k | if (bucket->hash == 0) { |
125 | 630 | return NULL; |
126 | 630 | } |
127 | 3.26k | if (object == bucket->object) { |
128 | 1.12k | return bucket; |
129 | 1.12k | } |
130 | 2.14k | index = FcSerializeNextBucketIndex (serialize, index); |
131 | 2.14k | } |
132 | 1 | return NULL; |
133 | 1.75k | } |
134 | | |
135 | | static FcSerializeBucket * |
136 | | FcSerializeUncheckedSet (FcSerialize *serialize, FcSerializeBucket *insert) |
137 | 1.39k | { |
138 | 1.39k | const void *object = insert->object; |
139 | 1.39k | size_t buckets_count = serialize->buckets_count; |
140 | 1.39k | size_t index = insert->hash & (buckets_count - 1); |
141 | 3.05k | for (size_t n = 0; n < buckets_count; ++n) { |
142 | 3.05k | FcSerializeBucket *bucket = &serialize->buckets[index]; |
143 | 3.05k | if (bucket->hash == 0) { |
144 | 1.39k | *bucket = *insert; |
145 | 1.39k | ++serialize->buckets_used; |
146 | 1.39k | return bucket; |
147 | 1.39k | } |
148 | 1.65k | if (object == bucket->object) { |
149 | | /* FcSerializeAlloc should not allow this to happen. */ |
150 | 0 | assert (0); |
151 | 0 | *bucket = *insert; |
152 | 0 | return bucket; |
153 | 0 | } |
154 | 1.65k | index = FcSerializeNextBucketIndex (serialize, index); |
155 | 1.65k | } |
156 | 0 | assert (0); |
157 | 0 | return NULL; |
158 | 0 | } |
159 | | |
160 | | static FcBool |
161 | | FcSerializeResize (FcSerialize *serialize, size_t new_count) |
162 | 9 | { |
163 | 9 | size_t old_used = serialize->buckets_used; |
164 | 9 | size_t old_count = serialize->buckets_count; |
165 | 9 | FcSerializeBucket *old_buckets = serialize->buckets; |
166 | 9 | FcSerializeBucket *old_buckets_end = old_buckets ? old_buckets + old_count : NULL; |
167 | | |
168 | 9 | FcSerializeBucket *new_buckets = malloc (new_count * sizeof (*old_buckets)); |
169 | 9 | if (!new_buckets) |
170 | 0 | return FcFalse; |
171 | 9 | FcSerializeBucket *new_buckets_end = new_buckets + new_count; |
172 | 2.05k | for (FcSerializeBucket *b = new_buckets; b < new_buckets_end; ++b) |
173 | 2.04k | b->hash = 0; |
174 | | |
175 | 9 | serialize->buckets = new_buckets; |
176 | 9 | serialize->buckets_count = new_count; |
177 | 9 | serialize->buckets_used = 0; |
178 | 1.02k | for (FcSerializeBucket *b = old_buckets; b < old_buckets_end; ++b) |
179 | 1.02k | if (b->hash != 0 && !FcSerializeUncheckedSet (serialize, b)) { |
180 | 0 | serialize->buckets = old_buckets; |
181 | 0 | serialize->buckets_count = old_count; |
182 | 0 | serialize->buckets_used = old_used; |
183 | 0 | free (new_buckets); |
184 | 0 | return FcFalse; |
185 | 0 | } |
186 | 9 | free (old_buckets); |
187 | 9 | return FcTrue; |
188 | 9 | } |
189 | | |
190 | | static FcSerializeBucket * |
191 | | FcSerializeSet (FcSerialize *serialize, const void *object, intptr_t offset) |
192 | 631 | { |
193 | 631 | if (serialize->buckets_used >= serialize->buckets_used_max) { |
194 | 9 | size_t capacity = serialize->buckets_count; |
195 | 9 | if (capacity == 0) |
196 | 1 | capacity = 4; |
197 | 8 | else if (capacity > SIZE_MAX / 2u) |
198 | 0 | return NULL; |
199 | 8 | else |
200 | 8 | capacity *= 2; |
201 | | |
202 | 9 | if (!FcSerializeResize (serialize, capacity)) |
203 | 0 | return NULL; |
204 | | |
205 | 9 | serialize->buckets_used_max = capacity / 4u * 3u; |
206 | 9 | } |
207 | | |
208 | 631 | FcSerializeBucket bucket; |
209 | 631 | bucket.object = object; |
210 | 631 | bucket.offset = offset; |
211 | 631 | bucket.hash = FcSerializeHashPtr (object); |
212 | 631 | return FcSerializeUncheckedSet (serialize, &bucket); |
213 | 631 | } |
214 | | |
215 | | /* |
216 | | * Allocate space for an object in the serialized array. Keep track |
217 | | * of where the object is placed and only allocate one copy of each object |
218 | | */ |
219 | | FcBool |
220 | | FcSerializeAlloc (FcSerialize *serialize, const void *object, int size) |
221 | 879 | { |
222 | 879 | FcSerializeBucket *bucket = FcSerializeFind (serialize, object); |
223 | 879 | if (bucket) |
224 | 248 | return FcTrue; |
225 | | |
226 | 631 | if (!FcSerializeSet (serialize, object, serialize->size)) |
227 | 0 | return FcFalse; |
228 | | |
229 | 631 | serialize->size += FcAlignSize (size); |
230 | 631 | return FcTrue; |
231 | 631 | } |
232 | | |
233 | | /* |
234 | | * Reserve space in the serialization array |
235 | | */ |
236 | | intptr_t |
237 | | FcSerializeReserve (FcSerialize *serialize, int size) |
238 | 1 | { |
239 | 1 | intptr_t offset = serialize->size; |
240 | 1 | serialize->size += FcAlignSize (size); |
241 | 1 | return offset; |
242 | 1 | } |
243 | | |
244 | | /* |
245 | | * Given an object, return the offset in the serialized array where |
246 | | * the serialized copy of the object is stored |
247 | | */ |
248 | | intptr_t |
249 | | FcSerializeOffset (FcSerialize *serialize, const void *object) |
250 | 879 | { |
251 | 879 | FcSerializeBucket *bucket = FcSerializeFind (serialize, object); |
252 | 879 | return bucket ? bucket->offset : 0; |
253 | 879 | } |
254 | | |
255 | | /* |
256 | | * Given a cache and an object, return a pointer to where |
257 | | * the serialized copy of the object is stored |
258 | | */ |
259 | | void * |
260 | | FcSerializePtr (FcSerialize *serialize, const void *object) |
261 | 879 | { |
262 | 879 | intptr_t offset = FcSerializeOffset (serialize, object); |
263 | | |
264 | 879 | if (!offset) |
265 | 0 | return NULL; |
266 | 879 | return (void *)((char *)serialize->linear + offset); |
267 | 879 | } |
268 | | |
269 | | FcBool |
270 | | FcStrSerializeAlloc (FcSerialize *serialize, const FcChar8 *str) |
271 | 156 | { |
272 | 156 | return FcSerializeAlloc (serialize, str, strlen ((const char *)str) + 1); |
273 | 156 | } |
274 | | |
275 | | FcChar8 * |
276 | | FcStrSerialize (FcSerialize *serialize, const FcChar8 *str) |
277 | 156 | { |
278 | 156 | FcChar8 *str_serialize = FcSerializePtr (serialize, str); |
279 | 156 | if (!str_serialize) |
280 | 0 | return NULL; |
281 | 156 | strcpy ((char *)str_serialize, (const char *)str); |
282 | 156 | return str_serialize; |
283 | 156 | } |
284 | | #include "fcaliastail.h" |
285 | | #undef __fcserialize__ |