fast-xml 1.1.0 → 1.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3bfc552fd27d382d26a930254300930396aed5da
4
- data.tar.gz: f960e2a0cd0b2c38ad983ca497a1ef0664422929
3
+ metadata.gz: e09415bf54f3b6a91bdb5f172164915201ac07cd
4
+ data.tar.gz: 3ece702f0638ec35967a90b0741451f056f08f55
5
5
  SHA512:
6
- metadata.gz: 958ee82a61a7d887f72dc89db46cc928a322012406ed816b368a03a0f35106ca6b6104e482d4deaa214ce66f7c471d4b15d267d03957b2da083693056309ac5a
7
- data.tar.gz: 3629dd0432f31eb23ef46fed569a942cf0f01749c33a2684109aa677d56442110d46264aac0bfa0250fdc63113eea3f95c6bd626a5cefd3c5b66b5afa734176f
6
+ metadata.gz: 4d2bd7962b208a0fce4dbec4fcc2d63e5f0a624766a2d07fee495850274d08e9f7ef42ae40c61fccfc245a29219b8faeaf9271581bc7e3097a421cd1aec3fa0d
7
+ data.tar.gz: 77e5159c4bc9fb4739077c6846f489c12b68c9c859a42e22f5916454c954b32ea81796f2715af97539e3e1403de36deeeb1ef2eaca54288be88abc68e1ad7738
data/README.md CHANGED
@@ -78,6 +78,7 @@ end
78
78
  # {"a"=>"aaa2"}
