swiss_hash 0.1.0 → 0.1.2

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.
@@ -12,8 +12,29 @@
12
12
  #endif
13
13
  #endif
14
14
 
15
+ #ifndef RB_LIKELY
16
+ #if defined(__GNUC__) || defined(__clang__)
17
+ #define RB_LIKELY(x) __builtin_expect(!!(x), 1)
18
+ #else
19
+ #define RB_LIKELY(x) (x)
20
+ #endif
21
+ #endif
22
+
23
+ #if defined(__GNUC__) || defined(__clang__)
24
+ #define SH_ALWAYS_INLINE static inline __attribute__((always_inline))
25
+ #else
26
+ #define SH_ALWAYS_INLINE static inline
27
+ #endif
28
+
29
+ #if defined(__GNUC__) || defined(__clang__)
30
+ #define SH_PREFETCH(p) __builtin_prefetch((const void *)(p), 0, 1)
31
+ #else
32
+ #define SH_PREFETCH(p) ((void)0)
33
+ #endif
34
+
15
35
  static uint64_t swiss_hash_seed0;
16
36
  static uint64_t swiss_hash_seed1;
37
+ static VALUE cSwissHashHash;
17
38
 
18
39
  static void init_hash_seed(void) {
19
40
  VALUE seed_val = rb_hash(INT2FIX(0));
@@ -115,7 +136,6 @@ static inline uint64_t wyhash(const void *data, size_t len, uint64_t seed) {
115
136
  return _wymix(s1 ^ len, _wymix(a ^ s1, b ^ seed));
116
137
  }
117
138
 
118
- #define GROUP_SIZE 8
119
139
  #define CTRL_EMPTY 0x80
120
140
  #define CTRL_DELETED 0xFE
121
141
  #define H2_MASK 0x7F
@@ -126,111 +146,77 @@ static inline uint64_t wyhash(const void *data, size_t len, uint64_t seed) {
126
146
  #if defined(__x86_64__) || defined(_M_X64)
127
147
  #define SWISS_USE_SSE2 1
128
148
  #include <emmintrin.h>
129
- #elif defined(__aarch64__) || defined(_M_ARM64)
130
- #define SWISS_USE_NEON 1
131
- #include <arm_neon.h>
149
+
150
+ #define GROUP_SIZE 16
151
+ #define GROUP_MASK 0xFFFFu
132
152
  #else
133
- #define SWISS_USE_PORTABLE 1
153
+ #define SWISS_USE_SWAR 1
154
+ #define GROUP_SIZE 8
155
+ #define GROUP_MASK 0xFFu
134
156
  #endif
135
157
 
136
158
  #ifdef SWISS_USE_SSE2
137
159
 
138
160
  static inline __m128i ctrl_load(const uint8_t *ctrl) {
139
- return _mm_loadl_epi64((const __m128i *)ctrl);
161
+ return _mm_loadu_si128((const __m128i *)ctrl);
140
162
  }
141
163
 
142
164
  static inline uint32_t ctrl_match_h2_vec(__m128i cv, uint8_t h2) {
143
165
  __m128i cmp = _mm_cmpeq_epi8(cv, _mm_set1_epi8((char)h2));
144
- return (uint32_t)_mm_movemask_epi8(cmp) & 0xFF;
166
+ return (uint32_t)_mm_movemask_epi8(cmp);
145
167
  }
146
168
 
147
169
  static inline uint32_t ctrl_match_empty_vec(__m128i cv) {
148
170
  __m128i cmp = _mm_cmpeq_epi8(cv, _mm_set1_epi8((char)CTRL_EMPTY));
149
- return (uint32_t)_mm_movemask_epi8(cmp) & 0xFF;
171
+ return (uint32_t)_mm_movemask_epi8(cmp);
150
172
  }
151
173
 
152
174
  static inline uint32_t ctrl_match_empty_or_deleted_vec(__m128i cv) {
153
- return (uint32_t)_mm_movemask_epi8(cv) & 0xFF;
175
+ return (uint32_t)_mm_movemask_epi8(cv);
154
176
  }
155
177
 
156
178
  static inline uint32_t ctrl_match_empty(const uint8_t *ctrl) {
157
179
  return ctrl_match_empty_vec(ctrl_load(ctrl));
158
180
  }
159
181
 
160
- #elif defined(SWISS_USE_NEON)
161
-
162
- static inline uint32_t neon_movemask(uint8x8_t v) {
163
- static const uint8_t power_of_two[8] = {1, 2, 4, 8, 16, 32, 64, 128};
164
- uint8x8_t bits = vand_u8(v, vld1_u8(power_of_two));
165
- bits = vpadd_u8(bits, bits);
166
- bits = vpadd_u8(bits, bits);
167
- bits = vpadd_u8(bits, bits);
168
- return (uint32_t)vget_lane_u8(bits, 0);
169
- }
170
-
171
- static inline uint8x8_t ctrl_load(const uint8_t *ctrl) {
172
- return vld1_u8(ctrl);
173
- }
174
-
175
- static inline uint32_t ctrl_match_h2_vec(uint8x8_t cv, uint8_t h2) {
176
- return neon_movemask(vceq_u8(cv, vdup_n_u8(h2)));
177
- }
182
+ #else /* SWAR */
178
183
 
179
- static inline uint32_t ctrl_match_empty_vec(uint8x8_t cv) {
180
- return neon_movemask(vceq_u8(cv, vdup_n_u8(CTRL_EMPTY)));
181
- }
184
+ #define SWAR_LSB 0x0101010101010101ULL
185
+ #define SWAR_MSB 0x8080808080808080ULL
182
186
 
183
- static inline uint32_t ctrl_match_empty_or_deleted_vec(uint8x8_t cv) {
184
- uint8x8_t msb = vshr_n_u8(cv, 7);
185
- uint8x8_t match = vceq_u8(msb, vdup_n_u8(1));
186
- return neon_movemask(match);
187
+ SH_ALWAYS_INLINE uint32_t ctrl_bitmask_from_msb(uint64_t msb_bits) {
188
+ uint64_t bits = (msb_bits & SWAR_MSB) >> 7;
189
+ return (uint32_t)((bits * 0x0102040810204080ULL) >> 56);
187
190
  }
188
191
 
189
- static inline uint32_t ctrl_match_empty(const uint8_t *ctrl) {
190
- return ctrl_match_empty_vec(ctrl_load(ctrl));
191
- }
192
-
193
- #else /* portable */
194
-
195
- static inline uint32_t ctrl_match_h2_raw(const uint8_t *ctrl, uint8_t h2) {
192
+ SH_ALWAYS_INLINE uint32_t ctrl_match_h2_raw(const uint8_t *ctrl, uint8_t h2) {
196
193
  uint64_t c;
197
194
  memcpy(&c, ctrl, 8);
198
- uint64_t broadcast = 0x0101010101010101ULL * h2;
195
+ uint64_t broadcast = SWAR_LSB * h2;
199
196
  uint64_t xored = c ^ broadcast;
200
- uint64_t result = (xored - 0x0101010101010101ULL) & ~xored & 0x8080808080808080ULL;
201
- uint32_t mask = 0;
202
- for (int i = 0; i < 8; i++) {
203
- if (result & (0x80ULL << (i * 8)))
204
- mask |= (1u << i);
205
- }
206
- return mask;
197
+ uint64_t result = (xored - SWAR_LSB) & ~xored & SWAR_MSB;
198
+ return ctrl_bitmask_from_msb(result);
207
199
  }
208
200
 
209
- static inline uint32_t ctrl_match_empty_raw(const uint8_t *ctrl) {
210
- uint32_t mask = 0;
211
- for (int i = 0; i < 8; i++) {
212
- if (ctrl[i] == CTRL_EMPTY)
213
- mask |= (1u << i);
214
- }
215
- return mask;
201
+ SH_ALWAYS_INLINE uint32_t ctrl_match_empty_raw(const uint8_t *ctrl) {
202
+ uint64_t c;
203
+ memcpy(&c, ctrl, 8);
204
+ return ctrl_bitmask_from_msb((c & ~(c << 6)) & SWAR_MSB);
216
205
  }
217
206
 
218
- static inline uint32_t ctrl_match_empty_or_deleted_raw(const uint8_t *ctrl) {
219
- uint32_t mask = 0;
220
- for (int i = 0; i < 8; i++) {
221
- if (ctrl[i] & 0x80)
222
- mask |= (1u << i);
223
- }
224
- return mask;
207
+ SH_ALWAYS_INLINE uint32_t ctrl_match_empty_or_deleted_raw(const uint8_t *ctrl) {
208
+ uint64_t c;
209
+ memcpy(&c, ctrl, 8);
210
+ return ctrl_bitmask_from_msb(c);
225
211
  }
226
212
 
227
- static inline uint32_t ctrl_match_empty(const uint8_t *ctrl) {
213
+ SH_ALWAYS_INLINE uint32_t ctrl_match_empty(const uint8_t *ctrl) {
228
214
  return ctrl_match_empty_raw(ctrl);
229
215
  }
230
216
 
231
- #endif /* SIMD selection */
217
+ #endif /* control-byte matching selection */
232
218
 
233
- static inline int ctz32(uint32_t v) {
219
+ SH_ALWAYS_INLINE int ctz32(uint32_t v) {
234
220
  #if defined(__GNUC__) || defined(__clang__)
235
221
  return __builtin_ctz(v);
236
222
  #elif defined(_MSC_VER)
@@ -280,7 +266,7 @@ typedef struct {
280
266
 
281
267
  #define FIBONACCI_HASH_C 0x9E3779B97F4A7C15ULL
282
268
 
283
- static inline uint64_t compute_hash(VALUE key) {
269
+ SH_ALWAYS_INLINE uint64_t compute_hash(VALUE key) {
284
270
  uint64_t v;
285
271
 
286
272
  if (FIXNUM_P(key)) {
@@ -296,7 +282,7 @@ static inline uint64_t compute_hash(VALUE key) {
296
282
  if (RB_TYPE_P(key, T_STRING)) {
297
283
  const char *ptr = RSTRING_PTR(key);
298
284
  long len = RSTRING_LEN(key);
299
- int enc_idx = rb_enc_get_index(key);
285
+ int enc_idx = ENCODING_GET(key);
300
286
  uint64_t str_seed = swiss_hash_seed0 ^ (uint64_t)enc_idx;
301
287
  return wyhash(ptr ? ptr : (const char *)"", (size_t)len, str_seed);
302
288
  }
@@ -314,22 +300,33 @@ static inline uint64_t compute_hash(VALUE key) {
314
300
  #define H1(hash) ((hash) >> 7)
315
301
  #define H2(hash) ((uint8_t)((hash) & H2_MASK))
316
302
 
317
- static inline int keys_equal(VALUE a, VALUE b) {
303
+ SH_ALWAYS_INLINE int keys_equal(VALUE a, VALUE b) {
318
304
  if (a == b)
319
305
  return 1;
320
-
321
- int ta = TYPE(a);
322
- if (ta == T_FIXNUM || ta == T_SYMBOL)
306
+ if (FIXNUM_P(a) || SYMBOL_P(a) || SPECIAL_CONST_P(a))
323
307
  return 0;
324
308
 
325
- if (ta == T_STRING && RB_TYPE_P(b, T_STRING)) {
309
+ if (RB_TYPE_P(a, T_STRING) && RB_TYPE_P(b, T_STRING)) {
326
310
  long la = RSTRING_LEN(a);
327
- long lb = RSTRING_LEN(b);
328
- if (la != lb)
311
+ if (la != RSTRING_LEN(b))
329
312
  return 0;
313
+ const char *pa = RSTRING_PTR(a);
314
+ const char *pb = RSTRING_PTR(b);
315
+ if (pa == pb)
316
+ return 1;
317
+
318
+ int ea = ENCODING_GET(a);
319
+ int eb = ENCODING_GET(b);
320
+ if (ea == eb) {
321
+ return memcmp(pa, pb, (size_t)la) == 0;
322
+ }
323
+
324
+ if (ENC_CODERANGE(a) == ENC_CODERANGE_7BIT && ENC_CODERANGE(b) == ENC_CODERANGE_7BIT) {
325
+ return memcmp(pa, pb, (size_t)la) == 0;
326
+ }
330
327
 
331
328
  if (rb_enc_compatible(a, b)) {
332
- return memcmp(RSTRING_PTR(a), RSTRING_PTR(b), (size_t)la) == 0;
329
+ return memcmp(pa, pb, (size_t)la) == 0;
333
330
  }
334
331
  return rb_eql(a, b);
335
332
  }
@@ -337,9 +334,18 @@ static inline int keys_equal(VALUE a, VALUE b) {
337
334
  return rb_eql(a, b);
338
335
  }
339
336
 
340
- static inline VALUE prepare_key(VALUE key) {
341
- if (RB_TYPE_P(key, T_STRING) && !OBJ_FROZEN(key)) {
342
- key = rb_str_new_frozen(key);
337
+ #ifndef SWISS_HASH_COPY_STRING_KEYS
338
+ #define SWISS_HASH_COPY_STRING_KEYS 1
339
+ #endif
340
+
341
+ SH_ALWAYS_INLINE VALUE prepare_key(VALUE key) {
342
+ if (RB_TYPE_P(key, T_STRING)) {
343
+ #if SWISS_HASH_COPY_STRING_KEYS
344
+ if (!OBJ_FROZEN(key)) {
345
+ key = rb_str_new_frozen(key);
346
+ }
347
+ #endif
348
+ rb_enc_str_coderange(key);
343
349
  }
344
350
  return key;
345
351
  }
@@ -370,7 +376,7 @@ static void swiss_init(SwissHash *sh, size_t min_capacity) {
370
376
  sh->growth_left = capacity * MAX_LOAD_NUM / MAX_LOAD_DEN;
371
377
 
372
378
  sh->ctrl = (uint8_t *)malloc(capacity);
373
- sh->slots = (Slot *)calloc(capacity, sizeof(Slot));
379
+ sh->slots = (Slot *)malloc(capacity * sizeof(Slot));
374
380
 
375
381
  if (!sh->ctrl || !sh->slots) {
376
382
  free(sh->ctrl);
@@ -389,7 +395,7 @@ typedef struct {
389
395
  size_t group_mask;
390
396
  } ProbeSeq;
391
397
 
392
- static inline ProbeSeq probe_start(uint64_t h1, size_t group_mask) {
398
+ SH_ALWAYS_INLINE ProbeSeq probe_start(uint64_t h1, size_t group_mask) {
393
399
  ProbeSeq ps;
394
400
  ps.group_idx = (size_t)(h1)&group_mask;
395
401
  ps.stride = 0;
@@ -397,7 +403,7 @@ static inline ProbeSeq probe_start(uint64_t h1, size_t group_mask) {
397
403
  return ps;
398
404
  }
399
405
 
400
- static inline void probe_next(ProbeSeq *ps) {
406
+ SH_ALWAYS_INLINE void probe_next(ProbeSeq *ps) {
401
407
  ps->stride++;
402
408
  ps->group_idx = (ps->group_idx + ps->stride) & ps->group_mask;
403
409
  }
@@ -414,20 +420,18 @@ static VALUE *swiss_lookup(SwissHash *sh, VALUE key) {
414
420
 
415
421
  #if defined(SWISS_USE_SSE2)
416
422
  __m128i cv = ctrl_load(sh->ctrl + off);
417
- uint32_t match = ctrl_match_h2_vec(cv, h2);
418
- uint32_t empty = ctrl_match_empty_vec(cv);
419
- #elif defined(SWISS_USE_NEON)
420
- uint8x8_t cv = ctrl_load(sh->ctrl + off);
423
+ SH_PREFETCH(&sh->slots[off]);
421
424
  uint32_t match = ctrl_match_h2_vec(cv, h2);
422
425
  uint32_t empty = ctrl_match_empty_vec(cv);
423
426
  #else
427
+ SH_PREFETCH(&sh->slots[off]);
424
428
  uint32_t match = ctrl_match_h2_raw(sh->ctrl + off, h2);
425
429
  uint32_t empty = ctrl_match_empty_raw(sh->ctrl + off);
426
430
  #endif
427
431
  while (match) {
428
432
  int slot = ctz32(match);
429
433
  Slot *s = &sh->slots[off + slot];
430
- if (keys_equal(s->key, key)) {
434
+ if (RB_LIKELY(s->key == key) || keys_equal(s->key, key)) {
431
435
  return &s->value;
432
436
  }
433
437
  match &= match - 1;
@@ -442,7 +446,7 @@ static VALUE *swiss_lookup(SwissHash *sh, VALUE key) {
442
446
  static void swiss_grow(SwissHash *sh);
443
447
  static void swiss_compact(SwissHash *sh);
444
448
 
445
- static inline void swiss_insert_rehash(SwissHash *sh, uint64_t hash, VALUE key, VALUE value) {
449
+ SH_ALWAYS_INLINE void swiss_insert_rehash(SwissHash *sh, uint64_t hash, VALUE key, VALUE value) {
446
450
  uint8_t h2 = H2(hash);
447
451
  ProbeSeq ps = probe_start(H1(hash), sh->group_mask);
448
452
 
@@ -474,7 +478,7 @@ static void swiss_compact(SwissHash *sh) {
474
478
  Slot *old_slots = sh->slots;
475
479
 
476
480
  sh->ctrl = (uint8_t *)malloc(cap);
477
- sh->slots = (Slot *)calloc(cap, sizeof(Slot));
481
+ sh->slots = (Slot *)malloc(cap * sizeof(Slot));
478
482
 
479
483
  if (!sh->ctrl || !sh->slots) {
480
484
  free(sh->ctrl);
@@ -523,15 +527,12 @@ static VALUE swiss_insert(SwissHash *sh, VALUE key, VALUE value) {
523
527
 
524
528
  #if defined(SWISS_USE_SSE2)
525
529
  __m128i cv = ctrl_load(sh->ctrl + off);
526
- uint32_t match = ctrl_match_h2_vec(cv, h2);
527
- uint32_t empty = ctrl_match_empty_vec(cv);
528
- uint32_t avail = ctrl_match_empty_or_deleted_vec(cv);
529
- #elif defined(SWISS_USE_NEON)
530
- uint8x8_t cv = ctrl_load(sh->ctrl + off);
530
+ SH_PREFETCH(&sh->slots[off]);
531
531
  uint32_t match = ctrl_match_h2_vec(cv, h2);
532
532
  uint32_t empty = ctrl_match_empty_vec(cv);
533
533
  uint32_t avail = ctrl_match_empty_or_deleted_vec(cv);
534
534
  #else
535
+ SH_PREFETCH(&sh->slots[off]);
535
536
  uint32_t match = ctrl_match_h2_raw(sh->ctrl + off, h2);
536
537
  uint32_t empty = ctrl_match_empty_raw(sh->ctrl + off);
537
538
  uint32_t avail = ctrl_match_empty_or_deleted_raw(sh->ctrl + off);
@@ -539,8 +540,9 @@ static VALUE swiss_insert(SwissHash *sh, VALUE key, VALUE value) {
539
540
  while (match) {
540
541
  int slot = ctz32(match);
541
542
  size_t idx = off + slot;
542
- if (keys_equal(sh->slots[idx].key, key)) {
543
- sh->slots[idx].value = value;
543
+ Slot *s = &sh->slots[idx];
544
+ if (RB_LIKELY(s->key == key) || keys_equal(s->key, key)) {
545
+ s->value = value;
544
546
  return value;
545
547
  }
546
548
  match &= match - 1;
@@ -581,21 +583,20 @@ static VALUE swiss_delete(SwissHash *sh, VALUE key) {
581
583
 
582
584
  #if defined(SWISS_USE_SSE2)
583
585
  __m128i cv = ctrl_load(sh->ctrl + off);
584
- uint32_t match = ctrl_match_h2_vec(cv, h2);
585
- uint32_t empty = ctrl_match_empty_vec(cv);
586
- #elif defined(SWISS_USE_NEON)
587
- uint8x8_t cv = ctrl_load(sh->ctrl + off);
586
+ SH_PREFETCH(&sh->slots[off]);
588
587
  uint32_t match = ctrl_match_h2_vec(cv, h2);
589
588
  uint32_t empty = ctrl_match_empty_vec(cv);
590
589
  #else
590
+ SH_PREFETCH(&sh->slots[off]);
591
591
  uint32_t match = ctrl_match_h2_raw(sh->ctrl + off, h2);
592
592
  uint32_t empty = ctrl_match_empty_raw(sh->ctrl + off);
593
593
  #endif
594
594
  while (match) {
595
595
  int slot = ctz32(match);
596
596
  size_t idx = off + slot;
597
- if (keys_equal(sh->slots[idx].key, key)) {
598
- VALUE old_value = sh->slots[idx].value;
597
+ Slot *s = &sh->slots[idx];
598
+ if (RB_LIKELY(s->key == key) || keys_equal(s->key, key)) {
599
+ VALUE old_value = s->value;
599
600
 
600
601
  MUTATE_GUARD_BEGIN(sh);
601
602
  sh->ctrl[idx] = CTRL_DELETED;
@@ -627,7 +628,7 @@ static void swiss_grow(SwissHash *sh) {
627
628
  size_t new_cap = new_num_groups * GROUP_SIZE;
628
629
 
629
630
  sh->ctrl = (uint8_t *)malloc(new_cap);
630
- sh->slots = (Slot *)calloc(new_cap, sizeof(Slot));
631
+ sh->slots = (Slot *)malloc(new_cap * sizeof(Slot));
631
632
 
632
633
  if (!sh->ctrl || !sh->slots) {
633
634
  free(sh->ctrl);
@@ -717,9 +718,38 @@ static VALUE swiss_hash_initialize(int argc, VALUE *argv, VALUE self) {
717
718
  return self;
718
719
  }
719
720
 
721
+ static VALUE swiss_hash_initialize_copy(VALUE self, VALUE original) {
722
+ if (self == original) {
723
+ return self;
724
+ }
725
+
726
+ SwissHash *src;
727
+ SwissHash *dst;
728
+ TypedData_Get_Struct(original, SwissHash, &swiss_hash_type, src);
729
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, dst);
730
+
731
+ if (dst->ctrl || dst->slots) {
732
+ swiss_free_arrays(dst);
733
+ }
734
+
735
+ if (!src->ctrl || !src->slots) {
736
+ swiss_init(dst, 16);
737
+ return self;
738
+ }
739
+
740
+ swiss_init(dst, src->capacity);
741
+ memcpy(dst->ctrl, src->ctrl, src->capacity * sizeof(uint8_t));
742
+ memcpy(dst->slots, src->slots, src->capacity * sizeof(Slot));
743
+ dst->size = src->size;
744
+ dst->growth_left = src->growth_left;
745
+ dst->tombstone_count = src->tombstone_count;
746
+ dst->mutating = 0;
747
+
748
+ return self;
749
+ }
750
+
720
751
  static VALUE swiss_hash_aset(VALUE self, VALUE key, VALUE value) {
721
- SwissHash *sh;
722
- TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
752
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
723
753
  if (RB_UNLIKELY(!(FIXNUM_P(key) || SYMBOL_P(key)))) {
724
754
  key = prepare_key(key);
725
755
  }
@@ -727,15 +757,13 @@ static VALUE swiss_hash_aset(VALUE self, VALUE key, VALUE value) {
727
757
  }
728
758
 
729
759
  static VALUE swiss_hash_aref(VALUE self, VALUE key) {
730
- SwissHash *sh;
731
- TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
760
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
732
761
  VALUE *val = swiss_lookup(sh, key);
733
762
  return val ? *val : Qnil;
734
763
  }
735
764
 
736
765
  static VALUE swiss_hash_delete(VALUE self, VALUE key) {
737
- SwissHash *sh;
738
- TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
766
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
739
767
  return swiss_delete(sh, key);
740
768
  }
741
769
 
@@ -808,16 +836,546 @@ static VALUE swiss_hash_values(VALUE self) {
808
836
  return ary;
809
837
  }
810
838
 
811
- static VALUE swiss_hash_key_p(VALUE self, VALUE key) {
839
+ static VALUE swiss_hash_each_key(VALUE self) {
812
840
  SwissHash *sh;
813
841
  TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
842
+
843
+ RETURN_ENUMERATOR(self, 0, 0);
844
+
845
+ for (size_t i = 0; i < sh->capacity; i++) {
846
+ uint8_t c = sh->ctrl[i];
847
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
848
+ rb_yield(sh->slots[i].key);
849
+ }
850
+ }
851
+
852
+ return self;
853
+ }
854
+
855
+ static VALUE swiss_hash_each_value(VALUE self) {
856
+ SwissHash *sh;
857
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
858
+
859
+ RETURN_ENUMERATOR(self, 0, 0);
860
+
861
+ for (size_t i = 0; i < sh->capacity; i++) {
862
+ uint8_t c = sh->ctrl[i];
863
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
864
+ rb_yield(sh->slots[i].value);
865
+ }
866
+ }
867
+
868
+ return self;
869
+ }
870
+
871
+ static VALUE swiss_hash_to_h(VALUE self) {
872
+ SwissHash *sh;
873
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
874
+
875
+ VALUE hash = rb_hash_new();
876
+ for (size_t i = 0; i < sh->capacity; i++) {
877
+ uint8_t c = sh->ctrl[i];
878
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
879
+ rb_hash_aset(hash, sh->slots[i].key, sh->slots[i].value);
880
+ }
881
+ }
882
+
883
+ return hash;
884
+ }
885
+
886
+ static VALUE swiss_hash_to_a(VALUE self) {
887
+ SwissHash *sh;
888
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
889
+
890
+ VALUE ary = rb_ary_new_capa(sh->size);
891
+ for (size_t i = 0; i < sh->capacity; i++) {
892
+ uint8_t c = sh->ctrl[i];
893
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
894
+ VALUE pair = rb_ary_new_capa(2);
895
+ rb_ary_push(pair, sh->slots[i].key);
896
+ rb_ary_push(pair, sh->slots[i].value);
897
+ rb_ary_push(ary, pair);
898
+ }
899
+ }
900
+
901
+ return ary;
902
+ }
903
+
904
+ static VALUE swiss_hash_fetch(int argc, VALUE *argv, VALUE self) {
905
+ VALUE key;
906
+ VALUE default_value;
907
+ rb_scan_args(argc, argv, "11", &key, &default_value);
908
+
909
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
910
+ VALUE *val = swiss_lookup(sh, key);
911
+ if (val) {
912
+ return *val;
913
+ }
914
+
915
+ if (rb_block_given_p()) {
916
+ if (argc == 2) {
917
+ rb_warn("block supersedes default value argument");
918
+ }
919
+ return rb_yield(key);
920
+ }
921
+
922
+ if (argc == 2) {
923
+ return default_value;
924
+ }
925
+
926
+ VALUE inspected = rb_inspect(key);
927
+ VALUE message = rb_str_plus(rb_str_new_cstr("key not found: "), inspected);
928
+ rb_exc_raise(rb_exc_new_str(rb_eKeyError, message));
929
+
930
+ return Qnil;
931
+ }
932
+
933
+ static VALUE swiss_hash_values_at(int argc, VALUE *argv, VALUE self) {
934
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
935
+ VALUE ary = rb_ary_new_capa((long)argc);
936
+
937
+ for (int i = 0; i < argc; i++) {
938
+ VALUE *val = swiss_lookup(sh, argv[i]);
939
+ rb_ary_push(ary, val ? *val : Qnil);
940
+ }
941
+
942
+ return ary;
943
+ }
944
+
945
+ static VALUE swiss_hash_value_p(VALUE self, VALUE value) {
946
+ SwissHash *sh;
947
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
948
+
949
+ for (size_t i = 0; i < sh->capacity; i++) {
950
+ uint8_t c = sh->ctrl[i];
951
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
952
+ if (RTEST(rb_equal(sh->slots[i].value, value))) {
953
+ return Qtrue;
954
+ }
955
+ }
956
+ }
957
+
958
+ return Qfalse;
959
+ }
960
+
961
+ static VALUE swiss_hash_key_for_value(VALUE self, VALUE value) {
962
+ SwissHash *sh;
963
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
964
+
965
+ for (size_t i = 0; i < sh->capacity; i++) {
966
+ uint8_t c = sh->ctrl[i];
967
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
968
+ if (RTEST(rb_equal(sh->slots[i].value, value))) {
969
+ return sh->slots[i].key;
970
+ }
971
+ }
972
+ }
973
+
974
+ return Qnil;
975
+ }
976
+
977
+ static VALUE swiss_hash_key_p(VALUE self, VALUE key) {
978
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
814
979
  VALUE *val = swiss_lookup(sh, key);
815
980
  return val ? Qtrue : Qfalse;
816
981
  }
817
982
 
983
+ static VALUE swiss_hash_new_like(VALUE self, size_t capacity) {
984
+ VALUE argv[1] = {SIZET2NUM(capacity)};
985
+ return rb_class_new_instance(1, argv, rb_obj_class(self));
986
+ }
987
+
988
+ static VALUE swiss_hash_store_prepared(SwissHash *sh, VALUE key, VALUE value) {
989
+ if (RB_UNLIKELY(!(FIXNUM_P(key) || SYMBOL_P(key)))) {
990
+ key = prepare_key(key);
991
+ }
992
+ return swiss_insert(sh, key, value);
993
+ }
994
+
995
+ typedef struct {
996
+ VALUE self;
997
+ SwissHash *sh;
998
+ int has_block;
999
+ } MergeCtx;
1000
+
1001
+ static void swiss_hash_merge_one_pair(MergeCtx *ctx, VALUE key, VALUE value) {
1002
+ if (ctx->has_block) {
1003
+ VALUE *old = swiss_lookup(ctx->sh, key);
1004
+ if (old) {
1005
+ value = rb_yield_values(3, key, *old, value);
1006
+ }
1007
+ }
1008
+ swiss_hash_store_prepared(ctx->sh, key, value);
1009
+ }
1010
+
1011
+ static int swiss_hash_merge_ruby_hash_i(VALUE key, VALUE value, VALUE arg) {
1012
+ swiss_hash_merge_one_pair((MergeCtx *)arg, key, value);
1013
+ return ST_CONTINUE;
1014
+ }
1015
+
1016
+ static void swiss_hash_merge_swiss_hash(MergeCtx *ctx, VALUE other) {
1017
+ SwissHash *src;
1018
+ TypedData_Get_Struct(other, SwissHash, &swiss_hash_type, src);
1019
+
1020
+ for (size_t i = 0; i < src->capacity; i++) {
1021
+ uint8_t c = src->ctrl[i];
1022
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1023
+ swiss_hash_merge_one_pair(ctx, src->slots[i].key, src->slots[i].value);
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ static void swiss_hash_merge_one(MergeCtx *ctx, VALUE other) {
1029
+ if (RTEST(rb_obj_is_kind_of(other, cSwissHashHash))) {
1030
+ swiss_hash_merge_swiss_hash(ctx, other);
1031
+ return;
1032
+ }
1033
+
1034
+ VALUE hash = rb_check_hash_type(other);
1035
+ if (NIL_P(hash)) {
1036
+ rb_raise(rb_eTypeError, "no implicit conversion of %s into Hash", rb_obj_classname(other));
1037
+ }
1038
+
1039
+ rb_hash_foreach(hash, swiss_hash_merge_ruby_hash_i, (VALUE)ctx);
1040
+ }
1041
+
1042
+ static VALUE swiss_hash_merge_bang(int argc, VALUE *argv, VALUE self) {
1043
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
1044
+ MergeCtx ctx = {self, sh, rb_block_given_p()};
1045
+
1046
+ for (int i = 0; i < argc; i++) {
1047
+ swiss_hash_merge_one(&ctx, argv[i]);
1048
+ }
1049
+
1050
+ return self;
1051
+ }
1052
+
1053
+ static VALUE swiss_hash_merge(int argc, VALUE *argv, VALUE self) {
1054
+ VALUE copy = rb_obj_dup(self);
1055
+ swiss_hash_merge_bang(argc, argv, copy);
1056
+ return copy;
1057
+ }
1058
+
1059
+ static VALUE swiss_hash_replace(VALUE self, VALUE other) {
1060
+ swiss_hash_clear(self);
1061
+ VALUE argv[1] = {other};
1062
+ swiss_hash_merge_bang(1, argv, self);
1063
+ return self;
1064
+ }
1065
+
1066
+ static VALUE swiss_hash_to_sh(VALUE self) {
1067
+ return rb_obj_dup(self);
1068
+ }
1069
+
1070
+ static VALUE swiss_hash_fetch_values(int argc, VALUE *argv, VALUE self) {
1071
+ SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
1072
+ VALUE ary = rb_ary_new_capa((long)argc);
1073
+ int has_block = rb_block_given_p();
1074
+
1075
+ for (int i = 0; i < argc; i++) {
1076
+ VALUE *val = swiss_lookup(sh, argv[i]);
1077
+ if (val) {
1078
+ rb_ary_push(ary, *val);
1079
+ } else if (has_block) {
1080
+ rb_ary_push(ary, rb_yield(argv[i]));
1081
+ } else {
1082
+ VALUE key_argv[1] = {argv[i]};
1083
+ rb_ary_push(ary, swiss_hash_fetch(1, key_argv, self));
1084
+ }
1085
+ }
1086
+
1087
+ return ary;
1088
+ }
1089
+
1090
+ static VALUE swiss_hash_slice(int argc, VALUE *argv, VALUE self) {
1091
+ SwissHash *src = (SwissHash *)RTYPEDDATA_DATA(self);
1092
+ VALUE result = swiss_hash_new_like(self, (size_t)argc);
1093
+ SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);
1094
+
1095
+ for (int i = 0; i < argc; i++) {
1096
+ VALUE *val = swiss_lookup(src, argv[i]);
1097
+ if (val) {
1098
+ swiss_hash_store_prepared(dst, argv[i], *val);
1099
+ }
1100
+ }
1101
+
1102
+ return result;
1103
+ }
1104
+
1105
+ static VALUE swiss_hash_except(int argc, VALUE *argv, VALUE self) {
1106
+ VALUE result = rb_obj_dup(self);
1107
+ for (int i = 0; i < argc; i++) {
1108
+ swiss_hash_delete(result, argv[i]);
1109
+ }
1110
+ return result;
1111
+ }
1112
+
1113
+ static VALUE swiss_hash_invert(VALUE self) {
1114
+ SwissHash *src;
1115
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
1116
+ VALUE result = swiss_hash_new_like(self, src->size);
1117
+ SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);
1118
+
1119
+ for (size_t i = 0; i < src->capacity; i++) {
1120
+ uint8_t c = src->ctrl[i];
1121
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1122
+ swiss_hash_store_prepared(dst, src->slots[i].value, src->slots[i].key);
1123
+ }
1124
+ }
1125
+
1126
+ return result;
1127
+ }
1128
+
1129
+ static VALUE swiss_hash_assoc(VALUE self, VALUE object) {
1130
+ SwissHash *sh;
1131
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
1132
+
1133
+ for (size_t i = 0; i < sh->capacity; i++) {
1134
+ uint8_t c = sh->ctrl[i];
1135
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1136
+ if (RTEST(rb_equal(sh->slots[i].key, object))) {
1137
+ VALUE ary = rb_ary_new_capa(2);
1138
+ rb_ary_push(ary, sh->slots[i].key);
1139
+ rb_ary_push(ary, sh->slots[i].value);
1140
+ return ary;
1141
+ }
1142
+ }
1143
+ }
1144
+
1145
+ return Qnil;
1146
+ }
1147
+
1148
+ static VALUE swiss_hash_rassoc(VALUE self, VALUE object) {
1149
+ SwissHash *sh;
1150
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
1151
+
1152
+ for (size_t i = 0; i < sh->capacity; i++) {
1153
+ uint8_t c = sh->ctrl[i];
1154
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1155
+ if (RTEST(rb_equal(sh->slots[i].value, object))) {
1156
+ VALUE ary = rb_ary_new_capa(2);
1157
+ rb_ary_push(ary, sh->slots[i].key);
1158
+ rb_ary_push(ary, sh->slots[i].value);
1159
+ return ary;
1160
+ }
1161
+ }
1162
+ }
1163
+
1164
+ return Qnil;
1165
+ }
1166
+
1167
+ static VALUE swiss_hash_shift(VALUE self) {
1168
+ SwissHash *sh;
1169
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
1170
+
1171
+ for (size_t i = 0; i < sh->capacity; i++) {
1172
+ uint8_t c = sh->ctrl[i];
1173
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1174
+ VALUE key = sh->slots[i].key;
1175
+ VALUE value = sh->slots[i].value;
1176
+ sh->ctrl[i] = CTRL_DELETED;
1177
+ sh->slots[i].key = Qnil;
1178
+ sh->slots[i].value = Qnil;
1179
+ sh->size--;
1180
+ sh->tombstone_count++;
1181
+
1182
+ VALUE ary = rb_ary_new_capa(2);
1183
+ rb_ary_push(ary, key);
1184
+ rb_ary_push(ary, value);
1185
+ return ary;
1186
+ }
1187
+ }
1188
+
1189
+ return Qnil;
1190
+ }
1191
+
1192
+ static VALUE swiss_hash_delete_if(VALUE self) {
1193
+ RETURN_ENUMERATOR(self, 0, 0);
1194
+
1195
+ SwissHash *sh;
1196
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
1197
+
1198
+ for (size_t i = 0; i < sh->capacity; i++) {
1199
+ uint8_t c = sh->ctrl[i];
1200
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1201
+ VALUE key = sh->slots[i].key;
1202
+ VALUE value = sh->slots[i].value;
1203
+ if (RTEST(rb_yield_values(2, key, value))) {
1204
+ swiss_delete(sh, key);
1205
+ }
1206
+ }
1207
+ }
1208
+
1209
+ return self;
1210
+ }
1211
+
1212
+ static VALUE swiss_hash_keep_if(VALUE self) {
1213
+ RETURN_ENUMERATOR(self, 0, 0);
1214
+
1215
+ SwissHash *sh;
1216
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
1217
+
1218
+ for (size_t i = 0; i < sh->capacity; i++) {
1219
+ uint8_t c = sh->ctrl[i];
1220
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1221
+ VALUE key = sh->slots[i].key;
1222
+ VALUE value = sh->slots[i].value;
1223
+ if (!RTEST(rb_yield_values(2, key, value))) {
1224
+ swiss_delete(sh, key);
1225
+ }
1226
+ }
1227
+ }
1228
+
1229
+ return self;
1230
+ }
1231
+
1232
+ static VALUE swiss_hash_select(VALUE self) {
1233
+ RETURN_ENUMERATOR(self, 0, 0);
1234
+
1235
+ SwissHash *src;
1236
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
1237
+ VALUE result = swiss_hash_new_like(self, src->size);
1238
+ SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);
1239
+
1240
+ for (size_t i = 0; i < src->capacity; i++) {
1241
+ uint8_t c = src->ctrl[i];
1242
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1243
+ VALUE key = src->slots[i].key;
1244
+ VALUE value = src->slots[i].value;
1245
+ if (RTEST(rb_yield_values(2, key, value))) {
1246
+ swiss_hash_store_prepared(dst, key, value);
1247
+ }
1248
+ }
1249
+ }
1250
+
1251
+ return result;
1252
+ }
1253
+
1254
+ static VALUE swiss_hash_reject(VALUE self) {
1255
+ RETURN_ENUMERATOR(self, 0, 0);
1256
+
1257
+ SwissHash *src;
1258
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
1259
+ VALUE result = swiss_hash_new_like(self, src->size);
1260
+ SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);
1261
+
1262
+ for (size_t i = 0; i < src->capacity; i++) {
1263
+ uint8_t c = src->ctrl[i];
1264
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1265
+ VALUE key = src->slots[i].key;
1266
+ VALUE value = src->slots[i].value;
1267
+ if (!RTEST(rb_yield_values(2, key, value))) {
1268
+ swiss_hash_store_prepared(dst, key, value);
1269
+ }
1270
+ }
1271
+ }
1272
+
1273
+ return result;
1274
+ }
1275
+
1276
+ static VALUE swiss_hash_select_bang(VALUE self) {
1277
+ RETURN_ENUMERATOR(self, 0, 0);
1278
+
1279
+ size_t old_size = ((SwissHash *)RTYPEDDATA_DATA(self))->size;
1280
+ swiss_hash_keep_if(self);
1281
+ return ((SwissHash *)RTYPEDDATA_DATA(self))->size == old_size ? Qnil : self;
1282
+ }
1283
+
1284
+ static VALUE swiss_hash_reject_bang(VALUE self) {
1285
+ RETURN_ENUMERATOR(self, 0, 0);
1286
+
1287
+ size_t old_size = ((SwissHash *)RTYPEDDATA_DATA(self))->size;
1288
+ swiss_hash_delete_if(self);
1289
+ return ((SwissHash *)RTYPEDDATA_DATA(self))->size == old_size ? Qnil : self;
1290
+ }
1291
+
1292
+ static VALUE swiss_hash_compact(VALUE self) {
1293
+ SwissHash *src;
1294
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
1295
+ VALUE result = swiss_hash_new_like(self, src->size);
1296
+ SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);
1297
+
1298
+ for (size_t i = 0; i < src->capacity; i++) {
1299
+ uint8_t c = src->ctrl[i];
1300
+ if (c != CTRL_EMPTY && c != CTRL_DELETED && !NIL_P(src->slots[i].value)) {
1301
+ swiss_hash_store_prepared(dst, src->slots[i].key, src->slots[i].value);
1302
+ }
1303
+ }
1304
+
1305
+ return result;
1306
+ }
1307
+
818
1308
  static VALUE swiss_hash_compact_bang(VALUE self) {
819
1309
  SwissHash *sh;
820
1310
  TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
1311
+ size_t old_size = sh->size;
1312
+
1313
+ for (size_t i = 0; i < sh->capacity; i++) {
1314
+ uint8_t c = sh->ctrl[i];
1315
+ if (c != CTRL_EMPTY && c != CTRL_DELETED && NIL_P(sh->slots[i].value)) {
1316
+ VALUE key = sh->slots[i].key;
1317
+ swiss_delete(sh, key);
1318
+ }
1319
+ }
1320
+
1321
+ return sh->size == old_size ? Qnil : self;
1322
+ }
1323
+
1324
+ static VALUE swiss_hash_transform_values(VALUE self) {
1325
+ RETURN_ENUMERATOR(self, 0, 0);
1326
+
1327
+ SwissHash *src;
1328
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
1329
+ VALUE result = swiss_hash_new_like(self, src->size);
1330
+ SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);
1331
+
1332
+ for (size_t i = 0; i < src->capacity; i++) {
1333
+ uint8_t c = src->ctrl[i];
1334
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1335
+ swiss_hash_store_prepared(dst, src->slots[i].key, rb_yield(src->slots[i].value));
1336
+ }
1337
+ }
1338
+
1339
+ return result;
1340
+ }
1341
+
1342
+ static VALUE swiss_hash_transform_values_bang(VALUE self) {
1343
+ RETURN_ENUMERATOR(self, 0, 0);
1344
+
1345
+ SwissHash *sh;
1346
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
1347
+
1348
+ for (size_t i = 0; i < sh->capacity; i++) {
1349
+ uint8_t c = sh->ctrl[i];
1350
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1351
+ sh->slots[i].value = rb_yield(sh->slots[i].value);
1352
+ }
1353
+ }
1354
+
1355
+ return self;
1356
+ }
1357
+
1358
+ static VALUE swiss_hash_transform_keys(VALUE self) {
1359
+ RETURN_ENUMERATOR(self, 0, 0);
1360
+
1361
+ SwissHash *src;
1362
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
1363
+ VALUE result = swiss_hash_new_like(self, src->size);
1364
+ SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);
1365
+
1366
+ for (size_t i = 0; i < src->capacity; i++) {
1367
+ uint8_t c = src->ctrl[i];
1368
+ if (c != CTRL_EMPTY && c != CTRL_DELETED) {
1369
+ swiss_hash_store_prepared(dst, rb_yield(src->slots[i].key), src->slots[i].value);
1370
+ }
1371
+ }
1372
+
1373
+ return result;
1374
+ }
1375
+
1376
+ static VALUE swiss_hash_compact_storage_bang(VALUE self) {
1377
+ SwissHash *sh;
1378
+ TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
821
1379
 
822
1380
  if (sh->tombstone_count > 0) {
823
1381
  swiss_compact(sh);
@@ -843,10 +1401,8 @@ static VALUE swiss_hash_stats(VALUE self) {
843
1401
 
844
1402
  #ifdef SWISS_USE_SSE2
845
1403
  rb_hash_aset(hash, ID2SYM(rb_intern("simd")), rb_str_new_cstr("SSE2"));
846
- #elif defined(SWISS_USE_NEON)
847
- rb_hash_aset(hash, ID2SYM(rb_intern("simd")), rb_str_new_cstr("NEON"));
848
1404
  #else
849
- rb_hash_aset(hash, ID2SYM(rb_intern("simd")), rb_str_new_cstr("portable/SWAR"));
1405
+ rb_hash_aset(hash, ID2SYM(rb_intern("simd")), rb_str_new_cstr("SWAR"));
850
1406
  #endif
851
1407
  rb_hash_aset(hash, ID2SYM(rb_intern("layout")), rb_str_new_cstr("hybrid"));
852
1408
 
@@ -858,9 +1414,11 @@ void Init_swiss_hash(void) {
858
1414
 
859
1415
  VALUE mSwissHash = rb_define_module("SwissHash");
860
1416
  VALUE cHash = rb_define_class_under(mSwissHash, "Hash", rb_cObject);
1417
+ cSwissHashHash = cHash;
861
1418
 
862
1419
  rb_define_alloc_func(cHash, swiss_hash_alloc);
863
1420
  rb_define_method(cHash, "initialize", swiss_hash_initialize, -1);
1421
+ rb_define_method(cHash, "initialize_copy", swiss_hash_initialize_copy, 1);
864
1422
  rb_define_method(cHash, "[]=", swiss_hash_aset, 2);
865
1423
  rb_define_method(cHash, "store", swiss_hash_aset, 2);
866
1424
  rb_define_method(cHash, "[]", swiss_hash_aref, 1);
@@ -870,11 +1428,48 @@ void Init_swiss_hash(void) {
870
1428
  rb_define_method(cHash, "empty?", swiss_hash_empty_p, 0);
871
1429
  rb_define_method(cHash, "clear", swiss_hash_clear, 0);
872
1430
  rb_define_method(cHash, "each", swiss_hash_each, 0);
1431
+ rb_define_method(cHash, "each_pair", swiss_hash_each, 0);
1432
+ rb_define_method(cHash, "each_key", swiss_hash_each_key, 0);
1433
+ rb_define_method(cHash, "each_value", swiss_hash_each_value, 0);
873
1434
  rb_define_method(cHash, "keys", swiss_hash_keys, 0);
874
1435
  rb_define_method(cHash, "values", swiss_hash_values, 0);
1436
+ rb_define_method(cHash, "to_h", swiss_hash_to_h, 0);
1437
+ rb_define_method(cHash, "to_a", swiss_hash_to_a, 0);
1438
+ rb_define_method(cHash, "fetch", swiss_hash_fetch, -1);
1439
+ rb_define_method(cHash, "values_at", swiss_hash_values_at, -1);
1440
+ rb_define_method(cHash, "fetch_values", swiss_hash_fetch_values, -1);
1441
+ rb_define_method(cHash, "merge!", swiss_hash_merge_bang, -1);
1442
+ rb_define_method(cHash, "update", swiss_hash_merge_bang, -1);
1443
+ rb_define_method(cHash, "merge", swiss_hash_merge, -1);
1444
+ rb_define_method(cHash, "replace", swiss_hash_replace, 1);
1445
+ rb_define_method(cHash, "to_sh", swiss_hash_to_sh, 0);
1446
+ rb_define_method(cHash, "slice", swiss_hash_slice, -1);
1447
+ rb_define_method(cHash, "except", swiss_hash_except, -1);
1448
+ rb_define_method(cHash, "invert", swiss_hash_invert, 0);
1449
+ rb_define_method(cHash, "assoc", swiss_hash_assoc, 1);
1450
+ rb_define_method(cHash, "rassoc", swiss_hash_rassoc, 1);
1451
+ rb_define_method(cHash, "shift", swiss_hash_shift, 0);
1452
+ rb_define_method(cHash, "delete_if", swiss_hash_delete_if, 0);
1453
+ rb_define_method(cHash, "keep_if", swiss_hash_keep_if, 0);
1454
+ rb_define_method(cHash, "select", swiss_hash_select, 0);
1455
+ rb_define_method(cHash, "filter", swiss_hash_select, 0);
1456
+ rb_define_method(cHash, "reject", swiss_hash_reject, 0);
1457
+ rb_define_method(cHash, "select!", swiss_hash_select_bang, 0);
1458
+ rb_define_method(cHash, "filter!", swiss_hash_select_bang, 0);
1459
+ rb_define_method(cHash, "reject!", swiss_hash_reject_bang, 0);
1460
+ rb_define_method(cHash, "compact", swiss_hash_compact, 0);
1461
+ rb_define_method(cHash, "compact!", swiss_hash_compact_bang, 0);
1462
+ rb_define_method(cHash, "transform_values", swiss_hash_transform_values, 0);
1463
+ rb_define_method(cHash, "transform_values!", swiss_hash_transform_values_bang, 0);
1464
+ rb_define_method(cHash, "transform_keys", swiss_hash_transform_keys, 0);
875
1465
  rb_define_method(cHash, "key?", swiss_hash_key_p, 1);
876
1466
  rb_define_method(cHash, "has_key?", swiss_hash_key_p, 1);
877
1467
  rb_define_method(cHash, "include?", swiss_hash_key_p, 1);
878
- rb_define_method(cHash, "compact!", swiss_hash_compact_bang, 0);
1468
+ rb_define_method(cHash, "member?", swiss_hash_key_p, 1);
1469
+ rb_define_method(cHash, "value?", swiss_hash_value_p, 1);
1470
+ rb_define_method(cHash, "has_value?", swiss_hash_value_p, 1);
1471
+ rb_define_method(cHash, "key", swiss_hash_key_for_value, 1);
1472
+ rb_define_method(cHash, "compact_storage!", swiss_hash_compact_storage_bang, 0);
1473
+ rb_define_method(cHash, "__compact_storage!", swiss_hash_compact_storage_bang, 0);
879
1474
  rb_define_method(cHash, "stats", swiss_hash_stats, 0);
880
1475
  }