fast-xml 1.1.2 → 1.1.3
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 +5 -5
- data/ext/fastxml/{ruby-2.4.1 → ruby-2.4.5}/xh_ruby_internal.h +0 -0
- data/ext/fastxml/{ruby-2.4.1 → ruby-2.4.5}/xh_ruby_st.h +70 -14
- data/ext/fastxml/ruby-2.5.1/xh_ruby_internal.h +25 -0
- data/ext/fastxml/ruby-2.5.1/xh_ruby_st.h +847 -0
- data/ext/fastxml/xh.c +3 -0
- data/ext/fastxml/xh_ruby_hash.h +7 -3
- data/lib/fastxml/version.rb +1 -1
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 607a72bcf9b089b76e70a8078d4768796db8b7426efe6c0bdd660e63a01ae1df
|
4
|
+
data.tar.gz: 7b31855d8c39a0892d67b176725934f9ec28a53b761679dfb614c82fb5b99056
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 819dc52f307e49d3496ac9aeb8da7da4c7f34b2979b0d6c47d946bdf7b8b514763f1f3e000c5381d92337f83016c8c4f80a7b714b89eb7bbc80f37c60bedd51a
|
7
|
+
data.tar.gz: 536e502352bfaf594f5d1ededdd342f3af5990d7a297ae04cb93394aa2607a64d440d5bb0b71cf518022d95ab03dc09cdc3d3a7f73abffa258764b743892824b
|
File without changes
|
@@ -70,6 +70,15 @@ static const struct st_hash_type type_strcasehash = {
|
|
70
70
|
#define PTR_EQUAL(tab, ptr, hash_val, key) \
|
71
71
|
((ptr)->hash == (hash_val) && EQUAL((tab), (key), (ptr)->key))
|
72
72
|
|
73
|
+
/* As PRT_EQUAL only its result is returned in RES. REBUILT_P is set
|
74
|
+
up to TRUE if the table is rebuilt during the comparison. */
|
75
|
+
#define DO_PTR_EQUAL_CHECK(tab, ptr, hash_val, key, res, rebuilt_p) \
|
76
|
+
do { \
|
77
|
+
unsigned int _old_rebuilds_num = (tab)->rebuilds_num; \
|
78
|
+
res = PTR_EQUAL(tab, ptr, hash_val, key); \
|
79
|
+
rebuilt_p = _old_rebuilds_num != (tab)->rebuilds_num; \
|
80
|
+
} while (FALSE)
|
81
|
+
|
73
82
|
/* Features of a table. */
|
74
83
|
struct st_features {
|
75
84
|
/* Power of 2 used for number of allocated entries. */
|
@@ -219,6 +228,11 @@ do_hash(st_data_t key, st_table *tab)
|
|
219
228
|
value, don't allocate bins and use a linear search. */
|
220
229
|
#define MAX_POWER2_FOR_TABLES_WITHOUT_BINS 4
|
221
230
|
|
231
|
+
/* Entry and bin values returned when we found a table rebuild during
|
232
|
+
the search. */
|
233
|
+
#define REBUILT_TABLE_ENTRY_IND (~(st_index_t) 1)
|
234
|
+
#define REBUILT_TABLE_BIN_IND (~(st_index_t) 1)
|
235
|
+
|
222
236
|
/* Return value of N-th bin in array BINS of table with bins size
|
223
237
|
index S. */
|
224
238
|
static inline st_index_t
|
@@ -393,6 +407,30 @@ static st_index_t
|
|
393
407
|
find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
|
394
408
|
st_data_t key, st_index_t *bin_ind);
|
395
409
|
|
410
|
+
#ifdef HASH_LOG
|
411
|
+
static void
|
412
|
+
count_collision(const struct st_hash_type *type)
|
413
|
+
{
|
414
|
+
collision.all++;
|
415
|
+
if (type == &type_numhash) {
|
416
|
+
collision.num++;
|
417
|
+
}
|
418
|
+
else if (type == &type_strhash) {
|
419
|
+
collision.strcase++;
|
420
|
+
}
|
421
|
+
else if (type == &type_strcasehash) {
|
422
|
+
collision.str++;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
|
426
|
+
#define COLLISION (collision_check ? count_collision(tab->type) : (void)0)
|
427
|
+
#define FOUND_BIN (collision_check ? collision.total++ : (void)0)
|
428
|
+
#define collision_check 0
|
429
|
+
#else
|
430
|
+
#define COLLISION
|
431
|
+
#define FOUND_BIN
|
432
|
+
#endif
|
433
|
+
|
396
434
|
/* If the number of entries in the table is at least REBUILD_THRESHOLD
|
397
435
|
times less than the entry array length, decrease the table
|
398
436
|
size. */
|
@@ -498,17 +536,22 @@ secondary_hash(st_index_t ind, st_table *tab, st_index_t *perterb)
|
|
498
536
|
|
499
537
|
/* Find an entry with HASH_VALUE and KEY in TABLE using a linear
|
500
538
|
search. Return the index of the found entry in array `entries`.
|
501
|
-
If it is not found, return UNDEFINED_ENTRY_IND.
|
539
|
+
If it is not found, return UNDEFINED_ENTRY_IND. If the table was
|
540
|
+
rebuilt during the search, return REBUILT_TABLE_ENTRY_IND. */
|
502
541
|
static inline st_index_t
|
503
542
|
find_entry(st_table *tab, st_hash_t hash_value, st_data_t key)
|
504
543
|
{
|
544
|
+
int eq_p, rebuilt_p;
|
505
545
|
st_index_t i, bound;
|
506
546
|
st_table_entry *entries;
|
507
547
|
|
508
548
|
bound = tab->entries_bound;
|
509
549
|
entries = tab->entries;
|
510
550
|
for (i = tab->entries_start; i < bound; i++) {
|
511
|
-
|
551
|
+
DO_PTR_EQUAL_CHECK(tab, &entries[i], hash_value, key, eq_p, rebuilt_p);
|
552
|
+
if (EXPECT(rebuilt_p, 0))
|
553
|
+
return REBUILT_TABLE_ENTRY_IND;
|
554
|
+
if (eq_p)
|
512
555
|
return i;
|
513
556
|
}
|
514
557
|
return UNDEFINED_ENTRY_IND;
|
@@ -536,17 +579,19 @@ find_table_bin_ind_direct(st_table *tab, st_hash_t hash_value, st_data_t key)
|
|
536
579
|
#else
|
537
580
|
peterb = hash_value;
|
538
581
|
#endif
|
582
|
+
FOUND_BIN;
|
539
583
|
for (;;) {
|
540
584
|
bin = get_bin(tab->bins, get_size_ind(tab), ind);
|
541
585
|
if (EMPTY_OR_DELETED_BIN_P(bin))
|
542
586
|
return ind;
|
543
|
-
st_assert (
|
587
|
+
st_assert (entries[bin - ENTRY_BASE].hash != hash_value);
|
544
588
|
#ifdef QUADRATIC_PROBE
|
545
589
|
ind = hash_bin(ind + d, tab);
|
546
590
|
d++;
|
547
591
|
#else
|
548
592
|
ind = secondary_hash(ind, tab, &peterb);
|
549
593
|
#endif
|
594
|
+
COLLISION;
|
550
595
|
}
|
551
596
|
}
|
552
597
|
|
@@ -557,10 +602,12 @@ find_table_bin_ind_direct(st_table *tab, st_hash_t hash_value, st_data_t key)
|
|
557
602
|
bigger entries array. Although we can reuse a deleted bin, the
|
558
603
|
result bin value is always empty if the table has no entry with
|
559
604
|
KEY. Return the entries array index of the found entry or
|
560
|
-
UNDEFINED_ENTRY_IND if it is not found.
|
605
|
+
UNDEFINED_ENTRY_IND if it is not found. If the table was rebuilt
|
606
|
+
during the search, return REBUILT_TABLE_ENTRY_IND. */
|
561
607
|
static st_index_t
|
562
608
|
find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
|
563
609
|
st_data_t key, st_index_t *bin_ind) {
|
610
|
+
int eq_p, rebuilt_p;
|
564
611
|
st_index_t ind;
|
565
612
|
st_hash_t curr_hash_value = *hash_value;
|
566
613
|
#ifdef QUADRATIC_PROBE
|
@@ -581,6 +628,7 @@ find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
|
|
581
628
|
#else
|
582
629
|
peterb = curr_hash_value;
|
583
630
|
#endif
|
631
|
+
FOUND_BIN;
|
584
632
|
first_deleted_bin_ind = UNDEFINED_BIN_IND;
|
585
633
|
entries = tab->entries;
|
586
634
|
for (;;) {
|
@@ -595,7 +643,10 @@ find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
|
|
595
643
|
}
|
596
644
|
break;
|
597
645
|
} else if (! DELETED_BIN_P(entry_index)) {
|
598
|
-
|
646
|
+
DO_PTR_EQUAL_CHECK(tab, &entries[entry_index - ENTRY_BASE], curr_hash_value, key, eq_p, rebuilt_p);
|
647
|
+
if (EXPECT(rebuilt_p, 0))
|
648
|
+
return REBUILT_TABLE_ENTRY_IND;
|
649
|
+
if (eq_p)
|
599
650
|
break;
|
600
651
|
} else if (first_deleted_bin_ind == UNDEFINED_BIN_IND)
|
601
652
|
first_deleted_bin_ind = ind;
|
@@ -605,12 +656,12 @@ find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
|
|
605
656
|
#else
|
606
657
|
ind = secondary_hash(ind, tab, &peterb);
|
607
658
|
#endif
|
659
|
+
COLLISION;
|
608
660
|
}
|
609
661
|
*bin_ind = ind;
|
610
662
|
return entry_index;
|
611
663
|
}
|
612
664
|
|
613
|
-
|
614
665
|
/* Check the table and rebuild it if it is necessary. */
|
615
666
|
static inline void
|
616
667
|
rebuild_table_if_necessary (st_table *tab)
|
@@ -724,12 +775,12 @@ strcasehash(st_data_t arg)
|
|
724
775
|
* FNV-1a hash each octet in the buffer
|
725
776
|
*/
|
726
777
|
while (*string) {
|
727
|
-
|
728
|
-
|
729
|
-
|
778
|
+
unsigned int c = (unsigned char)*string++;
|
779
|
+
if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
|
780
|
+
hval ^= c;
|
730
781
|
|
731
|
-
|
732
|
-
|
782
|
+
/* multiply by the 32 bit FNV magic prime mod 2^32 */
|
783
|
+
hval *= FNV_32_PRIME;
|
733
784
|
}
|
734
785
|
return hval;
|
735
786
|
}
|
@@ -745,17 +796,22 @@ st_store(st_table *tab, st_data_t key, st_data_t value, xh_bool_t update)
|
|
745
796
|
int new_p;
|
746
797
|
st_data_t *lval;
|
747
798
|
|
748
|
-
|
799
|
+
|
749
800
|
hash_value = do_hash(key, tab);
|
801
|
+
retry:
|
802
|
+
rebuild_table_if_necessary(tab);
|
750
803
|
if (tab->bins == NULL) {
|
751
804
|
bin = find_entry(tab, hash_value, key);
|
805
|
+
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
|
806
|
+
goto retry;
|
752
807
|
new_p = bin == UNDEFINED_ENTRY_IND;
|
753
808
|
if (new_p)
|
754
809
|
tab->num_entries++;
|
755
810
|
bin_ind = UNDEFINED_BIN_IND;
|
756
811
|
} else {
|
757
|
-
bin = find_table_bin_ptr_and_reserve(tab, &hash_value,
|
758
|
-
|
812
|
+
bin = find_table_bin_ptr_and_reserve(tab, &hash_value, key, &bin_ind);
|
813
|
+
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
|
814
|
+
goto retry;
|
759
815
|
new_p = bin == UNDEFINED_ENTRY_IND;
|
760
816
|
bin -= ENTRY_BASE;
|
761
817
|
}
|
@@ -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,847 @@
|
|
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
|
+
#ifdef __GNUC__
|
9
|
+
#define PREFETCH(addr, write_p) __builtin_prefetch(addr, write_p)
|
10
|
+
#define EXPECT(expr, val) __builtin_expect(expr, val)
|
11
|
+
#define ATTRIBUTE_UNUSED __attribute__((unused))
|
12
|
+
#else
|
13
|
+
#define PREFETCH(addr, write_p)
|
14
|
+
#define EXPECT(expr, val) (expr)
|
15
|
+
#define ATTRIBUTE_UNUSED
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#ifdef ST_DEBUG
|
19
|
+
#define st_assert(cond) assert(cond)
|
20
|
+
#else
|
21
|
+
#define st_assert(cond) ((void)(0 && (cond)))
|
22
|
+
#endif
|
23
|
+
|
24
|
+
/* The type of hashes. */
|
25
|
+
typedef st_index_t st_hash_t;
|
26
|
+
|
27
|
+
struct st_table_entry {
|
28
|
+
st_hash_t hash;
|
29
|
+
st_data_t key;
|
30
|
+
st_data_t record;
|
31
|
+
};
|
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
|
+
/* extern int strcmp(const char *, const char *); */
|
40
|
+
static st_index_t strhash(st_data_t);
|
41
|
+
static const struct st_hash_type type_strhash = {
|
42
|
+
strcmp,
|
43
|
+
strhash,
|
44
|
+
};
|
45
|
+
|
46
|
+
static st_index_t strcasehash(st_data_t);
|
47
|
+
static const struct st_hash_type type_strcasehash = {
|
48
|
+
st_locale_insensitive_strcasecmp,
|
49
|
+
strcasehash,
|
50
|
+
};
|
51
|
+
|
52
|
+
/* Value used to catch uninitialized entries/bins during debugging.
|
53
|
+
There is a possibility for a false alarm, but its probability is
|
54
|
+
extremely small. */
|
55
|
+
#define ST_INIT_VAL 0xafafafafafafafaf
|
56
|
+
#define ST_INIT_VAL_BYTE 0xafa
|
57
|
+
|
58
|
+
#ifdef RUBY
|
59
|
+
#undef malloc
|
60
|
+
#undef realloc
|
61
|
+
#undef calloc
|
62
|
+
#undef free
|
63
|
+
#define malloc ruby_xmalloc
|
64
|
+
#define calloc ruby_xcalloc
|
65
|
+
#define realloc ruby_xrealloc
|
66
|
+
#define free ruby_xfree
|
67
|
+
#endif
|
68
|
+
|
69
|
+
#define EQUAL(tab,x,y) ((x) == (y) || (*(tab)->type->compare)((x),(y)) == 0)
|
70
|
+
#define PTR_EQUAL(tab, ptr, hash_val, key) \
|
71
|
+
((ptr)->hash == (hash_val) && EQUAL((tab), (key), (ptr)->key))
|
72
|
+
|
73
|
+
/* As PRT_EQUAL only its result is returned in RES. REBUILT_P is set
|
74
|
+
up to TRUE if the table is rebuilt during the comparison. */
|
75
|
+
#define DO_PTR_EQUAL_CHECK(tab, ptr, hash_val, key, res, rebuilt_p) \
|
76
|
+
do { \
|
77
|
+
unsigned int _old_rebuilds_num = (tab)->rebuilds_num; \
|
78
|
+
res = PTR_EQUAL(tab, ptr, hash_val, key); \
|
79
|
+
rebuilt_p = _old_rebuilds_num != (tab)->rebuilds_num; \
|
80
|
+
} while (FALSE)
|
81
|
+
|
82
|
+
/* Features of a table. */
|
83
|
+
struct st_features {
|
84
|
+
/* Power of 2 used for number of allocated entries. */
|
85
|
+
unsigned char entry_power;
|
86
|
+
/* Power of 2 used for number of allocated bins. Depending on the
|
87
|
+
table size, the number of bins is 2-4 times more than the
|
88
|
+
number of entries. */
|
89
|
+
unsigned char bin_power;
|
90
|
+
/* Enumeration of sizes of bins (8-bit, 16-bit etc). */
|
91
|
+
unsigned char size_ind;
|
92
|
+
/* Bins are packed in words of type st_index_t. The following is
|
93
|
+
a size of bins counted by words. */
|
94
|
+
st_index_t bins_words;
|
95
|
+
};
|
96
|
+
|
97
|
+
/* Features of all possible size tables. */
|
98
|
+
#if SIZEOF_ST_INDEX_T == 8
|
99
|
+
#define MAX_POWER2 62
|
100
|
+
static const struct st_features features[] = {
|
101
|
+
{0, 1, 0, 0x0},
|
102
|
+
{1, 2, 0, 0x1},
|
103
|
+
{2, 3, 0, 0x1},
|
104
|
+
{3, 4, 0, 0x2},
|
105
|
+
{4, 5, 0, 0x4},
|
106
|
+
{5, 6, 0, 0x8},
|
107
|
+
{6, 7, 0, 0x10},
|
108
|
+
{7, 8, 0, 0x20},
|
109
|
+
{8, 9, 1, 0x80},
|
110
|
+
{9, 10, 1, 0x100},
|
111
|
+
{10, 11, 1, 0x200},
|
112
|
+
{11, 12, 1, 0x400},
|
113
|
+
{12, 13, 1, 0x800},
|
114
|
+
{13, 14, 1, 0x1000},
|
115
|
+
{14, 15, 1, 0x2000},
|
116
|
+
{15, 16, 1, 0x4000},
|
117
|
+
{16, 17, 2, 0x10000},
|
118
|
+
{17, 18, 2, 0x20000},
|
119
|
+
{18, 19, 2, 0x40000},
|
120
|
+
{19, 20, 2, 0x80000},
|
121
|
+
{20, 21, 2, 0x100000},
|
122
|
+
{21, 22, 2, 0x200000},
|
123
|
+
{22, 23, 2, 0x400000},
|
124
|
+
{23, 24, 2, 0x800000},
|
125
|
+
{24, 25, 2, 0x1000000},
|
126
|
+
{25, 26, 2, 0x2000000},
|
127
|
+
{26, 27, 2, 0x4000000},
|
128
|
+
{27, 28, 2, 0x8000000},
|
129
|
+
{28, 29, 2, 0x10000000},
|
130
|
+
{29, 30, 2, 0x20000000},
|
131
|
+
{30, 31, 2, 0x40000000},
|
132
|
+
{31, 32, 2, 0x80000000},
|
133
|
+
{32, 33, 3, 0x200000000},
|
134
|
+
{33, 34, 3, 0x400000000},
|
135
|
+
{34, 35, 3, 0x800000000},
|
136
|
+
{35, 36, 3, 0x1000000000},
|
137
|
+
{36, 37, 3, 0x2000000000},
|
138
|
+
{37, 38, 3, 0x4000000000},
|
139
|
+
{38, 39, 3, 0x8000000000},
|
140
|
+
{39, 40, 3, 0x10000000000},
|
141
|
+
{40, 41, 3, 0x20000000000},
|
142
|
+
{41, 42, 3, 0x40000000000},
|
143
|
+
{42, 43, 3, 0x80000000000},
|
144
|
+
{43, 44, 3, 0x100000000000},
|
145
|
+
{44, 45, 3, 0x200000000000},
|
146
|
+
{45, 46, 3, 0x400000000000},
|
147
|
+
{46, 47, 3, 0x800000000000},
|
148
|
+
{47, 48, 3, 0x1000000000000},
|
149
|
+
{48, 49, 3, 0x2000000000000},
|
150
|
+
{49, 50, 3, 0x4000000000000},
|
151
|
+
{50, 51, 3, 0x8000000000000},
|
152
|
+
{51, 52, 3, 0x10000000000000},
|
153
|
+
{52, 53, 3, 0x20000000000000},
|
154
|
+
{53, 54, 3, 0x40000000000000},
|
155
|
+
{54, 55, 3, 0x80000000000000},
|
156
|
+
{55, 56, 3, 0x100000000000000},
|
157
|
+
{56, 57, 3, 0x200000000000000},
|
158
|
+
{57, 58, 3, 0x400000000000000},
|
159
|
+
{58, 59, 3, 0x800000000000000},
|
160
|
+
{59, 60, 3, 0x1000000000000000},
|
161
|
+
{60, 61, 3, 0x2000000000000000},
|
162
|
+
{61, 62, 3, 0x4000000000000000},
|
163
|
+
{62, 63, 3, 0x8000000000000000},
|
164
|
+
};
|
165
|
+
|
166
|
+
#else
|
167
|
+
#define MAX_POWER2 30
|
168
|
+
|
169
|
+
static const struct st_features features[] = {
|
170
|
+
{0, 1, 0, 0x1},
|
171
|
+
{1, 2, 0, 0x1},
|
172
|
+
{2, 3, 0, 0x2},
|
173
|
+
{3, 4, 0, 0x4},
|
174
|
+
{4, 5, 0, 0x8},
|
175
|
+
{5, 6, 0, 0x10},
|
176
|
+
{6, 7, 0, 0x20},
|
177
|
+
{7, 8, 0, 0x40},
|
178
|
+
{8, 9, 1, 0x100},
|
179
|
+
{9, 10, 1, 0x200},
|
180
|
+
{10, 11, 1, 0x400},
|
181
|
+
{11, 12, 1, 0x800},
|
182
|
+
{12, 13, 1, 0x1000},
|
183
|
+
{13, 14, 1, 0x2000},
|
184
|
+
{14, 15, 1, 0x4000},
|
185
|
+
{15, 16, 1, 0x8000},
|
186
|
+
{16, 17, 2, 0x20000},
|
187
|
+
{17, 18, 2, 0x40000},
|
188
|
+
{18, 19, 2, 0x80000},
|
189
|
+
{19, 20, 2, 0x100000},
|
190
|
+
{20, 21, 2, 0x200000},
|
191
|
+
{21, 22, 2, 0x400000},
|
192
|
+
{22, 23, 2, 0x800000},
|
193
|
+
{23, 24, 2, 0x1000000},
|
194
|
+
{24, 25, 2, 0x2000000},
|
195
|
+
{25, 26, 2, 0x4000000},
|
196
|
+
{26, 27, 2, 0x8000000},
|
197
|
+
{27, 28, 2, 0x10000000},
|
198
|
+
{28, 29, 2, 0x20000000},
|
199
|
+
{29, 30, 2, 0x40000000},
|
200
|
+
{30, 31, 2, 0x80000000},
|
201
|
+
};
|
202
|
+
|
203
|
+
#endif
|
204
|
+
|
205
|
+
/* The reserved hash value and its substitution. */
|
206
|
+
#define RESERVED_HASH_VAL (~(st_hash_t) 0)
|
207
|
+
#define RESERVED_HASH_SUBSTITUTION_VAL ((st_hash_t) 0)
|
208
|
+
|
209
|
+
/* Return hash value of KEY for table TAB. */
|
210
|
+
static inline st_hash_t
|
211
|
+
do_hash(st_data_t key, st_table *tab)
|
212
|
+
{
|
213
|
+
st_hash_t hash = (st_hash_t)(tab->type->hash)(key);
|
214
|
+
|
215
|
+
/* RESERVED_HASH_VAL is used for a deleted entry. Map it into
|
216
|
+
another value. Such mapping should be extremely rare. */
|
217
|
+
return hash == RESERVED_HASH_VAL ? RESERVED_HASH_SUBSTITUTION_VAL : hash;
|
218
|
+
}
|
219
|
+
|
220
|
+
/* Power of 2 defining the minimal number of allocated entries. */
|
221
|
+
#define MINIMAL_POWER2 2
|
222
|
+
|
223
|
+
#if MINIMAL_POWER2 < 2
|
224
|
+
#error "MINIMAL_POWER2 should be >= 2"
|
225
|
+
#endif
|
226
|
+
|
227
|
+
/* If the power2 of the allocated `entries` is less than the following
|
228
|
+
value, don't allocate bins and use a linear search. */
|
229
|
+
#define MAX_POWER2_FOR_TABLES_WITHOUT_BINS 4
|
230
|
+
|
231
|
+
/* Entry and bin values returned when we found a table rebuild during
|
232
|
+
the search. */
|
233
|
+
#define REBUILT_TABLE_ENTRY_IND (~(st_index_t) 1)
|
234
|
+
#define REBUILT_TABLE_BIN_IND (~(st_index_t) 1)
|
235
|
+
|
236
|
+
/* Return value of N-th bin in array BINS of table with bins size
|
237
|
+
index S. */
|
238
|
+
static inline st_index_t
|
239
|
+
get_bin(st_index_t *bins, int s, st_index_t n)
|
240
|
+
{
|
241
|
+
return (s == 0 ? ((unsigned char *) bins)[n]
|
242
|
+
: s == 1 ? ((unsigned short *) bins)[n]
|
243
|
+
: s == 2 ? ((unsigned int *) bins)[n]
|
244
|
+
: ((st_index_t *) bins)[n]);
|
245
|
+
}
|
246
|
+
|
247
|
+
/* Set up N-th bin in array BINS of table with bins size index S to
|
248
|
+
value V. */
|
249
|
+
static inline void
|
250
|
+
set_bin(st_index_t *bins, int s, st_index_t n, st_index_t v)
|
251
|
+
{
|
252
|
+
if (s == 0) ((unsigned char *) bins)[n] = (unsigned char) v;
|
253
|
+
else if (s == 1) ((unsigned short *) bins)[n] = (unsigned short) v;
|
254
|
+
else if (s == 2) ((unsigned int *) bins)[n] = (unsigned int) v;
|
255
|
+
else ((st_index_t *) bins)[n] = v;
|
256
|
+
}
|
257
|
+
|
258
|
+
/* These macros define reserved values for empty table bin and table
|
259
|
+
bin which contains a deleted entry. We will never use such values
|
260
|
+
for an entry index in bins. */
|
261
|
+
#define EMPTY_BIN 0
|
262
|
+
#define DELETED_BIN 1
|
263
|
+
/* Base of a real entry index in the bins. */
|
264
|
+
#define ENTRY_BASE 2
|
265
|
+
|
266
|
+
/* Mark I-th bin of table TAB as empty, in other words not
|
267
|
+
corresponding to any entry. */
|
268
|
+
#define MARK_BIN_EMPTY(tab, i) (set_bin((tab)->bins, get_size_ind(tab), i, EMPTY_BIN))
|
269
|
+
|
270
|
+
/* Values used for not found entry and bin with given
|
271
|
+
characteristics. */
|
272
|
+
#define UNDEFINED_ENTRY_IND (~(st_index_t) 0)
|
273
|
+
#define UNDEFINED_BIN_IND (~(st_index_t) 0)
|
274
|
+
|
275
|
+
/* Mark I-th bin of table TAB as corresponding to a deleted table
|
276
|
+
entry. Update number of entries in the table and number of bins
|
277
|
+
corresponding to deleted entries. */
|
278
|
+
#define MARK_BIN_DELETED(tab, i) \
|
279
|
+
do { \
|
280
|
+
st_assert(i != UNDEFINED_BIN_IND); \
|
281
|
+
st_assert(! IND_EMPTY_OR_DELETED_BIN_P(tab, i)); \
|
282
|
+
set_bin((tab)->bins, get_size_ind(tab), i, DELETED_BIN); \
|
283
|
+
} while (0)
|
284
|
+
|
285
|
+
/* Macros to check that value B is used empty bins and bins
|
286
|
+
corresponding deleted entries. */
|
287
|
+
#define EMPTY_BIN_P(b) ((b) == EMPTY_BIN)
|
288
|
+
#define DELETED_BIN_P(b) ((b) == DELETED_BIN)
|
289
|
+
#define EMPTY_OR_DELETED_BIN_P(b) ((b) <= DELETED_BIN)
|
290
|
+
|
291
|
+
/* Macros to check empty bins and bins corresponding to deleted
|
292
|
+
entries. Bins are given by their index I in table TAB. */
|
293
|
+
#define IND_EMPTY_BIN_P(tab, i) (EMPTY_BIN_P(get_bin((tab)->bins, get_size_ind(tab), i)))
|
294
|
+
#define IND_DELETED_BIN_P(tab, i) (DELETED_BIN_P(get_bin((tab)->bins, get_size_ind(tab), i)))
|
295
|
+
#define IND_EMPTY_OR_DELETED_BIN_P(tab, i) (EMPTY_OR_DELETED_BIN_P(get_bin((tab)->bins, get_size_ind(tab), i)))
|
296
|
+
|
297
|
+
/* Macros for marking and checking deleted entries given by their
|
298
|
+
pointer E_PTR. */
|
299
|
+
#define MARK_ENTRY_DELETED(e_ptr) ((e_ptr)->hash = RESERVED_HASH_VAL)
|
300
|
+
#define DELETED_ENTRY_P(e_ptr) ((e_ptr)->hash == RESERVED_HASH_VAL)
|
301
|
+
|
302
|
+
/* Return bin size index of table TAB. */
|
303
|
+
static inline unsigned int
|
304
|
+
get_size_ind(const st_table *tab)
|
305
|
+
{
|
306
|
+
return tab->size_ind;
|
307
|
+
}
|
308
|
+
|
309
|
+
/* Return the number of allocated bins of table TAB. */
|
310
|
+
static inline st_index_t
|
311
|
+
get_bins_num(const st_table *tab)
|
312
|
+
{
|
313
|
+
return ((st_index_t) 1)<<tab->bin_power;
|
314
|
+
}
|
315
|
+
|
316
|
+
/* Return mask for a bin index in table TAB. */
|
317
|
+
static inline st_index_t
|
318
|
+
bins_mask(const st_table *tab)
|
319
|
+
{
|
320
|
+
return get_bins_num(tab) - 1;
|
321
|
+
}
|
322
|
+
|
323
|
+
/* Return the index of table TAB bin corresponding to
|
324
|
+
HASH_VALUE. */
|
325
|
+
static inline st_index_t
|
326
|
+
hash_bin(st_hash_t hash_value, st_table *tab)
|
327
|
+
{
|
328
|
+
return hash_value & bins_mask(tab);
|
329
|
+
}
|
330
|
+
|
331
|
+
/* Return the number of allocated entries of table TAB. */
|
332
|
+
static inline st_index_t
|
333
|
+
get_allocated_entries(const st_table *tab)
|
334
|
+
{
|
335
|
+
return ((st_index_t) 1)<<tab->entry_power;
|
336
|
+
}
|
337
|
+
|
338
|
+
/* Return size of the allocated bins of table TAB. */
|
339
|
+
static inline st_index_t
|
340
|
+
bins_size(const st_table *tab)
|
341
|
+
{
|
342
|
+
return features[tab->entry_power].bins_words * sizeof (st_index_t);
|
343
|
+
}
|
344
|
+
|
345
|
+
/* Mark all bins of table TAB as empty. */
|
346
|
+
static void
|
347
|
+
initialize_bins(st_table *tab)
|
348
|
+
{
|
349
|
+
memset(tab->bins, 0, bins_size(tab));
|
350
|
+
}
|
351
|
+
|
352
|
+
#ifdef ST_DEBUG
|
353
|
+
#define st_assert_notinitial(ent) \
|
354
|
+
do { \
|
355
|
+
st_assert(ent.hash != (st_hash_t) ST_INIT_VAL); \
|
356
|
+
st_assert(ent.key != ST_INIT_VAL); \
|
357
|
+
st_assert(ent.record != ST_INIT_VAL); \
|
358
|
+
} while (0)
|
359
|
+
/* Check the table T consistency. It can be extremely slow. So use
|
360
|
+
it only for debugging. */
|
361
|
+
static void
|
362
|
+
st_check(st_table *tab)
|
363
|
+
{
|
364
|
+
st_index_t d, e, i, n, p;
|
365
|
+
|
366
|
+
for (p = get_allocated_entries(tab), i = 0; p > 1; i++, p>>=1)
|
367
|
+
;
|
368
|
+
p = i;
|
369
|
+
st_assert(p >= MINIMAL_POWER2);
|
370
|
+
st_assert(tab->entries_bound <= get_allocated_entries(tab));
|
371
|
+
st_assert(tab->entries_start <= tab->entries_bound);
|
372
|
+
n = 0;
|
373
|
+
return;
|
374
|
+
if (tab->entries_bound != 0)
|
375
|
+
for (i = tab->entries_start; i < tab->entries_bound; i++) {
|
376
|
+
st_assert_notinitial(tab->entries[i]);
|
377
|
+
if (! DELETED_ENTRY_P(&tab->entries[i]))
|
378
|
+
n++;
|
379
|
+
}
|
380
|
+
st_assert(n == tab->num_entries);
|
381
|
+
if (tab->bins == NULL)
|
382
|
+
st_assert(p <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS);
|
383
|
+
else {
|
384
|
+
st_assert(p > MAX_POWER2_FOR_TABLES_WITHOUT_BINS);
|
385
|
+
for (n = d = i = 0; i < get_bins_num(tab); i++) {
|
386
|
+
st_assert(get_bin(tab->bins, tab->size_ind, i) != ST_INIT_VAL);
|
387
|
+
if (IND_DELETED_BIN_P(tab, i)) {
|
388
|
+
d++;
|
389
|
+
continue;
|
390
|
+
}
|
391
|
+
else if (IND_EMPTY_BIN_P(tab, i))
|
392
|
+
continue;
|
393
|
+
n++;
|
394
|
+
e = get_bin(tab->bins, tab->size_ind, i) - ENTRY_BASE;
|
395
|
+
st_assert(tab->entries_start <= e && e < tab->entries_bound);
|
396
|
+
st_assert(! DELETED_ENTRY_P(&tab->entries[e]));
|
397
|
+
st_assert_notinitial(tab->entries[e]);
|
398
|
+
}
|
399
|
+
st_assert(n == tab->num_entries);
|
400
|
+
st_assert(n + d < get_bins_num(tab));
|
401
|
+
}
|
402
|
+
}
|
403
|
+
#endif
|
404
|
+
|
405
|
+
static st_index_t
|
406
|
+
find_table_bin_ind_direct(st_table *table, st_hash_t hash_value, st_data_t key);
|
407
|
+
|
408
|
+
static st_index_t
|
409
|
+
find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
|
410
|
+
st_data_t key, st_index_t *bin_ind);
|
411
|
+
|
412
|
+
#ifdef HASH_LOG
|
413
|
+
static void
|
414
|
+
count_collision(const struct st_hash_type *type)
|
415
|
+
{
|
416
|
+
collision.all++;
|
417
|
+
if (type == &type_numhash) {
|
418
|
+
collision.num++;
|
419
|
+
}
|
420
|
+
else if (type == &type_strhash) {
|
421
|
+
collision.strcase++;
|
422
|
+
}
|
423
|
+
else if (type == &type_strcasehash) {
|
424
|
+
collision.str++;
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
428
|
+
#define COLLISION (collision_check ? count_collision(tab->type) : (void)0)
|
429
|
+
#define FOUND_BIN (collision_check ? collision.total++ : (void)0)
|
430
|
+
#define collision_check 0
|
431
|
+
#else
|
432
|
+
#define COLLISION
|
433
|
+
#define FOUND_BIN
|
434
|
+
#endif
|
435
|
+
|
436
|
+
/* If the number of entries in the table is at least REBUILD_THRESHOLD
|
437
|
+
times less than the entry array length, decrease the table
|
438
|
+
size. */
|
439
|
+
#define REBUILD_THRESHOLD 4
|
440
|
+
|
441
|
+
#if REBUILD_THRESHOLD < 2
|
442
|
+
#error "REBUILD_THRESHOLD should be >= 2"
|
443
|
+
#endif
|
444
|
+
|
445
|
+
/* Rebuild table TAB. Rebuilding removes all deleted bins and entries
|
446
|
+
and can change size of the table entries and bins arrays.
|
447
|
+
Rebuilding is implemented by creation of a new table or by
|
448
|
+
compaction of the existing one. */
|
449
|
+
static void
|
450
|
+
rebuild_table(st_table *tab)
|
451
|
+
{
|
452
|
+
st_index_t i, ni, bound;
|
453
|
+
unsigned int size_ind;
|
454
|
+
st_table *new_tab;
|
455
|
+
st_table_entry *entries, *new_entries;
|
456
|
+
st_table_entry *curr_entry_ptr;
|
457
|
+
st_index_t *bins;
|
458
|
+
st_index_t bin_ind;
|
459
|
+
|
460
|
+
st_assert(tab != NULL);
|
461
|
+
bound = tab->entries_bound;
|
462
|
+
entries = tab->entries;
|
463
|
+
if ((2 * tab->num_entries <= get_allocated_entries(tab)
|
464
|
+
&& REBUILD_THRESHOLD * tab->num_entries > get_allocated_entries(tab))
|
465
|
+
|| tab->num_entries < (1 << MINIMAL_POWER2)) {
|
466
|
+
/* Compaction: */
|
467
|
+
tab->num_entries = 0;
|
468
|
+
if (tab->bins != NULL)
|
469
|
+
initialize_bins(tab);
|
470
|
+
new_tab = tab;
|
471
|
+
new_entries = entries;
|
472
|
+
}
|
473
|
+
else {
|
474
|
+
new_tab = st_init_table_with_size(tab->type,
|
475
|
+
2 * tab->num_entries - 1);
|
476
|
+
new_entries = new_tab->entries;
|
477
|
+
}
|
478
|
+
ni = 0;
|
479
|
+
bins = new_tab->bins;
|
480
|
+
size_ind = get_size_ind(new_tab);
|
481
|
+
for (i = tab->entries_start; i < bound; i++) {
|
482
|
+
curr_entry_ptr = &entries[i];
|
483
|
+
PREFETCH(entries + i + 1, 0);
|
484
|
+
if (EXPECT(DELETED_ENTRY_P(curr_entry_ptr), 0))
|
485
|
+
continue;
|
486
|
+
if (&new_entries[ni] != curr_entry_ptr)
|
487
|
+
new_entries[ni] = *curr_entry_ptr;
|
488
|
+
if (EXPECT(bins != NULL, 1)) {
|
489
|
+
bin_ind = find_table_bin_ind_direct(new_tab, curr_entry_ptr->hash,
|
490
|
+
curr_entry_ptr->key);
|
491
|
+
st_assert(bin_ind != UNDEFINED_BIN_IND
|
492
|
+
&& (tab == new_tab || new_tab->rebuilds_num == 0)
|
493
|
+
&& IND_EMPTY_BIN_P(new_tab, bin_ind));
|
494
|
+
set_bin(bins, size_ind, bin_ind, ni + ENTRY_BASE);
|
495
|
+
}
|
496
|
+
new_tab->num_entries++;
|
497
|
+
ni++;
|
498
|
+
}
|
499
|
+
if (new_tab != tab) {
|
500
|
+
tab->entry_power = new_tab->entry_power;
|
501
|
+
tab->bin_power = new_tab->bin_power;
|
502
|
+
tab->size_ind = new_tab->size_ind;
|
503
|
+
st_assert(tab->num_entries == ni);
|
504
|
+
st_assert(new_tab->num_entries == ni);
|
505
|
+
if (tab->bins != NULL)
|
506
|
+
free(tab->bins);
|
507
|
+
tab->bins = new_tab->bins;
|
508
|
+
free(tab->entries);
|
509
|
+
tab->entries = new_tab->entries;
|
510
|
+
free(new_tab);
|
511
|
+
}
|
512
|
+
tab->entries_start = 0;
|
513
|
+
tab->entries_bound = tab->num_entries;
|
514
|
+
tab->rebuilds_num++;
|
515
|
+
#ifdef ST_DEBUG
|
516
|
+
st_check(tab);
|
517
|
+
#endif
|
518
|
+
}
|
519
|
+
|
520
|
+
/* Return the next secondary hash index for table TAB using previous
|
521
|
+
index IND and PERTERB. Finally modulo of the function becomes a
|
522
|
+
full *cycle linear congruential generator*, in other words it
|
523
|
+
guarantees traversing all table bins in extreme case.
|
524
|
+
|
525
|
+
According the Hull-Dobell theorem a generator
|
526
|
+
"Xnext = (a*Xprev + c) mod m" is a full cycle generator iff
|
527
|
+
o m and c are relatively prime
|
528
|
+
o a-1 is divisible by all prime factors of m
|
529
|
+
o a-1 is divisible by 4 if m is divisible by 4.
|
530
|
+
|
531
|
+
For our case a is 5, c is 1, and m is a power of two. */
|
532
|
+
static inline st_index_t
|
533
|
+
secondary_hash(st_index_t ind, st_table *tab, st_index_t *perterb)
|
534
|
+
{
|
535
|
+
*perterb >>= 11;
|
536
|
+
ind = (ind << 2) + ind + *perterb + 1;
|
537
|
+
return hash_bin(ind, tab);
|
538
|
+
}
|
539
|
+
|
540
|
+
/* Find an entry with HASH_VALUE and KEY in TABLE using a linear
|
541
|
+
search. Return the index of the found entry in array `entries`.
|
542
|
+
If it is not found, return UNDEFINED_ENTRY_IND. If the table was
|
543
|
+
rebuilt during the search, return REBUILT_TABLE_ENTRY_IND. */
|
544
|
+
static inline st_index_t
|
545
|
+
find_entry(st_table *tab, st_hash_t hash_value, st_data_t key)
|
546
|
+
{
|
547
|
+
int eq_p, rebuilt_p;
|
548
|
+
st_index_t i, bound;
|
549
|
+
st_table_entry *entries;
|
550
|
+
|
551
|
+
bound = tab->entries_bound;
|
552
|
+
entries = tab->entries;
|
553
|
+
for (i = tab->entries_start; i < bound; i++) {
|
554
|
+
DO_PTR_EQUAL_CHECK(tab, &entries[i], hash_value, key, eq_p, rebuilt_p);
|
555
|
+
if (EXPECT(rebuilt_p, 0))
|
556
|
+
return REBUILT_TABLE_ENTRY_IND;
|
557
|
+
if (eq_p)
|
558
|
+
return i;
|
559
|
+
}
|
560
|
+
return UNDEFINED_ENTRY_IND;
|
561
|
+
}
|
562
|
+
|
563
|
+
/* Find and return index of table TAB bin corresponding to an entry
|
564
|
+
with HASH_VALUE and KEY. The entry should be in the table
|
565
|
+
already. */
|
566
|
+
static st_index_t
|
567
|
+
find_table_bin_ind_direct(st_table *tab, st_hash_t hash_value, st_data_t key)
|
568
|
+
{
|
569
|
+
st_index_t ind;
|
570
|
+
#ifdef QUADRATIC_PROBE
|
571
|
+
st_index_t d;
|
572
|
+
#else
|
573
|
+
st_index_t peterb;
|
574
|
+
#endif
|
575
|
+
st_index_t bin;
|
576
|
+
st_table_entry *entries = tab->entries;
|
577
|
+
|
578
|
+
st_assert(tab != NULL);
|
579
|
+
st_assert(tab->bins != NULL);
|
580
|
+
ind = hash_bin(hash_value, tab);
|
581
|
+
#ifdef QUADRATIC_PROBE
|
582
|
+
d = 1;
|
583
|
+
#else
|
584
|
+
peterb = hash_value;
|
585
|
+
#endif
|
586
|
+
FOUND_BIN;
|
587
|
+
for (;;) {
|
588
|
+
bin = get_bin(tab->bins, get_size_ind(tab), ind);
|
589
|
+
if (EMPTY_OR_DELETED_BIN_P(bin))
|
590
|
+
return ind;
|
591
|
+
st_assert (entries[bin - ENTRY_BASE].hash != hash_value);
|
592
|
+
#ifdef QUADRATIC_PROBE
|
593
|
+
ind = hash_bin(ind + d, tab);
|
594
|
+
d++;
|
595
|
+
#else
|
596
|
+
ind = secondary_hash(ind, tab, &peterb);
|
597
|
+
#endif
|
598
|
+
COLLISION;
|
599
|
+
}
|
600
|
+
}
|
601
|
+
|
602
|
+
/* Return index of table TAB bin for HASH_VALUE and KEY through
|
603
|
+
BIN_IND and the pointed value as the function result. Reserve the
|
604
|
+
bin for inclusion of the corresponding entry into the table if it
|
605
|
+
is not there yet. We always find such bin as bins array length is
|
606
|
+
bigger entries array. Although we can reuse a deleted bin, the
|
607
|
+
result bin value is always empty if the table has no entry with
|
608
|
+
KEY. Return the entries array index of the found entry or
|
609
|
+
UNDEFINED_ENTRY_IND if it is not found. If the table was rebuilt
|
610
|
+
during the search, return REBUILT_TABLE_ENTRY_IND. */
|
611
|
+
static st_index_t
|
612
|
+
find_table_bin_ptr_and_reserve(st_table *tab, st_hash_t *hash_value,
|
613
|
+
st_data_t key, st_index_t *bin_ind)
|
614
|
+
{
|
615
|
+
int eq_p, rebuilt_p;
|
616
|
+
st_index_t ind;
|
617
|
+
st_hash_t curr_hash_value = *hash_value;
|
618
|
+
#ifdef QUADRATIC_PROBE
|
619
|
+
st_index_t d;
|
620
|
+
#else
|
621
|
+
st_index_t peterb;
|
622
|
+
#endif
|
623
|
+
st_index_t entry_index;
|
624
|
+
st_index_t first_deleted_bin_ind;
|
625
|
+
st_table_entry *entries;
|
626
|
+
|
627
|
+
st_assert(tab != NULL);
|
628
|
+
st_assert(tab->bins != NULL);
|
629
|
+
st_assert(tab->entries_bound <= get_allocated_entries(tab));
|
630
|
+
st_assert(tab->entries_start <= tab->entries_bound);
|
631
|
+
ind = hash_bin(curr_hash_value, tab);
|
632
|
+
#ifdef QUADRATIC_PROBE
|
633
|
+
d = 1;
|
634
|
+
#else
|
635
|
+
peterb = curr_hash_value;
|
636
|
+
#endif
|
637
|
+
FOUND_BIN;
|
638
|
+
first_deleted_bin_ind = UNDEFINED_BIN_IND;
|
639
|
+
entries = tab->entries;
|
640
|
+
for (;;) {
|
641
|
+
entry_index = get_bin(tab->bins, get_size_ind(tab), ind);
|
642
|
+
if (EMPTY_BIN_P(entry_index)) {
|
643
|
+
tab->num_entries++;
|
644
|
+
entry_index = UNDEFINED_ENTRY_IND;
|
645
|
+
if (first_deleted_bin_ind != UNDEFINED_BIN_IND) {
|
646
|
+
/* We can reuse bin of a deleted entry. */
|
647
|
+
ind = first_deleted_bin_ind;
|
648
|
+
MARK_BIN_EMPTY(tab, ind);
|
649
|
+
}
|
650
|
+
break;
|
651
|
+
}
|
652
|
+
else if (! DELETED_BIN_P(entry_index)) {
|
653
|
+
DO_PTR_EQUAL_CHECK(tab, &entries[entry_index - ENTRY_BASE], curr_hash_value, key, eq_p, rebuilt_p);
|
654
|
+
if (EXPECT(rebuilt_p, 0))
|
655
|
+
return REBUILT_TABLE_ENTRY_IND;
|
656
|
+
if (eq_p)
|
657
|
+
break;
|
658
|
+
}
|
659
|
+
else if (first_deleted_bin_ind == UNDEFINED_BIN_IND)
|
660
|
+
first_deleted_bin_ind = ind;
|
661
|
+
#ifdef QUADRATIC_PROBE
|
662
|
+
ind = hash_bin(ind + d, tab);
|
663
|
+
d++;
|
664
|
+
#else
|
665
|
+
ind = secondary_hash(ind, tab, &peterb);
|
666
|
+
#endif
|
667
|
+
COLLISION;
|
668
|
+
}
|
669
|
+
*bin_ind = ind;
|
670
|
+
return entry_index;
|
671
|
+
}
|
672
|
+
|
673
|
+
/* Check the table and rebuild it if it is necessary. */
|
674
|
+
static inline void
|
675
|
+
rebuild_table_if_necessary (st_table *tab)
|
676
|
+
{
|
677
|
+
st_index_t bound = tab->entries_bound;
|
678
|
+
|
679
|
+
if (bound == get_allocated_entries(tab))
|
680
|
+
rebuild_table(tab);
|
681
|
+
st_assert(tab->entries_bound < get_allocated_entries(tab));
|
682
|
+
}
|
683
|
+
|
684
|
+
#define FNV1_32A_INIT 0x811c9dc5
|
685
|
+
|
686
|
+
/*
|
687
|
+
* 32 bit magic FNV-1a prime
|
688
|
+
*/
|
689
|
+
#define FNV_32_PRIME 0x01000193
|
690
|
+
|
691
|
+
#ifndef UNALIGNED_WORD_ACCESS
|
692
|
+
# if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
|
693
|
+
defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
|
694
|
+
defined(__powerpc64__) || \
|
695
|
+
defined(__mc68020__)
|
696
|
+
# define UNALIGNED_WORD_ACCESS 1
|
697
|
+
# endif
|
698
|
+
#endif
|
699
|
+
#ifndef UNALIGNED_WORD_ACCESS
|
700
|
+
# define UNALIGNED_WORD_ACCESS 0
|
701
|
+
#endif
|
702
|
+
|
703
|
+
/* This hash function is quite simplified MurmurHash3
|
704
|
+
* Simplification is legal, cause most of magic still happens in finalizator.
|
705
|
+
* And finalizator is almost the same as in MurmurHash3 */
|
706
|
+
#define BIG_CONSTANT(x,y) ((st_index_t)(x)<<32|(st_index_t)(y))
|
707
|
+
#define ROTL(x,n) ((x)<<(n)|(x)>>(SIZEOF_ST_INDEX_T*CHAR_BIT-(n)))
|
708
|
+
|
709
|
+
#if ST_INDEX_BITS <= 32
|
710
|
+
#define C1 (st_index_t)0xcc9e2d51
|
711
|
+
#define C2 (st_index_t)0x1b873593
|
712
|
+
#else
|
713
|
+
#define C1 BIG_CONSTANT(0x87c37b91,0x114253d5);
|
714
|
+
#define C2 BIG_CONSTANT(0x4cf5ad43,0x2745937f);
|
715
|
+
#endif
|
716
|
+
static inline st_index_t
|
717
|
+
murmur_step(st_index_t h, st_index_t k)
|
718
|
+
{
|
719
|
+
#if ST_INDEX_BITS <= 32
|
720
|
+
#define r1 (17)
|
721
|
+
#define r2 (11)
|
722
|
+
#else
|
723
|
+
#define r1 (33)
|
724
|
+
#define r2 (24)
|
725
|
+
#endif
|
726
|
+
k *= C1;
|
727
|
+
h ^= ROTL(k, r1);
|
728
|
+
h *= C2;
|
729
|
+
h = ROTL(h, r2);
|
730
|
+
return h;
|
731
|
+
}
|
732
|
+
#undef r1
|
733
|
+
#undef r2
|
734
|
+
|
735
|
+
static inline st_index_t
|
736
|
+
murmur_finish(st_index_t h)
|
737
|
+
{
|
738
|
+
#if ST_INDEX_BITS <= 32
|
739
|
+
#define r1 (16)
|
740
|
+
#define r2 (13)
|
741
|
+
#define r3 (16)
|
742
|
+
const st_index_t c1 = 0x85ebca6b;
|
743
|
+
const st_index_t c2 = 0xc2b2ae35;
|
744
|
+
#else
|
745
|
+
/* values are taken from Mix13 on http://zimbry.blogspot.ru/2011/09/better-bit-mixing-improving-on.html */
|
746
|
+
#define r1 (30)
|
747
|
+
#define r2 (27)
|
748
|
+
#define r3 (31)
|
749
|
+
const st_index_t c1 = BIG_CONSTANT(0xbf58476d,0x1ce4e5b9);
|
750
|
+
const st_index_t c2 = BIG_CONSTANT(0x94d049bb,0x133111eb);
|
751
|
+
#endif
|
752
|
+
#if ST_INDEX_BITS > 64
|
753
|
+
h ^= h >> 64;
|
754
|
+
h *= c2;
|
755
|
+
h ^= h >> 65;
|
756
|
+
#endif
|
757
|
+
h ^= h >> r1;
|
758
|
+
h *= c1;
|
759
|
+
h ^= h >> r2;
|
760
|
+
h *= c2;
|
761
|
+
h ^= h >> r3;
|
762
|
+
return h;
|
763
|
+
}
|
764
|
+
#undef r1
|
765
|
+
#undef r2
|
766
|
+
#undef r3
|
767
|
+
|
768
|
+
static st_index_t
|
769
|
+
strhash(st_data_t arg)
|
770
|
+
{
|
771
|
+
register const char *string = (const char *)arg;
|
772
|
+
return st_hash(string, strlen(string), FNV1_32A_INIT);
|
773
|
+
}
|
774
|
+
|
775
|
+
PUREFUNC(static st_index_t strcasehash(st_data_t));
|
776
|
+
static st_index_t
|
777
|
+
strcasehash(st_data_t arg)
|
778
|
+
{
|
779
|
+
register const char *string = (const char *)arg;
|
780
|
+
register st_index_t hval = FNV1_32A_INIT;
|
781
|
+
|
782
|
+
/*
|
783
|
+
* FNV-1a hash each octet in the buffer
|
784
|
+
*/
|
785
|
+
while (*string) {
|
786
|
+
unsigned int c = (unsigned char)*string++;
|
787
|
+
if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
|
788
|
+
hval ^= c;
|
789
|
+
|
790
|
+
/* multiply by the 32 bit FNV magic prime mod 2^32 */
|
791
|
+
hval *= FNV_32_PRIME;
|
792
|
+
}
|
793
|
+
return hval;
|
794
|
+
}
|
795
|
+
|
796
|
+
static st_data_t *
|
797
|
+
st_store(st_table *tab, st_data_t key, st_data_t value, xh_bool_t update)
|
798
|
+
{
|
799
|
+
st_table_entry *entry;
|
800
|
+
st_index_t bin;
|
801
|
+
st_index_t ind;
|
802
|
+
st_hash_t hash_value;
|
803
|
+
st_index_t bin_ind;
|
804
|
+
int new_p;
|
805
|
+
st_data_t *lval;
|
806
|
+
|
807
|
+
|
808
|
+
hash_value = do_hash(key, tab);
|
809
|
+
retry:
|
810
|
+
rebuild_table_if_necessary(tab);
|
811
|
+
if (tab->bins == NULL) {
|
812
|
+
bin = find_entry(tab, hash_value, key);
|
813
|
+
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
|
814
|
+
goto retry;
|
815
|
+
new_p = bin == UNDEFINED_ENTRY_IND;
|
816
|
+
if (new_p)
|
817
|
+
tab->num_entries++;
|
818
|
+
bin_ind = UNDEFINED_BIN_IND;
|
819
|
+
} else {
|
820
|
+
bin = find_table_bin_ptr_and_reserve(tab, &hash_value, key, &bin_ind);
|
821
|
+
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
|
822
|
+
goto retry;
|
823
|
+
new_p = bin == UNDEFINED_ENTRY_IND;
|
824
|
+
bin -= ENTRY_BASE;
|
825
|
+
}
|
826
|
+
|
827
|
+
if (new_p) {
|
828
|
+
ind = tab->entries_bound++;
|
829
|
+
entry = &tab->entries[ind];
|
830
|
+
entry->hash = hash_value;
|
831
|
+
entry->key = key;
|
832
|
+
entry->record = value;
|
833
|
+
if (bin_ind != UNDEFINED_BIN_IND)
|
834
|
+
set_bin(tab->bins, get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
|
835
|
+
}
|
836
|
+
else {
|
837
|
+
entry = &tab->entries[bin];
|
838
|
+
}
|
839
|
+
|
840
|
+
lval = &entry->record;
|
841
|
+
|
842
|
+
if (update) *lval = value;
|
843
|
+
|
844
|
+
return lval;
|
845
|
+
}
|
846
|
+
|
847
|
+
#endif /* _XH_RUBY_ST_H_ */
|
data/ext/fastxml/xh.c
CHANGED
@@ -232,16 +232,19 @@ xh_parse_arg(VALUE key, VALUE value, VALUE ctx)
|
|
232
232
|
opts->merge_text = xh_param_assign_bool(value);
|
233
233
|
break;
|
234
234
|
}
|
235
|
+
goto error;
|
235
236
|
case 11:
|
236
237
|
if (xh_str_equal11(keyptr, 'f', 'o', 'r', 'c', 'e', '_', 'a', 'r', 'r', 'a', 'y')) {
|
237
238
|
xh_param_assign_pattern(&opts->force_array, value);
|
238
239
|
break;
|
239
240
|
}
|
241
|
+
goto error;
|
240
242
|
case 13:
|
241
243
|
if (xh_str_equal13(keyptr, 'f', 'o', 'r', 'c', 'e', '_', 'c', 'o', 'n', 't', 'e', 'n', 't')) {
|
242
244
|
opts->force_content = xh_param_assign_bool(value);
|
243
245
|
break;
|
244
246
|
}
|
247
|
+
goto error;
|
245
248
|
default:
|
246
249
|
goto error;
|
247
250
|
}
|
data/ext/fastxml/xh_ruby_hash.h
CHANGED
@@ -4,11 +4,15 @@
|
|
4
4
|
#include "xh_config.h"
|
5
5
|
#include "xh_core.h"
|
6
6
|
#if RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR == 2
|
7
|
-
#include "ruby-2.2.7/xh_ruby_st.h"
|
7
|
+
#include "ruby-2.2.7/xh_ruby_st.h"
|
8
8
|
#elif RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR == 3
|
9
|
-
#include "ruby-2.3.4/xh_ruby_st.h"
|
9
|
+
#include "ruby-2.3.4/xh_ruby_st.h"
|
10
10
|
#elif RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR == 4
|
11
|
-
#include "ruby-2.4.
|
11
|
+
#include "ruby-2.4.5/xh_ruby_st.h"
|
12
|
+
#elif RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR == 5
|
13
|
+
#include "ruby-2.5.1/xh_ruby_st.h"
|
14
|
+
#else
|
15
|
+
#error "unsupported version of ruby"
|
12
16
|
#endif
|
13
17
|
|
14
18
|
static VALUE *
|
data/lib/fastxml/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast-xml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuriy Ustushenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '1.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,8 +89,10 @@ files:
|
|
89
89
|
- ext/fastxml/ruby-2.2.7/xh_ruby_st.h
|
90
90
|
- ext/fastxml/ruby-2.3.4/xh_ruby_internal.h
|
91
91
|
- ext/fastxml/ruby-2.3.4/xh_ruby_st.h
|
92
|
-
- ext/fastxml/ruby-2.4.
|
93
|
-
- ext/fastxml/ruby-2.4.
|
92
|
+
- ext/fastxml/ruby-2.4.5/xh_ruby_internal.h
|
93
|
+
- ext/fastxml/ruby-2.4.5/xh_ruby_st.h
|
94
|
+
- ext/fastxml/ruby-2.5.1/xh_ruby_internal.h
|
95
|
+
- ext/fastxml/ruby-2.5.1/xh_ruby_st.h
|
94
96
|
- ext/fastxml/xh.c
|
95
97
|
- ext/fastxml/xh.h
|
96
98
|
- ext/fastxml/xh_buffer.c
|
@@ -148,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
150
|
version: '0'
|
149
151
|
requirements: []
|
150
152
|
rubyforge_project:
|
151
|
-
rubygems_version: 2.6
|
153
|
+
rubygems_version: 2.7.6
|
152
154
|
signing_key:
|
153
155
|
specification_version: 4
|
154
156
|
summary: Fast Ruby Hash to XML and XML to Ruby Hash converter
|