fast-xml 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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_ */