79
79
  ```
80
80
 
81
+
81
82
  ## Options
82
83
 
83
84
  The following options are available to pass to FastXML.hash2xml(hash, options = {}).
@@ -0,0 +1,25 @@
1
+ #ifndef _XH_RUBY_INTERNAL_H_
2
+ #define _XH_RUBY_INTERNAL_H_
3
+
4
+ #include "xh_config.h"
5
+ #include "xh_core.h"
6
+
7
+ struct RHash {
8
+ struct RBasic basic;
9
+ struct st_table *ntbl; /* possibly 0 */
10
+ int iter_lev;
11
+ const VALUE ifnone;
12
+ };
13
+
14
+ #define RHASH(obj) (R_CAST(RHash)(obj))
15
+
16
+ #ifdef RHASH_ITER_LEV
17
+ #undef RHASH_ITER_LEV
18
+ #undef RHASH_IFNONE
19
+ #undef RHASH_SIZE
20
+ #define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev)
21
+ #define RHASH_IFNONE(h) (RHASH(h)->ifnone)
22
+ #define RHASH_SIZE(h) (RHASH(h)->ntbl ? (st_index_t)RHASH(h)->ntbl->num_entries : 0)
23
+ #endif
24
+
25
+ #endif /* _XH_RUBY_INTERNAL_H_ */
@@ -0,0 +1,336 @@
1
+ #ifndef _XH_RUBY_ST_H_
2
+ #define _XH_RUBY_ST_H_
3
+
4
+ #include "xh_config.h"
5
+ #include "xh_core.h"
6
+ #include "xh_ruby_internal.h"
7
+
8
+ typedef struct st_table_entry st_table_entry;
9
+
10
+ struct st_table_entry {
11
+ st_index_t hash;
12
+ st_data_t key;
13
+ st_data_t record;
14
+ st_table_entry *next;
15
+ st_table_entry *fore, *back;
16
+ };
17
+
18
+ typedef struct st_packed_entry {
19
+ st_index_t hash;
20
+ st_data_t key, val;
21
+ } st_packed_entry;
22
+
23
+ #define ST_DEFAULT_MAX_DENSITY 5
24
+ #define ST_DEFAULT_INIT_TABLE_SIZE 16
25
+ #define ST_DEFAULT_PACKED_TABLE_SIZE 18
26
+ #define PACKED_UNIT (int)(sizeof(st_packed_entry) / sizeof(st_table_entry*))
27
+ #define MAX_PACKED_HASH (int)(ST_DEFAULT_PACKED_TABLE_SIZE * sizeof(st_table_entry*) / sizeof(st_packed_entry))
28
+
29
+ #define FNV1_32A_INIT 0x811c9dc5
30
+ #define FNV_32_PRIME 0x01000193
31
+
32
+ #define type_numhash st_hashtype_num
33
+ const struct st_hash_type st_hashtype_num = {
34
+ st_numcmp,
35
+ st_numhash,
36
+ };
37
+
38
+ static st_index_t
39
+ strcasehash(st_data_t arg)
40
+ {
41
+ register const char *string = (const char *)arg;
42
+ register st_index_t hval = FNV1_32A_INIT;
43
+
44
+ /*
45
+ * FNV-1a hash each octet in the buffer
46
+ */
47
+ while (*string) {
48
+ unsigned int c = (unsigned char)*string++;
49
+ if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
50
+ hval ^= c;
51
+
52
+ /* multiply by the 32 bit FNV magic prime mod 2^32 */
53
+ hval *= FNV_32_PRIME;
54
+ }
55
+ return hval;
56
+ }
57
+
58
+ static st_index_t
59
+ strhash(st_data_t arg)
60
+ {
61
+ register const char *string = (const char *)arg;
62
+ return st_hash(string, strlen(string), FNV1_32A_INIT);
63
+ }
64
+
65
+ /* extern int strcmp(const char *, const char *); */
66
+ static st_index_t strhash(st_data_t);
67
+ static const struct st_hash_type type_strhash = {
68
+ strcmp,
69
+ strhash,
70
+ };
71
+
72
+ static st_index_t strcasehash(st_data_t);
73
+ static const struct st_hash_type type_strcasehash = {
74
+ st_locale_insensitive_strcasecmp,
75
+ strcasehash,
76
+ };
77
+
78
+ #define EQUAL(table,x,y) ((x)==(y) || (*(table)->type->compare)((x),(y)) == 0)
79
+
80
+ #define do_hash(key,table) (st_index_t)(*(table)->type->hash)((key))
81
+ #define hash_pos(h,n) ((h) & (n - 1))
82
+
83
+ #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
84
+ ((ptr) != 0 && ((ptr)->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
85
+
86
+ /* preparation for possible allocation improvements */
87
+ #define st_alloc_entry() (st_table_entry *)malloc(sizeof(st_table_entry))
88
+ #define st_free_entry(entry) free(entry)
89
+ #define st_alloc_table() (st_table *)malloc(sizeof(st_table))
90
+ #define st_dealloc_table(table) free(table)
91
+ #define st_alloc_bins(size) (st_table_entry **)calloc(size, sizeof(st_table_entry *))
92
+ #define st_free_bins(bins, size) free(bins)
93
+ static inline st_table_entry**
94
+ st_realloc_bins(st_table_entry **bins, st_index_t newsize, st_index_t oldsize)
95
+ {
96
+ bins = (st_table_entry **)realloc(bins, newsize * sizeof(st_table_entry *));
97
+ MEMZERO(bins, st_table_entry*, newsize);
98
+ return bins;
99
+ }
100
+
101
+ /* Shortcut */
102
+ #define bins as.big.bins
103
+ #define head as.big.head
104
+ #define tail as.big.tail
105
+ #define real_entries as.packed.real_entries
106
+
107
+ /* preparation for possible packing improvements */
108
+ #define PACKED_BINS(table) ((table)->as.packed.entries)
109
+ #define PACKED_ENT(table, i) PACKED_BINS(table)[i]
110
+ #define PKEY(table, i) PACKED_ENT((table), (i)).key
111
+ #define PVAL(table, i) PACKED_ENT((table), (i)).val
112
+ #define PHASH(table, i) PACKED_ENT((table), (i)).hash
113
+ #define PKEY_SET(table, i, v) (PKEY((table), (i)) = (v))
114
+ #define PVAL_SET(table, i, v) (PVAL((table), (i)) = (v))
115
+ #define PHASH_SET(table, i, v) (PHASH((table), (i)) = (v))
116
+
117
+ static st_index_t
118
+ next_pow2(st_index_t x)
119
+ {
120
+ x |= x >> 1;
121
+ x |= x >> 2;
122
+ x |= x >> 4;
123
+ x |= x >> 8;
124
+ x |= x >> 16;
125
+ #if SIZEOF_ST_INDEX_T == 8
126
+ x |= x >> 32;
127
+ #endif
128
+ return x + 1;
129
+ }
130
+
131
+ static st_index_t
132
+ new_size(st_index_t size)
133
+ {
134
+ st_index_t n;
135
+
136
+ if (size && (size & ~(size - 1)) == size) /* already a power-of-two? */
137
+ return size;
138
+
139
+ n = next_pow2(size);
140
+ if (n > size)
141
+ return n;
142
+ #ifndef NOT_RUBY
143
+ rb_raise(rb_eRuntimeError, "st_table too big");
144
+ #endif
145
+ return -1; /* should raise exception */
146
+ }
147
+
148
+ static void
149
+ rehash(register st_table *table)
150
+ {
151
+ register st_table_entry *ptr = 0, **new_bins;
152
+ st_index_t new_num_bins, hash_val;
153
+
154
+ new_num_bins = new_size(table->num_bins+1);
155
+ new_bins = st_realloc_bins(table->bins, new_num_bins, table->num_bins);
156
+ table->num_bins = new_num_bins;
157
+ table->bins = new_bins;
158
+
159
+ if ((ptr = table->head) != 0) {
160
+ do {
161
+ hash_val = hash_pos(ptr->hash, new_num_bins);
162
+ ptr->next = new_bins[hash_val];
163
+ new_bins[hash_val] = ptr;
164
+ } while ((ptr = ptr->fore) != 0);
165
+ }
166
+ }
167
+
168
+ static st_table_entry *
169
+ find_entry(const st_table *table, st_data_t key, st_index_t hash_val,
170
+ st_index_t bin_pos)
171
+ {
172
+ register st_table_entry *ptr = table->bins[bin_pos];
173
+ if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {
174
+ while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {
175
+ ptr = ptr->next;
176
+ }
177
+ ptr = ptr->next;
178
+ }
179
+ return ptr;
180
+ }
181
+
182
+ static inline st_index_t
183
+ find_packed_index_from(const st_table *table, st_index_t hash_val,
184
+ st_data_t key, st_index_t i)
185
+ {
186
+ while (i < table->real_entries &&
187
+ (PHASH(table, i) != hash_val || !EQUAL(table, key, PKEY(table, i)))) {
188
+ i++;
189
+ }
190
+ return i;
191
+ }
192
+
193
+ static inline st_index_t
194
+ find_packed_index(const st_table *table, st_index_t hash_val, st_data_t key)
195
+ {
196
+ return find_packed_index_from(table, hash_val, key, 0);
197
+ }
198
+
199
+ static inline st_table_entry *
200
+ new_entry(st_table * table, st_data_t key, st_data_t value,
201
+ st_index_t hash_val, register st_index_t bin_pos)
202
+ {
203
+ register st_table_entry *entry = st_alloc_entry();
204
+
205
+ entry->next = table->bins[bin_pos];
206
+ table->bins[bin_pos] = entry;
207
+ entry->hash = hash_val;
208
+ entry->key = key;
209
+ entry->record = value;
210
+
211
+ return entry;
212
+ }
213
+
214
+ static inline st_data_t *
215
+ add_direct(st_table *table, st_data_t key, st_data_t value,
216
+ st_index_t hash_val, register st_index_t bin_pos)
217
+ {
218
+ register st_table_entry *entry;
219
+ if (table->num_entries > ST_DEFAULT_MAX_DENSITY * table->num_bins) {
220
+ rehash(table);
221
+ bin_pos = hash_pos(hash_val, table->num_bins);
222
+ }
223
+
224
+ entry = new_entry(table, key, value, hash_val, bin_pos);
225
+
226
+ if (table->head != 0) {
227
+ entry->fore = 0;
228
+ (entry->back = table->tail)->fore = entry;
229
+ table->tail = entry;
230
+ }
231
+ else {
232
+ table->head = table->tail = entry;
233
+ entry->fore = entry->back = 0;
234
+ }
235
+
236
+ table->num_entries++;
237
+ return &entry->record;
238
+ }
239
+
240
+ static void
241
+ unpack_entries(register st_table *table)
242
+ {
243
+ st_index_t i;
244
+ st_packed_entry packed_bins[MAX_PACKED_HASH];
245
+ register st_table_entry *entry, *preventry = 0, **chain;
246
+ st_table tmp_table = *table;
247
+
248
+ MEMCPY(packed_bins, PACKED_BINS(table), st_packed_entry, MAX_PACKED_HASH);
249
+ table->as.packed.entries = packed_bins;
250
+ tmp_table.entries_packed = 0;
251
+ #if ST_DEFAULT_INIT_TABLE_SIZE == ST_DEFAULT_PACKED_TABLE_SIZE
252
+ MEMZERO(tmp_table.bins, st_table_entry*, tmp_table.num_bins);
253
+ #else
254
+ tmp_table.bins = st_realloc_bins(tmp_table.bins, ST_DEFAULT_INIT_TABLE_SIZE, tmp_table.num_bins);
255
+ tmp_table.num_bins = ST_DEFAULT_INIT_TABLE_SIZE;
256
+ #endif
257
+
258
+ /*
259
+ * order is important here, we need to keep the original table
260
+ * walkable during GC (GC may be triggered by new_entry call)
261
+ */
262
+ i = 0;
263
+ chain = &tmp_table.head;
264
+ do {
265
+ st_data_t key = packed_bins[i].key;
266
+ st_data_t val = packed_bins[i].val;
267
+ st_index_t hash = packed_bins[i].hash;
268
+ entry = new_entry(&tmp_table, key, val, hash,
269
+ hash_pos(hash, ST_DEFAULT_INIT_TABLE_SIZE));
270
+ *chain = entry;
271
+ entry->back = preventry;
272
+ preventry = entry;
273
+ chain = &entry->fore;
274
+ } while (++i < MAX_PACKED_HASH);
275
+ *chain = NULL;
276
+ tmp_table.tail = entry;
277
+ *table = tmp_table;
278
+ }
279
+
280
+ static st_data_t *
281
+ add_packed_direct(st_table *table, st_data_t key, st_data_t value, st_index_t hash_val)
282
+ {
283
+ st_data_t *lval;
284
+
285
+ if (table->real_entries < MAX_PACKED_HASH) {
286
+ st_index_t i = table->real_entries++;
287
+ PKEY_SET(table, i, key);
288
+ PVAL_SET(table, i, value);
289
+ PHASH_SET(table, i, hash_val);
290
+ table->num_entries++;
291
+ lval = &PVAL(table, i);
292
+ }
293
+ else {
294
+ unpack_entries(table);
295
+ lval = add_direct(table, key, value, hash_val, hash_pos(hash_val, table->num_bins));
296
+ }
297
+
298
+ return lval;
299
+ }
300
+
301
+ static st_data_t *
302
+ st_store(register st_table *table, register st_data_t key, st_data_t value, xh_bool_t update)
303
+ {
304
+ st_index_t hash_val;
305
+ register st_index_t bin_pos;
306
+ register st_table_entry *ptr;
307
+ st_data_t *lval;
308
+
309
+ hash_val = do_hash(key, table);
310
+
311
+ if (table->entries_packed) {
312
+ st_index_t i = find_packed_index(table, hash_val, key);
313
+ if (i < table->real_entries) {
314
+ lval = &PVAL(table, i);
315
+ }
316
+ else {
317
+ lval = add_packed_direct(table, key, value, hash_val);
318
+ }
319
+ }
320
+ else {
321
+ ptr = find_entry(table, key, hash_val, bin_pos = hash_pos(hash_val, table->num_bins));
322
+
323
+ if (ptr == 0) {
324
+ lval = add_direct(table, key, value, hash_val, bin_pos);
325
+ }
326
+ else {
327
+ lval = &ptr->record;
328
+ }
329
+ }
330
+
331
+ if (update) *lval = value;
332
+
333
+ return lval;
334
+ }
335
+
336
+ #endif /* _XH_RUBY_ST_H_ */
@@ -0,0 +1,25 @@
1
+ #ifndef _XH_RUBY_INTERNAL_H_
2
+ #define _XH_RUBY_INTERNAL_H_
3
+
4
+ #include "xh_config.h"
5
+ #include "xh_core.h"
6
+
7
+ struct RHash {
8
+ struct RBasic basic;
9
+ struct st_table *ntbl; /* possibly 0 */
10
+ int iter_lev;
11
+ const VALUE ifnone;
12
+ };
13
+
14
+ #define RHASH(obj) (R_CAST(RHash)(obj))
15
+
16
+ #ifdef RHASH_ITER_LEV
17
+ #undef RHASH_ITER_LEV
18
+ #undef RHASH_IFNONE
19
+ #undef RHASH_SIZE
20
+ #define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev)
21
+ #define RHASH_IFNONE(h) (RHASH(h)->ifnone)
22
+ #define RHASH_SIZE(h) (RHASH(h)->ntbl ? (st_index_t)RHASH(h)->ntbl->num_entries : 0)
23
+ #endif
24
+
25
+ #endif /* _XH_RUBY_INTERNAL_H_ */
@@ -0,0 +1,329 @@
1
+ #ifndef _XH_RUBY_ST_H_
2
+ #define _XH_RUBY_ST_H_
3
+
4
+ #include "xh_config.h"
5
+ #include "xh_core.h"
6
+ #include "xh_ruby_internal.h"
7
+ #include "ccan/list/list.h"
8
+
9
+ typedef struct st_table_entry st_table_entry;
10
+
11
+ struct st_table_entry {
12
+ st_index_t hash;
13
+ st_data_t key;
14
+ st_data_t record;
15
+ st_table_entry *next;
16
+ struct list_node olist;
17
+ };
18
+
19
+ typedef struct st_packed_entry {
20
+ st_index_t hash;
21
+ st_data_t key, val;
22
+ } st_packed_entry;
23
+
24
+ #define ST_DEFAULT_MAX_DENSITY 5
25
+ #define ST_DEFAULT_INIT_TABLE_SIZE 16
26
+ #define ST_DEFAULT_PACKED_TABLE_SIZE 18
27
+ #define PACKED_UNIT (int)(sizeof(st_packed_entry) / sizeof(st_table_entry*))
28
+ #define MAX_PACKED_HASH (int)(ST_DEFAULT_PACKED_TABLE_SIZE * sizeof(st_table_entry*) / sizeof(st_packed_entry))
29
+
30
+ #define FNV1_32A_INIT 0x811c9dc5
31
+ #define FNV_32_PRIME 0x01000193
32
+
33
+ #define type_numhash st_hashtype_num
34
+ const struct st_hash_type st_hashtype_num = {
35
+ st_numcmp,
36
+ st_numhash,
37
+ };
38
+
39
+ static st_index_t
40
+ strcasehash(st_data_t arg)
41
+ {
42
+ register const char *string = (const char *)arg;
43
+ register st_index_t hval = FNV1_32A_INIT;
44
+
45
+ /*
46
+ * FNV-1a hash each octet in the buffer
47
+ */
48
+ while (*string) {
49
+ unsigned int c = (unsigned char)*string++;
50
+ if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
51
+ hval ^= c;
52
+
53
+ /* multiply by the 32 bit FNV magic prime mod 2^32 */
54
+ hval *= FNV_32_PRIME;
55
+ }
56
+ return hval;
57
+ }
58
+
59
+ static st_index_t
60
+ strhash(st_data_t arg)
61
+ {
62
+ register const char *string = (const char *)arg;
63
+ return st_hash(string, strlen(string), FNV1_32A_INIT);
64
+ }
65
+
66
+ /* extern int strcmp(const char *, const char *); */
67
+ static st_index_t strhash(st_data_t);
68
+ static const struct st_hash_type type_strhash = {
69
+ strcmp,
70
+ strhash,
71
+ };
72
+
73
+ static st_index_t strcasehash(st_data_t);
74
+ static const struct st_hash_type type_strcasehash = {
75
+ st_locale_insensitive_strcasecmp,
76
+ strcasehash,
77
+ };
78
+
79
+ #define EQUAL(table,x,ent) ((x)==(ent)->key || (*(table)->type->compare)((x),(ent)->key) == 0)
80
+
81
+ #define do_hash(key,table) (st_index_t)(*(table)->type->hash)((key))
82
+ #define hash_pos(h,n) ((h) & (n - 1))
83
+
84
+ #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
85
+ ((ptr) != 0 && ((ptr)->hash != (hash_val) || !EQUAL((table), (key), (ptr))))
86
+
87
+ /* preparation for possible allocation improvements */
88
+ #define st_alloc_entry() (st_table_entry *)malloc(sizeof(st_table_entry))
89
+ #define st_free_entry(entry) free(entry)
90
+ #define st_alloc_table() (st_table *)malloc(sizeof(st_table))
91
+ #define st_dealloc_table(table) free(table)
92
+ #define st_alloc_bins(size) (st_table_entry **)calloc(size, sizeof(st_table_entry *))
93
+ #define st_free_bins(bins, size) free(bins)
94
+ static inline st_table_entry**
95
+ st_realloc_bins(st_table_entry **bins, st_index_t newsize, st_index_t oldsize)
96
+ {
97
+ bins = (st_table_entry **)realloc(bins, newsize * sizeof(st_table_entry *));
98
+ MEMZERO(bins, st_table_entry*, newsize);
99
+ return bins;
100
+ }
101
+
102
+ /* Shortcut */
103
+ #define bins as.big.bins
104
+ #define real_entries as.packed.real_entries
105
+
106
+ /* preparation for possible packing improvements */
107
+ #define PACKED_BINS(table) ((table)->as.packed.entries)
108
+ #define PACKED_ENT(table, i) PACKED_BINS(table)[i]
109
+ #define PKEY(table, i) PACKED_ENT((table), (i)).key
110
+ #define PVAL(table, i) PACKED_ENT((table), (i)).val
111
+ #define PHASH(table, i) PACKED_ENT((table), (i)).hash
112
+ #define PKEY_SET(table, i, v) (PKEY((table), (i)) = (v))
113
+ #define PVAL_SET(table, i, v) (PVAL((table), (i)) = (v))
114
+ #define PHASH_SET(table, i, v) (PHASH((table), (i)) = (v))
115
+
116
+ static struct list_head *
117
+ st_head(const st_table *tbl)
118
+ {
119
+ uintptr_t addr = (uintptr_t)&tbl->as.big.private_list_head;
120
+ return (struct list_head *)addr;
121
+ }
122
+
123
+ static st_index_t
124
+ next_pow2(st_index_t x)
125
+ {
126
+ x |= x >> 1;
127
+ x |= x >> 2;
128
+ x |= x >> 4;
129
+ x |= x >> 8;
130
+ x |= x >> 16;
131
+ #if SIZEOF_ST_INDEX_T == 8
132
+ x |= x >> 32;
133
+ #endif
134
+ return x + 1;
135
+ }
136
+
137
+ static st_index_t
138
+ new_size(st_index_t size)
139
+ {
140
+ st_index_t n;
141
+
142
+ if (size && (size & ~(size - 1)) == size) /* already a power-of-two? */
143
+ return size;
144
+
145
+ n = next_pow2(size);
146
+ if (n > size)
147
+ return n;
148
+ #ifndef NOT_RUBY
149
+ rb_raise(rb_eRuntimeError, "st_table too big");
150
+ #endif
151
+ return -1; /* should raise exception */
152
+ }
153
+
154
+ static void
155
+ rehash(register st_table *table)
156
+ {
157
+ register st_table_entry *ptr = 0, **new_bins;
158
+ st_index_t new_num_bins, hash_val;
159
+
160
+ new_num_bins = new_size(table->num_bins+1);
161
+ new_bins = st_realloc_bins(table->bins, new_num_bins, table->num_bins);
162
+ table->num_bins = new_num_bins;
163
+ table->bins = new_bins;
164
+
165
+ list_for_each(st_head(table), ptr, olist) {
166
+ hash_val = hash_pos(ptr->hash, new_num_bins);
167
+ ptr->next = new_bins[hash_val];
168
+ new_bins[hash_val] = ptr;
169
+ }
170
+ }
171
+
172
+ static st_table_entry *
173
+ find_entry(const st_table *table, st_data_t key, st_index_t hash_val,
174
+ st_index_t bin_pos)
175
+ {
176
+ register st_table_entry *ptr = table->bins[bin_pos];
177
+ if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {
178
+ while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {
179
+ ptr = ptr->next;
180
+ }
181
+ ptr = ptr->next;
182
+ }
183
+ return ptr;
184
+ }
185
+
186
+ static inline st_index_t
187
+ find_packed_index_from(const st_table *table, st_index_t hash_val,
188
+ st_data_t key, st_index_t i)
189
+ {
190
+ while (i < table->real_entries &&
191
+ (PHASH(table, i) != hash_val || !EQUAL(table, key, &PACKED_ENT(table, i)))) {
192
+ i++;
193
+ }
194
+ return i;
195
+ }
196
+
197
+ static inline st_index_t
198
+ find_packed_index(const st_table *table, st_index_t hash_val, st_data_t key)
199
+ {
200
+ return find_packed_index_from(table, hash_val, key, 0);
201
+ }
202
+
203
+ static inline st_table_entry *
204
+ new_entry(st_table * table, st_data_t key, st_data_t value,
205
+ st_index_t hash_val, register st_index_t bin_pos)
206
+ {
207
+ register st_table_entry *entry = st_alloc_entry();
208
+
209
+ entry->next = table->bins[bin_pos];
210
+ table->bins[bin_pos] = entry;
211
+ entry->hash = hash_val;
212
+ entry->key = key;
213
+ entry->record = value;
214
+
215
+ return entry;
216
+ }
217
+
218
+ static inline st_data_t *
219
+ add_direct(st_table *table, st_data_t key, st_data_t value,
220
+ st_index_t hash_val, register st_index_t bin_pos)
221
+ {
222
+ register st_table_entry *entry;
223
+ if (table->num_entries > ST_DEFAULT_MAX_DENSITY * table->num_bins) {
224
+ rehash(table);
225
+ bin_pos = hash_pos(hash_val, table->num_bins);
226
+ }
227
+
228
+ entry = new_entry(table, key, value, hash_val, bin_pos);
229
+
230
+ list_add_tail(st_head(table), &entry->olist);
231
+
232
+ table->num_entries++;
233
+ return &entry->record;
234
+ }
235
+
236
+ static void
237
+ unpack_entries(register st_table *table)
238
+ {
239
+ st_index_t i;
240
+ st_packed_entry packed_bins[MAX_PACKED_HASH];
241
+ register st_table_entry *entry;
242
+ st_table tmp_table = *table;
243
+
244
+ MEMCPY(packed_bins, PACKED_BINS(table), st_packed_entry, MAX_PACKED_HASH);
245
+ table->as.packed.entries = packed_bins;
246
+ tmp_table.entries_packed = 0;
247
+ #if ST_DEFAULT_INIT_TABLE_SIZE == ST_DEFAULT_PACKED_TABLE_SIZE
248
+ MEMZERO(tmp_table.bins, st_table_entry*, tmp_table.num_bins);
249
+ #else
250
+ tmp_table.bins = st_realloc_bins(tmp_table.bins, ST_DEFAULT_INIT_TABLE_SIZE, tmp_table.num_bins);
251
+ tmp_table.num_bins = ST_DEFAULT_INIT_TABLE_SIZE;
252
+ #endif
253
+
254
+ /*
255
+ * order is important here, we need to keep the original table
256
+ * walkable during GC (GC may be triggered by new_entry call)
257
+ */
258
+ i = 0;
259
+ list_head_init(st_head(&tmp_table));
260
+ do {
261
+ st_data_t key = packed_bins[i].key;
262
+ st_data_t val = packed_bins[i].val;
263
+ st_index_t hash = packed_bins[i].hash;
264
+ entry = new_entry(&tmp_table, key, val, hash,
265
+ hash_pos(hash, ST_DEFAULT_INIT_TABLE_SIZE));
266
+ list_add_tail(st_head(&tmp_table), &entry->olist);
267
+ } while (++i < MAX_PACKED_HASH);
268
+ *table = tmp_table;
269
+ list_head_init(st_head(table));
270
+ list_append_list(st_head(table), st_head(&tmp_table));
271
+ }
272
+
273
+ static st_data_t *
274
+ add_packed_direct(st_table *table, st_data_t key, st_data_t value, st_index_t hash_val)
275
+ {
276
+ st_data_t *lval;
277
+
278
+ if (table->real_entries < MAX_PACKED_HASH) {
279
+ st_index_t i = table->real_entries++;
280
+ PKEY_SET(table, i, key);
281
+ PVAL_SET(table, i, value);
282
+ PHASH_SET(table, i, hash_val);
283
+ table->num_entries++;
284
+ lval = &PVAL(table, i);
285
+ }
286
+ else {
287
+ unpack_entries(table);
288
+ lval = add_direct(table, key, value, hash_val, hash_pos(hash_val, table->num_bins));
289
+ }
290
+
291
+ return lval;
292
+ }
293
+
294
+ static st_data_t *
295
+ st_store(register st_table *table, register st_data_t key, st_data_t value, xh_bool_t update)
296
+ {
297
+ st_index_t hash_val;
298
+ register st_index_t bin_pos;
299
+ register st_table_entry *ptr;
300
+ st_data_t *lval;
301
+
302
+ hash_val = do_hash(key, table);
303
+
304
+ if (table->entries_packed) {
305
+ st_index_t i = find_packed_index(table, hash_val, key);
306
+ if (i < table->real_entries) {
307
+ lval = &PVAL(table, i);
308
+ }
309
+ else {
310
+ lval = add_packed_direct(table, key, value, hash_val);
311
+ }
312
+ }
313
+ else {
314
+ ptr = find_entry(table, key, hash_val, bin_pos = hash_pos(hash_val, table->num_bins));
315
+
316
+ if (ptr == 0) {
317
+ lval = add_direct(table, key, value, hash_val, bin_pos);
318
+ }
319
+ else {
320
+ lval = &ptr->record;
321
+ }
322
+ }
323
+
324
+ if (update) *lval = value;
325
+
326
+ return lval;
327
+ }
328
+
329
+ #endif /* _XH_RUBY_ST_H_ */