fast-xml 1.1.2 → 1.1.3

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
- SHA1:
3
- metadata.gz: 5330c4667e2dac78d62d4dbef99f2f9d57f88a38
4
- data.tar.gz: e6ba2183d3e1ae9c53118d1de6e23c9f7b32c8f6
2
+ SHA256:
3
+ metadata.gz: 607a72bcf9b089b76e70a8078d4768796db8b7426efe6c0bdd660e63a01ae1df
4
+ data.tar.gz: 7b31855d8c39a0892d67b176725934f9ec28a53b761679dfb614c82fb5b99056
5
5
  SHA512:
6
- metadata.gz: c6c19df9ded0121c7322c7e1f93e9b0b52ed3c9bc6ddd89bc910291911f9cceee3a0d5c67cc4ecf84d3cc62ca0c3e1970c039abd090a1f10494ca7aa44a55fab
7
- data.tar.gz: 9fd300c03e3950f52d0f702696b585bff1ef9d5b57b085d98c9a6a97feebfcd775d97b24df593767ffbf7bf5c15f0bb69bd5d9719a597dd18312ed438da0eadf
6
+ metadata.gz: 819dc52f307e49d3496ac9aeb8da7da4c7f34b2979b0d6c47d946bdf7b8b514763f1f3e000c5381d92337f83016c8c4f80a7b714b89eb7bbc80f37c60bedd51a
7
+ data.tar.gz: 536e502352bfaf594f5d1ededdd342f3af5990d7a297ae04cb93394aa2607a64d440d5bb0b71cf518022d95ab03dc09cdc3d3a7f73abffa258764b743892824b
@@ -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
- if (PTR_EQUAL(tab, &entries[i], hash_value, key))
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 (! PTR_EQUAL(tab, &entries[bin - ENTRY_BASE], hash_value, key));
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
- if (PTR_EQUAL(tab, &entries[entry_index - ENTRY_BASE], curr_hash_value, key))
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
- unsigned int c = (unsigned char)*string++;
728
- if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
729
- hval ^= c;
778
+ unsigned int c = (unsigned char)*string++;
779
+ if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
780
+ hval ^= c;
730
781
 
731
- /* multiply by the 32 bit FNV magic prime mod 2^32 */
732
- hval *= FNV_32_PRIME;
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
- rebuild_table_if_necessary(tab);
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
- key, &bin_ind);
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_ */
@@ -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
  }
@@ -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.1/xh_ruby_st.h"
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 *
@@ -1,3 +1,3 @@
1
1
  module FastXML
2
- VERSION = "1.1.2"
2
+ VERSION = "1.1.3"
3
3
  end
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.2
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: 2017-06-28 00:00:00.000000000 Z
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.1/xh_ruby_internal.h
93
- - ext/fastxml/ruby-2.4.1/xh_ruby_st.h
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.12
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