ucl 0.1.3.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/LICENSE-DEPENDENCIES.md +161 -0
- data/README.md +270 -0
- data/ext/extconf.rb +67 -3
- data/ext/libucl/COPYING +23 -0
- data/ext/libucl/include/ucl.h +1689 -0
- data/ext/libucl/klib/khash.h +627 -0
- data/ext/libucl/klib/kvec.h +161 -0
- data/ext/libucl/src/mum.h +440 -0
- data/ext/libucl/src/tree.h +209 -0
- data/ext/libucl/src/ucl_chartable.h +267 -0
- data/ext/libucl/src/ucl_emitter.c +721 -0
- data/ext/libucl/src/ucl_emitter_streamline.c +178 -0
- data/ext/libucl/src/ucl_emitter_utils.c +521 -0
- data/ext/libucl/src/ucl_hash.c +642 -0
- data/ext/libucl/src/ucl_hash.h +115 -0
- data/ext/libucl/src/ucl_internal.h +668 -0
- data/ext/libucl/src/ucl_msgpack.c +1574 -0
- data/ext/libucl/src/ucl_parser.c +3247 -0
- data/ext/libucl/src/ucl_schema.c +1102 -0
- data/ext/libucl/src/ucl_sexp.c +229 -0
- data/ext/libucl/src/ucl_util.c +4004 -0
- data/ext/libucl/uthash/uthash.h +720 -0
- data/ext/libucl/uthash/utlist.h +1076 -0
- data/ext/libucl/uthash/utstring.h +412 -0
- data/ext/ucl.c +398 -90
- data/test/test_ucl.rb +452 -0
- data/ucl.gemspec +30 -7
- metadata +77 -14
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
/* Copyright (c) 2013, Vsevolod Stakhov
|
|
2
|
+
* All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Redistribution and use in source and binary forms, with or without
|
|
5
|
+
* modification, are permitted provided that the following conditions are met:
|
|
6
|
+
* * Redistributions of source code must retain the above copyright
|
|
7
|
+
* notice, this list of conditions and the following disclaimer.
|
|
8
|
+
* * Redistributions in binary form must reproduce the above copyright
|
|
9
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
10
|
+
* documentation and/or other materials provided with the distribution.
|
|
11
|
+
*
|
|
12
|
+
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
|
|
13
|
+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
14
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
15
|
+
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
|
|
16
|
+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
17
|
+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
18
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
19
|
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
20
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
21
|
+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
#include "ucl_internal.h"
|
|
25
|
+
#include "ucl_hash.h"
|
|
26
|
+
#include "khash.h"
|
|
27
|
+
#include "kvec.h"
|
|
28
|
+
#include "mum.h"
|
|
29
|
+
|
|
30
|
+
#include <time.h>
|
|
31
|
+
#include <limits.h>
|
|
32
|
+
|
|
33
|
+
struct ucl_hash_elt {
|
|
34
|
+
const ucl_object_t *obj;
|
|
35
|
+
struct ucl_hash_elt *prev, *next;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
struct ucl_hash_struct {
|
|
39
|
+
void *hash;
|
|
40
|
+
struct ucl_hash_elt *head;
|
|
41
|
+
bool caseless;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
static uint64_t
|
|
45
|
+
ucl_hash_seed(void)
|
|
46
|
+
{
|
|
47
|
+
static uint64_t seed;
|
|
48
|
+
if (seed == 0) {
|
|
49
|
+
#ifdef UCL_RANDOM_FUNCTION
|
|
50
|
+
seed = UCL_RANDOM_FUNCTION;
|
|
51
|
+
#else
|
|
52
|
+
/* Not very random but can be useful for our purposes */
|
|
53
|
+
seed = time(NULL);
|
|
54
|
+
#endif
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return seed;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static const unsigned char lc_map[256] = {
|
|
61
|
+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
62
|
+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
63
|
+
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
64
|
+
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
|
65
|
+
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
|
66
|
+
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
|
67
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
68
|
+
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
|
69
|
+
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
|
70
|
+
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
|
71
|
+
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
|
72
|
+
0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
|
73
|
+
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
|
74
|
+
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
|
75
|
+
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
|
76
|
+
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
|
77
|
+
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
|
78
|
+
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
|
79
|
+
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
|
80
|
+
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
|
81
|
+
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
|
82
|
+
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
|
83
|
+
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
|
84
|
+
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
|
85
|
+
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
|
86
|
+
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
|
87
|
+
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
|
88
|
+
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
|
89
|
+
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
|
90
|
+
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
|
91
|
+
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
|
92
|
+
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
|
|
93
|
+
|
|
94
|
+
#if (defined(WORD_BIT) && WORD_BIT == 64) || \
|
|
95
|
+
(defined(__WORDSIZE) && __WORDSIZE == 64) || \
|
|
96
|
+
defined(__x86_64__) || \
|
|
97
|
+
defined(__amd64__)
|
|
98
|
+
#define UCL64_BIT_HASH 1
|
|
99
|
+
#endif
|
|
100
|
+
|
|
101
|
+
static inline uint32_t
|
|
102
|
+
ucl_hash_func(const ucl_object_t *o)
|
|
103
|
+
{
|
|
104
|
+
return mum_hash(o->key, o->keylen, ucl_hash_seed());
|
|
105
|
+
}
|
|
106
|
+
static inline int
|
|
107
|
+
ucl_hash_equal(const ucl_object_t *k1, const ucl_object_t *k2)
|
|
108
|
+
{
|
|
109
|
+
if (k1->keylen == k2->keylen) {
|
|
110
|
+
return memcmp(k1->key, k2->key, k1->keylen) == 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
KHASH_INIT(ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt *, 1,
|
|
117
|
+
ucl_hash_func, ucl_hash_equal)
|
|
118
|
+
|
|
119
|
+
static inline uint32_t
|
|
120
|
+
ucl_hash_caseless_func(const ucl_object_t *o)
|
|
121
|
+
{
|
|
122
|
+
unsigned len = o->keylen;
|
|
123
|
+
unsigned leftover = o->keylen % 8;
|
|
124
|
+
unsigned fp, i;
|
|
125
|
+
const uint8_t *s = (const uint8_t *) o->key;
|
|
126
|
+
union {
|
|
127
|
+
struct {
|
|
128
|
+
unsigned char c1, c2, c3, c4, c5, c6, c7, c8;
|
|
129
|
+
} c;
|
|
130
|
+
uint64_t pp;
|
|
131
|
+
} u;
|
|
132
|
+
uint64_t r;
|
|
133
|
+
|
|
134
|
+
fp = len - leftover;
|
|
135
|
+
r = ucl_hash_seed();
|
|
136
|
+
|
|
137
|
+
for (i = 0; i != fp; i += 8) {
|
|
138
|
+
u.c.c1 = s[i], u.c.c2 = s[i + 1], u.c.c3 = s[i + 2], u.c.c4 = s[i + 3];
|
|
139
|
+
u.c.c5 = s[i + 4], u.c.c6 = s[i + 5], u.c.c7 = s[i + 6], u.c.c8 = s[i + 7];
|
|
140
|
+
u.c.c1 = lc_map[u.c.c1];
|
|
141
|
+
u.c.c2 = lc_map[u.c.c2];
|
|
142
|
+
u.c.c3 = lc_map[u.c.c3];
|
|
143
|
+
u.c.c4 = lc_map[u.c.c4];
|
|
144
|
+
u.c.c5 = lc_map[u.c.c5];
|
|
145
|
+
u.c.c6 = lc_map[u.c.c6];
|
|
146
|
+
u.c.c7 = lc_map[u.c.c7];
|
|
147
|
+
u.c.c8 = lc_map[u.c.c8];
|
|
148
|
+
r = mum_hash_step(r, u.pp);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
u.pp = 0;
|
|
152
|
+
switch (leftover) {
|
|
153
|
+
case 7:
|
|
154
|
+
u.c.c7 = lc_map[(unsigned char) s[i++]];
|
|
155
|
+
/* FALLTHRU */
|
|
156
|
+
case 6:
|
|
157
|
+
u.c.c6 = lc_map[(unsigned char) s[i++]];
|
|
158
|
+
/* FALLTHRU */
|
|
159
|
+
case 5:
|
|
160
|
+
u.c.c5 = lc_map[(unsigned char) s[i++]];
|
|
161
|
+
/* FALLTHRU */
|
|
162
|
+
case 4:
|
|
163
|
+
u.c.c4 = lc_map[(unsigned char) s[i++]];
|
|
164
|
+
/* FALLTHRU */
|
|
165
|
+
case 3:
|
|
166
|
+
u.c.c3 = lc_map[(unsigned char) s[i++]];
|
|
167
|
+
/* FALLTHRU */
|
|
168
|
+
case 2:
|
|
169
|
+
u.c.c2 = lc_map[(unsigned char) s[i++]];
|
|
170
|
+
/* FALLTHRU */
|
|
171
|
+
case 1:
|
|
172
|
+
u.c.c1 = lc_map[(unsigned char) s[i]];
|
|
173
|
+
r = mum_hash_step(r, u.pp);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return mum_hash_finish(r);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static inline int
|
|
181
|
+
ucl_hash_caseless_equal(const ucl_object_t *k1, const ucl_object_t *k2)
|
|
182
|
+
{
|
|
183
|
+
if (k1->keylen == k2->keylen) {
|
|
184
|
+
unsigned fp, i;
|
|
185
|
+
const char *s = k1->key, *d = k2->key;
|
|
186
|
+
unsigned char c1, c2, c3, c4;
|
|
187
|
+
union {
|
|
188
|
+
unsigned char c[4];
|
|
189
|
+
uint32_t n;
|
|
190
|
+
} cmp1, cmp2;
|
|
191
|
+
size_t leftover = k1->keylen % 4;
|
|
192
|
+
|
|
193
|
+
fp = k1->keylen - leftover;
|
|
194
|
+
|
|
195
|
+
for (i = 0; i != fp; i += 4) {
|
|
196
|
+
c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
|
|
197
|
+
cmp1.c[0] = lc_map[c1];
|
|
198
|
+
cmp1.c[1] = lc_map[c2];
|
|
199
|
+
cmp1.c[2] = lc_map[c3];
|
|
200
|
+
cmp1.c[3] = lc_map[c4];
|
|
201
|
+
|
|
202
|
+
c1 = d[i], c2 = d[i + 1], c3 = d[i + 2], c4 = d[i + 3];
|
|
203
|
+
cmp2.c[0] = lc_map[c1];
|
|
204
|
+
cmp2.c[1] = lc_map[c2];
|
|
205
|
+
cmp2.c[2] = lc_map[c3];
|
|
206
|
+
cmp2.c[3] = lc_map[c4];
|
|
207
|
+
|
|
208
|
+
if (cmp1.n != cmp2.n) {
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
while (leftover > 0) {
|
|
214
|
+
if (lc_map[(unsigned char) s[i]] != lc_map[(unsigned char) d[i]]) {
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
leftover--;
|
|
219
|
+
i++;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return 1;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
KHASH_INIT(ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt *, 1,
|
|
229
|
+
ucl_hash_caseless_func, ucl_hash_caseless_equal)
|
|
230
|
+
|
|
231
|
+
ucl_hash_t *
|
|
232
|
+
ucl_hash_create(bool ignore_case)
|
|
233
|
+
{
|
|
234
|
+
ucl_hash_t *new;
|
|
235
|
+
|
|
236
|
+
new = UCL_ALLOC(sizeof(ucl_hash_t));
|
|
237
|
+
if (new != NULL) {
|
|
238
|
+
void *h;
|
|
239
|
+
new->head = NULL;
|
|
240
|
+
new->caseless = ignore_case;
|
|
241
|
+
if (ignore_case) {
|
|
242
|
+
h = (void *) kh_init(ucl_hash_caseless_node);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
h = (void *) kh_init(ucl_hash_node);
|
|
246
|
+
}
|
|
247
|
+
if (h == NULL) {
|
|
248
|
+
UCL_FREE(sizeof(ucl_hash_t), new);
|
|
249
|
+
return NULL;
|
|
250
|
+
}
|
|
251
|
+
new->hash = h;
|
|
252
|
+
}
|
|
253
|
+
return new;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
void ucl_hash_destroy(ucl_hash_t *hashlin, ucl_hash_free_func func)
|
|
257
|
+
{
|
|
258
|
+
|
|
259
|
+
if (hashlin == NULL) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (func != NULL) {
|
|
264
|
+
/* Iterate over the hash first */
|
|
265
|
+
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
266
|
+
hashlin->hash;
|
|
267
|
+
khiter_t k;
|
|
268
|
+
const ucl_object_t *cur, *tmp;
|
|
269
|
+
|
|
270
|
+
for (k = kh_begin(h); k != kh_end(h); ++k) {
|
|
271
|
+
if (kh_exist(h, k)) {
|
|
272
|
+
cur = (kh_value(h, k))->obj;
|
|
273
|
+
while (cur != NULL) {
|
|
274
|
+
tmp = cur->next;
|
|
275
|
+
func(__DECONST(ucl_object_t *, cur));
|
|
276
|
+
cur = tmp;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (hashlin->caseless) {
|
|
283
|
+
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
|
284
|
+
hashlin->hash;
|
|
285
|
+
kh_destroy(ucl_hash_caseless_node, h);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
289
|
+
hashlin->hash;
|
|
290
|
+
kh_destroy(ucl_hash_node, h);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
struct ucl_hash_elt *cur, *tmp;
|
|
294
|
+
|
|
295
|
+
DL_FOREACH_SAFE(hashlin->head, cur, tmp)
|
|
296
|
+
{
|
|
297
|
+
UCL_FREE(sizeof(*cur), cur);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
UCL_FREE(sizeof(*hashlin), hashlin);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
bool ucl_hash_insert(ucl_hash_t *hashlin, const ucl_object_t *obj,
|
|
304
|
+
const char *key, unsigned keylen)
|
|
305
|
+
{
|
|
306
|
+
khiter_t k;
|
|
307
|
+
int ret;
|
|
308
|
+
struct ucl_hash_elt **pelt, *elt;
|
|
309
|
+
|
|
310
|
+
if (hashlin == NULL) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (hashlin->caseless) {
|
|
315
|
+
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
|
316
|
+
hashlin->hash;
|
|
317
|
+
k = kh_put(ucl_hash_caseless_node, h, obj, &ret);
|
|
318
|
+
if (ret > 0) {
|
|
319
|
+
elt = UCL_ALLOC(sizeof(*elt));
|
|
320
|
+
pelt = &kh_value(h, k);
|
|
321
|
+
*pelt = elt;
|
|
322
|
+
DL_APPEND(hashlin->head, elt);
|
|
323
|
+
elt->obj = obj;
|
|
324
|
+
}
|
|
325
|
+
else if (ret < 0) {
|
|
326
|
+
goto e0;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
331
|
+
hashlin->hash;
|
|
332
|
+
k = kh_put(ucl_hash_node, h, obj, &ret);
|
|
333
|
+
if (ret > 0) {
|
|
334
|
+
elt = UCL_ALLOC(sizeof(*elt));
|
|
335
|
+
pelt = &kh_value(h, k);
|
|
336
|
+
*pelt = elt;
|
|
337
|
+
DL_APPEND(hashlin->head, elt);
|
|
338
|
+
elt->obj = obj;
|
|
339
|
+
}
|
|
340
|
+
else if (ret < 0) {
|
|
341
|
+
goto e0;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return true;
|
|
345
|
+
e0:
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
void ucl_hash_replace(ucl_hash_t *hashlin, const ucl_object_t *old,
|
|
350
|
+
const ucl_object_t *new)
|
|
351
|
+
{
|
|
352
|
+
khiter_t k;
|
|
353
|
+
int ret;
|
|
354
|
+
struct ucl_hash_elt *elt, *nelt;
|
|
355
|
+
|
|
356
|
+
if (hashlin == NULL) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (hashlin->caseless) {
|
|
361
|
+
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
|
362
|
+
hashlin->hash;
|
|
363
|
+
k = kh_put(ucl_hash_caseless_node, h, old, &ret);
|
|
364
|
+
if (ret == 0) {
|
|
365
|
+
elt = kh_value(h, k);
|
|
366
|
+
kh_del(ucl_hash_caseless_node, h, k);
|
|
367
|
+
k = kh_put(ucl_hash_caseless_node, h, new, &ret);
|
|
368
|
+
nelt = UCL_ALLOC(sizeof(*nelt));
|
|
369
|
+
nelt->obj = new;
|
|
370
|
+
kh_value(h, k) = nelt;
|
|
371
|
+
DL_REPLACE_ELEM(hashlin->head, elt, nelt);
|
|
372
|
+
UCL_FREE(sizeof(*elt), elt);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
377
|
+
hashlin->hash;
|
|
378
|
+
k = kh_put(ucl_hash_node, h, old, &ret);
|
|
379
|
+
if (ret == 0) {
|
|
380
|
+
elt = kh_value(h, k);
|
|
381
|
+
kh_del(ucl_hash_node, h, k);
|
|
382
|
+
k = kh_put(ucl_hash_node, h, new, &ret);
|
|
383
|
+
nelt = UCL_ALLOC(sizeof(*nelt));
|
|
384
|
+
nelt->obj = new;
|
|
385
|
+
kh_value(h, k) = nelt;
|
|
386
|
+
DL_REPLACE_ELEM(hashlin->head, elt, nelt);
|
|
387
|
+
UCL_FREE(sizeof(*elt), elt);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
struct ucl_hash_real_iter {
|
|
393
|
+
const struct ucl_hash_elt *cur;
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
#define UHI_SETERR(ep, ern) \
|
|
397
|
+
{ \
|
|
398
|
+
if (ep != NULL) *ep = (ern); \
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const void *
|
|
402
|
+
ucl_hash_iterate2(ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep)
|
|
403
|
+
{
|
|
404
|
+
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *) (*iter);
|
|
405
|
+
const ucl_object_t *ret = NULL;
|
|
406
|
+
|
|
407
|
+
if (hashlin == NULL) {
|
|
408
|
+
UHI_SETERR(ep, EINVAL);
|
|
409
|
+
return NULL;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (it == NULL) {
|
|
413
|
+
it = UCL_ALLOC(sizeof(*it));
|
|
414
|
+
|
|
415
|
+
if (it == NULL) {
|
|
416
|
+
UHI_SETERR(ep, ENOMEM);
|
|
417
|
+
return NULL;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
it->cur = hashlin->head;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
UHI_SETERR(ep, 0);
|
|
424
|
+
if (it->cur) {
|
|
425
|
+
ret = it->cur->obj;
|
|
426
|
+
it->cur = it->cur->next;
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
UCL_FREE(sizeof(*it), it);
|
|
430
|
+
*iter = NULL;
|
|
431
|
+
return NULL;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
*iter = it;
|
|
435
|
+
|
|
436
|
+
return ret;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
bool ucl_hash_iter_has_next(ucl_hash_t *hashlin, ucl_hash_iter_t iter)
|
|
440
|
+
{
|
|
441
|
+
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *) (iter);
|
|
442
|
+
|
|
443
|
+
return it->cur != NULL;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
void ucl_hash_iterate_free(ucl_hash_iter_t iter)
|
|
447
|
+
{
|
|
448
|
+
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *) (iter);
|
|
449
|
+
|
|
450
|
+
if (it != NULL) {
|
|
451
|
+
UCL_FREE(sizeof(*it), it);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const ucl_object_t *
|
|
456
|
+
ucl_hash_search(ucl_hash_t *hashlin, const char *key, unsigned keylen)
|
|
457
|
+
{
|
|
458
|
+
khiter_t k;
|
|
459
|
+
const ucl_object_t *ret = NULL;
|
|
460
|
+
ucl_object_t search;
|
|
461
|
+
struct ucl_hash_elt *elt;
|
|
462
|
+
|
|
463
|
+
search.key = key;
|
|
464
|
+
search.keylen = keylen;
|
|
465
|
+
|
|
466
|
+
if (hashlin == NULL) {
|
|
467
|
+
return NULL;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (hashlin->caseless) {
|
|
471
|
+
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
|
472
|
+
hashlin->hash;
|
|
473
|
+
|
|
474
|
+
k = kh_get(ucl_hash_caseless_node, h, &search);
|
|
475
|
+
if (k != kh_end(h)) {
|
|
476
|
+
elt = kh_value(h, k);
|
|
477
|
+
ret = elt->obj;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
482
|
+
hashlin->hash;
|
|
483
|
+
k = kh_get(ucl_hash_node, h, &search);
|
|
484
|
+
if (k != kh_end(h)) {
|
|
485
|
+
elt = kh_value(h, k);
|
|
486
|
+
ret = elt->obj;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return ret;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
void ucl_hash_delete(ucl_hash_t *hashlin, const ucl_object_t *obj)
|
|
494
|
+
{
|
|
495
|
+
khiter_t k;
|
|
496
|
+
struct ucl_hash_elt *elt;
|
|
497
|
+
|
|
498
|
+
if (hashlin == NULL) {
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (hashlin->caseless) {
|
|
503
|
+
khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
|
|
504
|
+
hashlin->hash;
|
|
505
|
+
|
|
506
|
+
k = kh_get(ucl_hash_caseless_node, h, obj);
|
|
507
|
+
if (k != kh_end(h)) {
|
|
508
|
+
elt = kh_value(h, k);
|
|
509
|
+
DL_DELETE(hashlin->head, elt);
|
|
510
|
+
kh_del(ucl_hash_caseless_node, h, k);
|
|
511
|
+
UCL_FREE(sizeof(*elt), elt);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
516
|
+
hashlin->hash;
|
|
517
|
+
k = kh_get(ucl_hash_node, h, obj);
|
|
518
|
+
if (k != kh_end(h)) {
|
|
519
|
+
elt = kh_value(h, k);
|
|
520
|
+
DL_DELETE(hashlin->head, elt);
|
|
521
|
+
kh_del(ucl_hash_node, h, k);
|
|
522
|
+
UCL_FREE(sizeof(*elt), elt);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
bool ucl_hash_reserve(ucl_hash_t *hashlin, size_t sz)
|
|
528
|
+
{
|
|
529
|
+
if (hashlin == NULL) {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (sz > kh_size((khash_t(ucl_hash_node) *) hashlin->hash)) {
|
|
534
|
+
if (hashlin->caseless) {
|
|
535
|
+
khash_t(ucl_hash_caseless_node) *h = (khash_t(
|
|
536
|
+
ucl_hash_caseless_node) *)
|
|
537
|
+
hashlin->hash;
|
|
538
|
+
kh_resize(ucl_hash_caseless_node, h, sz * 2);
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
|
542
|
+
hashlin->hash;
|
|
543
|
+
kh_resize(ucl_hash_node, h, sz * 2);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
static int
|
|
550
|
+
ucl_lc_cmp(const char *s, const char *d, size_t l)
|
|
551
|
+
{
|
|
552
|
+
unsigned int fp, i;
|
|
553
|
+
unsigned char c1, c2, c3, c4;
|
|
554
|
+
union {
|
|
555
|
+
unsigned char c[4];
|
|
556
|
+
uint32_t n;
|
|
557
|
+
} cmp1, cmp2;
|
|
558
|
+
size_t leftover = l % 4;
|
|
559
|
+
int ret = 0;
|
|
560
|
+
|
|
561
|
+
fp = l - leftover;
|
|
562
|
+
|
|
563
|
+
for (i = 0; i != fp; i += 4) {
|
|
564
|
+
c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
|
|
565
|
+
cmp1.c[0] = lc_map[c1];
|
|
566
|
+
cmp1.c[1] = lc_map[c2];
|
|
567
|
+
cmp1.c[2] = lc_map[c3];
|
|
568
|
+
cmp1.c[3] = lc_map[c4];
|
|
569
|
+
|
|
570
|
+
c1 = d[i], c2 = d[i + 1], c3 = d[i + 2], c4 = d[i + 3];
|
|
571
|
+
cmp2.c[0] = lc_map[c1];
|
|
572
|
+
cmp2.c[1] = lc_map[c2];
|
|
573
|
+
cmp2.c[2] = lc_map[c3];
|
|
574
|
+
cmp2.c[3] = lc_map[c4];
|
|
575
|
+
|
|
576
|
+
if (cmp1.n != cmp2.n) {
|
|
577
|
+
return cmp1.n - cmp2.n;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
while (leftover > 0) {
|
|
582
|
+
if (lc_map[(unsigned char) s[i]] != lc_map[(unsigned char) d[i]]) {
|
|
583
|
+
return s[i] - d[i];
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
leftover--;
|
|
587
|
+
i++;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return ret;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
static int
|
|
594
|
+
ucl_hash_cmp_icase(const void *a, const void *b)
|
|
595
|
+
{
|
|
596
|
+
const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *) a,
|
|
597
|
+
*ob = (const struct ucl_hash_elt *) b;
|
|
598
|
+
|
|
599
|
+
if (oa->obj->keylen == ob->obj->keylen) {
|
|
600
|
+
return ucl_lc_cmp(oa->obj->key, ob->obj->key, oa->obj->keylen);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return ((int) (oa->obj->keylen)) - ob->obj->keylen;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
static int
|
|
607
|
+
ucl_hash_cmp_case_sens(const void *a, const void *b)
|
|
608
|
+
{
|
|
609
|
+
const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *) a,
|
|
610
|
+
*ob = (const struct ucl_hash_elt *) b;
|
|
611
|
+
|
|
612
|
+
if (oa->obj->keylen == ob->obj->keylen) {
|
|
613
|
+
return memcmp(oa->obj->key, ob->obj->key, oa->obj->keylen);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return ((int) (oa->obj->keylen)) - ob->obj->keylen;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
void ucl_hash_sort(ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl)
|
|
620
|
+
{
|
|
621
|
+
if (hashlin == NULL) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (fl & UCL_SORT_KEYS_ICASE) {
|
|
626
|
+
DL_SORT(hashlin->head, ucl_hash_cmp_icase);
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
DL_SORT(hashlin->head, ucl_hash_cmp_case_sens);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (fl & UCL_SORT_KEYS_RECURSIVE) {
|
|
633
|
+
struct ucl_hash_elt *elt;
|
|
634
|
+
|
|
635
|
+
DL_FOREACH(hashlin->head, elt)
|
|
636
|
+
{
|
|
637
|
+
if (ucl_object_type(elt->obj) == UCL_OBJECT) {
|
|
638
|
+
ucl_hash_sort(elt->obj->value.ov, fl);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|