Class: SwissHash::Hash

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/swiss_hash.rb,
ext/swiss_hash/swiss_hash.c

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Object



708
709
710
711
712
713
714
715
716
717
718
719
# File 'ext/swiss_hash/swiss_hash.c', line 708

static VALUE swiss_hash_initialize(int argc, VALUE *argv, VALUE self) {
    VALUE capacity_val;
    rb_scan_args(argc, argv, "01", &capacity_val);

    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    size_t capacity = NIL_P(capacity_val) ? 16 : NUM2SIZET(capacity_val);
    swiss_init(sh, capacity);

    return self;
}

Instance Method Details

#==(other) ⇒ Object



36
37
38
39
# File 'lib/swiss_hash.rb', line 36

def ==(other)
  other = other.to_h if other.is_a?(self.class)
  to_h == other
end

#[](key) ⇒ Object



759
760
761
762
763
# File 'ext/swiss_hash/swiss_hash.c', line 759

static VALUE swiss_hash_aref(VALUE self, VALUE key) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE *val = swiss_lookup(sh, key);
    return val ? *val : Qnil;
}

#[]=(key, value) ⇒ Object



751
752
753
754
755
756
757
# File 'ext/swiss_hash/swiss_hash.c', line 751

static VALUE swiss_hash_aset(VALUE self, VALUE key, VALUE value) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    if (RB_UNLIKELY(!(FIXNUM_P(key) || SYMBOL_P(key)))) {
        key = prepare_key(key);
    }
    return swiss_insert(sh, key, value);
}

#__compact_storage!Object



1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
# File 'ext/swiss_hash/swiss_hash.c', line 1376

static VALUE swiss_hash_compact_storage_bang(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    if (sh->tombstone_count > 0) {
        swiss_compact(sh);
    }

    return self;
}

#assoc(object) ⇒ Object



1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
# File 'ext/swiss_hash/swiss_hash.c', line 1129

static VALUE swiss_hash_assoc(VALUE self, VALUE object) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            if (RTEST(rb_equal(sh->slots[i].key, object))) {
                VALUE ary = rb_ary_new_capa(2);
                rb_ary_push(ary, sh->slots[i].key);
                rb_ary_push(ary, sh->slots[i].value);
                return ary;
            }
        }
    }

    return Qnil;
}

#clearObject



782
783
784
785
786
787
788
789
790
791
792
793
# File 'ext/swiss_hash/swiss_hash.c', line 782

static VALUE swiss_hash_clear(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    memset(sh->ctrl, CTRL_EMPTY, sh->capacity);
    memset(sh->slots, 0, sh->capacity * sizeof(Slot));
    sh->size = 0;
    sh->growth_left = sh->capacity * MAX_LOAD_NUM / MAX_LOAD_DEN;
    sh->tombstone_count = 0;

    return self;
}

#compactObject



1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
# File 'ext/swiss_hash/swiss_hash.c', line 1292

static VALUE swiss_hash_compact(VALUE self) {
    SwissHash *src;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
    VALUE result = swiss_hash_new_like(self, src->size);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (size_t i = 0; i < src->capacity; i++) {
        uint8_t c = src->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED && !NIL_P(src->slots[i].value)) {
            swiss_hash_store_prepared(dst, src->slots[i].key, src->slots[i].value);
        }
    }

    return result;
}

#compact!Object



1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
# File 'ext/swiss_hash/swiss_hash.c', line 1308

static VALUE swiss_hash_compact_bang(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
    size_t old_size = sh->size;

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED && NIL_P(sh->slots[i].value)) {
            VALUE key = sh->slots[i].key;
            swiss_delete(sh, key);
        }
    }

    return sh->size == old_size ? Qnil : self;
}

#compact_storage!Object



1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
# File 'ext/swiss_hash/swiss_hash.c', line 1376

static VALUE swiss_hash_compact_storage_bang(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    if (sh->tombstone_count > 0) {
        swiss_compact(sh);
    }

    return self;
}

#count(*args, &block) ⇒ Object



10
11
12
13
14
# File 'lib/swiss_hash.rb', line 10

def count(*args, &block)
  return size if args.empty? && !block

  each.count(*args, &block)
end

#delete(key) ⇒ Object



765
766
767
768
# File 'ext/swiss_hash/swiss_hash.c', line 765

static VALUE swiss_hash_delete(VALUE self, VALUE key) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    return swiss_delete(sh, key);
}

#delete_ifObject



1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
# File 'ext/swiss_hash/swiss_hash.c', line 1192

static VALUE swiss_hash_delete_if(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            VALUE key = sh->slots[i].key;
            VALUE value = sh->slots[i].value;
            if (RTEST(rb_yield_values(2, key, value))) {
                swiss_delete(sh, key);
            }
        }
    }

    return self;
}

#dig(key, *rest) ⇒ Object



16
17
18
19
20
21
# File 'lib/swiss_hash.rb', line 16

def dig(key, *rest)
  value = self[key]
  return value if rest.empty? || value.nil?

  value.dig(*rest)
end

#eachObject



795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
# File 'ext/swiss_hash/swiss_hash.c', line 795

static VALUE swiss_hash_each(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    RETURN_ENUMERATOR(self, 0, 0);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            rb_yield_values(2, sh->slots[i].key, sh->slots[i].value);
        }
    }

    return self;
}

#each_keyObject



839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
# File 'ext/swiss_hash/swiss_hash.c', line 839

static VALUE swiss_hash_each_key(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    RETURN_ENUMERATOR(self, 0, 0);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            rb_yield(sh->slots[i].key);
        }
    }

    return self;
}

#each_pairObject



795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
# File 'ext/swiss_hash/swiss_hash.c', line 795

static VALUE swiss_hash_each(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    RETURN_ENUMERATOR(self, 0, 0);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            rb_yield_values(2, sh->slots[i].key, sh->slots[i].value);
        }
    }

    return self;
}

#each_valueObject



855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
# File 'ext/swiss_hash/swiss_hash.c', line 855

static VALUE swiss_hash_each_value(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    RETURN_ENUMERATOR(self, 0, 0);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            rb_yield(sh->slots[i].value);
        }
    }

    return self;
}

#empty?Boolean

Returns:

  • (Boolean)


776
777
778
779
780
# File 'ext/swiss_hash/swiss_hash.c', line 776

static VALUE swiss_hash_empty_p(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
    return sh->size == 0 ? Qtrue : Qfalse;
}

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
44
# File 'lib/swiss_hash.rb', line 41

def eql?(other)
  other = other.to_h if other.is_a?(self.class)
  to_h.eql?(other)
end

#except(*args) ⇒ Object



1105
1106
1107
1108
1109
1110
1111
# File 'ext/swiss_hash/swiss_hash.c', line 1105

static VALUE swiss_hash_except(int argc, VALUE *argv, VALUE self) {
    VALUE result = rb_obj_dup(self);
    for (int i = 0; i < argc; i++) {
        swiss_hash_delete(result, argv[i]);
    }
    return result;
}

#fetch(*args) ⇒ Object



904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
# File 'ext/swiss_hash/swiss_hash.c', line 904

static VALUE swiss_hash_fetch(int argc, VALUE *argv, VALUE self) {
    VALUE key;
    VALUE default_value;
    rb_scan_args(argc, argv, "11", &key, &default_value);

    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE *val = swiss_lookup(sh, key);
    if (val) {
        return *val;
    }

    if (rb_block_given_p()) {
        if (argc == 2) {
            rb_warn("block supersedes default value argument");
        }
        return rb_yield(key);
    }

    if (argc == 2) {
        return default_value;
    }

    VALUE inspected = rb_inspect(key);
    VALUE message = rb_str_plus(rb_str_new_cstr("key not found: "), inspected);
    rb_exc_raise(rb_exc_new_str(rb_eKeyError, message));

    return Qnil;
}

#fetch_values(*args) ⇒ Object



1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
# File 'ext/swiss_hash/swiss_hash.c', line 1070

static VALUE swiss_hash_fetch_values(int argc, VALUE *argv, VALUE self) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE ary = rb_ary_new_capa((long)argc);
    int has_block = rb_block_given_p();

    for (int i = 0; i < argc; i++) {
        VALUE *val = swiss_lookup(sh, argv[i]);
        if (val) {
            rb_ary_push(ary, *val);
        } else if (has_block) {
            rb_ary_push(ary, rb_yield(argv[i]));
        } else {
            VALUE key_argv[1] = {argv[i]};
            rb_ary_push(ary, swiss_hash_fetch(1, key_argv, self));
        }
    }

    return ary;
}

#filterObject



1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
# File 'ext/swiss_hash/swiss_hash.c', line 1232

static VALUE swiss_hash_select(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *src;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
    VALUE result = swiss_hash_new_like(self, src->size);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (size_t i = 0; i < src->capacity; i++) {
        uint8_t c = src->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            VALUE key = src->slots[i].key;
            VALUE value = src->slots[i].value;
            if (RTEST(rb_yield_values(2, key, value))) {
                swiss_hash_store_prepared(dst, key, value);
            }
        }
    }

    return result;
}

#filter!Object



1276
1277
1278
1279
1280
1281
1282
# File 'ext/swiss_hash/swiss_hash.c', line 1276

static VALUE swiss_hash_select_bang(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    size_t old_size = ((SwissHash *)RTYPEDDATA_DATA(self))->size;
    swiss_hash_keep_if(self);
    return ((SwissHash *)RTYPEDDATA_DATA(self))->size == old_size ? Qnil : self;
}

#flatten(level = 1) ⇒ Object



32
33
34
# File 'lib/swiss_hash.rb', line 32

def flatten(level = 1)
  to_a.flatten(level)
end

#has_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


977
978
979
980
981
# File 'ext/swiss_hash/swiss_hash.c', line 977

static VALUE swiss_hash_key_p(VALUE self, VALUE key) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE *val = swiss_lookup(sh, key);
    return val ? Qtrue : Qfalse;
}

#has_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
# File 'ext/swiss_hash/swiss_hash.c', line 945

static VALUE swiss_hash_value_p(VALUE self, VALUE value) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            if (RTEST(rb_equal(sh->slots[i].value, value))) {
                return Qtrue;
            }
        }
    }

    return Qfalse;
}

#hashObject



46
47
48
# File 'lib/swiss_hash.rb', line 46

def hash
  to_h.hash
end

#include?(key) ⇒ Boolean

Returns:

  • (Boolean)


977
978
979
980
981
# File 'ext/swiss_hash/swiss_hash.c', line 977

static VALUE swiss_hash_key_p(VALUE self, VALUE key) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE *val = swiss_lookup(sh, key);
    return val ? Qtrue : Qfalse;
}

#initialize_copy(original) ⇒ Object



721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
# File 'ext/swiss_hash/swiss_hash.c', line 721

static VALUE swiss_hash_initialize_copy(VALUE self, VALUE original) {
    if (self == original) {
        return self;
    }

    SwissHash *src;
    SwissHash *dst;
    TypedData_Get_Struct(original, SwissHash, &swiss_hash_type, src);
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, dst);

    if (dst->ctrl || dst->slots) {
        swiss_free_arrays(dst);
    }

    if (!src->ctrl || !src->slots) {
        swiss_init(dst, 16);
        return self;
    }

    swiss_init(dst, src->capacity);
    memcpy(dst->ctrl, src->ctrl, src->capacity * sizeof(uint8_t));
    memcpy(dst->slots, src->slots, src->capacity * sizeof(Slot));
    dst->size = src->size;
    dst->growth_left = src->growth_left;
    dst->tombstone_count = src->tombstone_count;
    dst->mutating = 0;

    return self;
}

#inspectObject Also known as: to_s



50
51
52
53
# File 'lib/swiss_hash.rb', line 50

def inspect
  s = stats
  "#<SwissHash::Hash size=#{s[:size]} capacity=#{s[:capacity]} load=#{(s[:load_factor] * 100).round(1)}%>"
end

#invertObject



1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
# File 'ext/swiss_hash/swiss_hash.c', line 1113

static VALUE swiss_hash_invert(VALUE self) {
    SwissHash *src;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
    VALUE result = swiss_hash_new_like(self, src->size);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (size_t i = 0; i < src->capacity; i++) {
        uint8_t c = src->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            swiss_hash_store_prepared(dst, src->slots[i].value, src->slots[i].key);
        }
    }

    return result;
}

#keep_ifObject



1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
# File 'ext/swiss_hash/swiss_hash.c', line 1212

static VALUE swiss_hash_keep_if(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            VALUE key = sh->slots[i].key;
            VALUE value = sh->slots[i].value;
            if (!RTEST(rb_yield_values(2, key, value))) {
                swiss_delete(sh, key);
            }
        }
    }

    return self;
}

#key(value) ⇒ Object



961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
# File 'ext/swiss_hash/swiss_hash.c', line 961

static VALUE swiss_hash_key_for_value(VALUE self, VALUE value) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            if (RTEST(rb_equal(sh->slots[i].value, value))) {
                return sh->slots[i].key;
            }
        }
    }

    return Qnil;
}

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


977
978
979
980
981
# File 'ext/swiss_hash/swiss_hash.c', line 977

static VALUE swiss_hash_key_p(VALUE self, VALUE key) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE *val = swiss_lookup(sh, key);
    return val ? Qtrue : Qfalse;
}

#keysObject



811
812
813
814
815
816
817
818
819
820
821
822
823
# File 'ext/swiss_hash/swiss_hash.c', line 811

static VALUE swiss_hash_keys(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
    VALUE ary = rb_ary_new_capa(sh->size);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            rb_ary_push(ary, sh->slots[i].key);
        }
    }
    return ary;
}

#lengthObject



770
771
772
773
774
# File 'ext/swiss_hash/swiss_hash.c', line 770

static VALUE swiss_hash_size(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
    return SIZET2NUM(sh->size);
}

#member?(key) ⇒ Boolean

Returns:

  • (Boolean)


977
978
979
980
981
# File 'ext/swiss_hash/swiss_hash.c', line 977

static VALUE swiss_hash_key_p(VALUE self, VALUE key) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE *val = swiss_lookup(sh, key);
    return val ? Qtrue : Qfalse;
}

#merge(*args) ⇒ Object



1053
1054
1055
1056
1057
# File 'ext/swiss_hash/swiss_hash.c', line 1053

static VALUE swiss_hash_merge(int argc, VALUE *argv, VALUE self) {
    VALUE copy = rb_obj_dup(self);
    swiss_hash_merge_bang(argc, argv, copy);
    return copy;
}

#merge!(*args) ⇒ Object



1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
# File 'ext/swiss_hash/swiss_hash.c', line 1042

static VALUE swiss_hash_merge_bang(int argc, VALUE *argv, VALUE self) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    MergeCtx ctx = {self, sh, rb_block_given_p()};

    for (int i = 0; i < argc; i++) {
        swiss_hash_merge_one(&ctx, argv[i]);
    }

    return self;
}

#rassoc(object) ⇒ Object



1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
# File 'ext/swiss_hash/swiss_hash.c', line 1148

static VALUE swiss_hash_rassoc(VALUE self, VALUE object) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            if (RTEST(rb_equal(sh->slots[i].value, object))) {
                VALUE ary = rb_ary_new_capa(2);
                rb_ary_push(ary, sh->slots[i].key);
                rb_ary_push(ary, sh->slots[i].value);
                return ary;
            }
        }
    }

    return Qnil;
}

#rejectObject



1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
# File 'ext/swiss_hash/swiss_hash.c', line 1254

static VALUE swiss_hash_reject(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *src;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
    VALUE result = swiss_hash_new_like(self, src->size);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (size_t i = 0; i < src->capacity; i++) {
        uint8_t c = src->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            VALUE key = src->slots[i].key;
            VALUE value = src->slots[i].value;
            if (!RTEST(rb_yield_values(2, key, value))) {
                swiss_hash_store_prepared(dst, key, value);
            }
        }
    }

    return result;
}

#reject!Object



1284
1285
1286
1287
1288
1289
1290
# File 'ext/swiss_hash/swiss_hash.c', line 1284

static VALUE swiss_hash_reject_bang(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    size_t old_size = ((SwissHash *)RTYPEDDATA_DATA(self))->size;
    swiss_hash_delete_if(self);
    return ((SwissHash *)RTYPEDDATA_DATA(self))->size == old_size ? Qnil : self;
}

#replace(other) ⇒ Object



1059
1060
1061
1062
1063
1064
# File 'ext/swiss_hash/swiss_hash.c', line 1059

static VALUE swiss_hash_replace(VALUE self, VALUE other) {
    swiss_hash_clear(self);
    VALUE argv[1] = {other};
    swiss_hash_merge_bang(1, argv, self);
    return self;
}

#selectObject



1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
# File 'ext/swiss_hash/swiss_hash.c', line 1232

static VALUE swiss_hash_select(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *src;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
    VALUE result = swiss_hash_new_like(self, src->size);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (size_t i = 0; i < src->capacity; i++) {
        uint8_t c = src->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            VALUE key = src->slots[i].key;
            VALUE value = src->slots[i].value;
            if (RTEST(rb_yield_values(2, key, value))) {
                swiss_hash_store_prepared(dst, key, value);
            }
        }
    }

    return result;
}

#select!Object



1276
1277
1278
1279
1280
1281
1282
# File 'ext/swiss_hash/swiss_hash.c', line 1276

static VALUE swiss_hash_select_bang(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    size_t old_size = ((SwissHash *)RTYPEDDATA_DATA(self))->size;
    swiss_hash_keep_if(self);
    return ((SwissHash *)RTYPEDDATA_DATA(self))->size == old_size ? Qnil : self;
}

#shiftObject



1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
# File 'ext/swiss_hash/swiss_hash.c', line 1167

static VALUE swiss_hash_shift(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            VALUE key = sh->slots[i].key;
            VALUE value = sh->slots[i].value;
            sh->ctrl[i] = CTRL_DELETED;
            sh->slots[i].key = Qnil;
            sh->slots[i].value = Qnil;
            sh->size--;
            sh->tombstone_count++;

            VALUE ary = rb_ary_new_capa(2);
            rb_ary_push(ary, key);
            rb_ary_push(ary, value);
            return ary;
        }
    }

    return Qnil;
}

#sizeObject



770
771
772
773
774
# File 'ext/swiss_hash/swiss_hash.c', line 770

static VALUE swiss_hash_size(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
    return SIZET2NUM(sh->size);
}

#slice(*args) ⇒ Object



1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
# File 'ext/swiss_hash/swiss_hash.c', line 1090

static VALUE swiss_hash_slice(int argc, VALUE *argv, VALUE self) {
    SwissHash *src = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE result = swiss_hash_new_like(self, (size_t)argc);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (int i = 0; i < argc; i++) {
        VALUE *val = swiss_lookup(src, argv[i]);
        if (val) {
            swiss_hash_store_prepared(dst, argv[i], *val);
        }
    }

    return result;
}

#statsObject



1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
# File 'ext/swiss_hash/swiss_hash.c', line 1387

static VALUE swiss_hash_stats(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    double load = sh->capacity > 0 ? (double)sh->size / sh->capacity : 0.0;

    VALUE hash = rb_hash_new();
    rb_hash_aset(hash, ID2SYM(rb_intern("capacity")), SIZET2NUM(sh->capacity));
    rb_hash_aset(hash, ID2SYM(rb_intern("size")), SIZET2NUM(sh->size));
    rb_hash_aset(hash, ID2SYM(rb_intern("num_groups")), SIZET2NUM(sh->num_groups));
    rb_hash_aset(hash, ID2SYM(rb_intern("load_factor")), DBL2NUM(load));
    rb_hash_aset(hash, ID2SYM(rb_intern("memory_bytes")), SIZET2NUM(swiss_hash_memsize(sh)));
    rb_hash_aset(hash, ID2SYM(rb_intern("growth_left")), SIZET2NUM(sh->growth_left));
    rb_hash_aset(hash, ID2SYM(rb_intern("tombstones")), SIZET2NUM(sh->tombstone_count));

#ifdef SWISS_USE_SSE2
    rb_hash_aset(hash, ID2SYM(rb_intern("simd")), rb_str_new_cstr("SSE2"));
#else
    rb_hash_aset(hash, ID2SYM(rb_intern("simd")), rb_str_new_cstr("SWAR"));
#endif
    rb_hash_aset(hash, ID2SYM(rb_intern("layout")), rb_str_new_cstr("hybrid"));

    return hash;
}

#store(key, value) ⇒ Object



751
752
753
754
755
756
757
# File 'ext/swiss_hash/swiss_hash.c', line 751

static VALUE swiss_hash_aset(VALUE self, VALUE key, VALUE value) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    if (RB_UNLIKELY(!(FIXNUM_P(key) || SYMBOL_P(key)))) {
        key = prepare_key(key);
    }
    return swiss_insert(sh, key, value);
}

#to_aObject



886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
# File 'ext/swiss_hash/swiss_hash.c', line 886

static VALUE swiss_hash_to_a(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    VALUE ary = rb_ary_new_capa(sh->size);
    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            VALUE pair = rb_ary_new_capa(2);
            rb_ary_push(pair, sh->slots[i].key);
            rb_ary_push(pair, sh->slots[i].value);
            rb_ary_push(ary, pair);
        }
    }

    return ary;
}

#to_hObject



871
872
873
874
875
876
877
878
879
880
881
882
883
884
# File 'ext/swiss_hash/swiss_hash.c', line 871

static VALUE swiss_hash_to_h(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    VALUE hash = rb_hash_new();
    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            rb_hash_aset(hash, sh->slots[i].key, sh->slots[i].value);
        }
    }

    return hash;
}

#to_shObject



1066
1067
1068
# File 'ext/swiss_hash/swiss_hash.c', line 1066

static VALUE swiss_hash_to_sh(VALUE self) {
    return rb_obj_dup(self);
}

#transform_keysObject



1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
# File 'ext/swiss_hash/swiss_hash.c', line 1358

static VALUE swiss_hash_transform_keys(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *src;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
    VALUE result = swiss_hash_new_like(self, src->size);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (size_t i = 0; i < src->capacity; i++) {
        uint8_t c = src->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            swiss_hash_store_prepared(dst, rb_yield(src->slots[i].key), src->slots[i].value);
        }
    }

    return result;
}

#transform_keys!Object



23
24
25
26
27
28
29
30
# File 'lib/swiss_hash.rb', line 23

def transform_keys!
  return enum_for(:transform_keys!) unless block_given?

  pairs = to_a
  clear
  pairs.each { |key, value| self[yield(key)] = value }
  self
end

#transform_valuesObject



1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
# File 'ext/swiss_hash/swiss_hash.c', line 1324

static VALUE swiss_hash_transform_values(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *src;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, src);
    VALUE result = swiss_hash_new_like(self, src->size);
    SwissHash *dst = (SwissHash *)RTYPEDDATA_DATA(result);

    for (size_t i = 0; i < src->capacity; i++) {
        uint8_t c = src->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            swiss_hash_store_prepared(dst, src->slots[i].key, rb_yield(src->slots[i].value));
        }
    }

    return result;
}

#transform_values!Object



1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
# File 'ext/swiss_hash/swiss_hash.c', line 1342

static VALUE swiss_hash_transform_values_bang(VALUE self) {
    RETURN_ENUMERATOR(self, 0, 0);

    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            sh->slots[i].value = rb_yield(sh->slots[i].value);
        }
    }

    return self;
}

#update(*args) ⇒ Object



1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
# File 'ext/swiss_hash/swiss_hash.c', line 1042

static VALUE swiss_hash_merge_bang(int argc, VALUE *argv, VALUE self) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    MergeCtx ctx = {self, sh, rb_block_given_p()};

    for (int i = 0; i < argc; i++) {
        swiss_hash_merge_one(&ctx, argv[i]);
    }

    return self;
}

#value?(value) ⇒ Boolean

Returns:

  • (Boolean)


945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
# File 'ext/swiss_hash/swiss_hash.c', line 945

static VALUE swiss_hash_value_p(VALUE self, VALUE value) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            if (RTEST(rb_equal(sh->slots[i].value, value))) {
                return Qtrue;
            }
        }
    }

    return Qfalse;
}

#valuesObject



825
826
827
828
829
830
831
832
833
834
835
836
837
# File 'ext/swiss_hash/swiss_hash.c', line 825

static VALUE swiss_hash_values(VALUE self) {
    SwissHash *sh;
    TypedData_Get_Struct(self, SwissHash, &swiss_hash_type, sh);
    VALUE ary = rb_ary_new_capa(sh->size);

    for (size_t i = 0; i < sh->capacity; i++) {
        uint8_t c = sh->ctrl[i];
        if (c != CTRL_EMPTY && c != CTRL_DELETED) {
            rb_ary_push(ary, sh->slots[i].value);
        }
    }
    return ary;
}

#values_at(*args) ⇒ Object



933
934
935
936
937
938
939
940
941
942
943
# File 'ext/swiss_hash/swiss_hash.c', line 933

static VALUE swiss_hash_values_at(int argc, VALUE *argv, VALUE self) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE ary = rb_ary_new_capa((long)argc);

    for (int i = 0; i < argc; i++) {
        VALUE *val = swiss_lookup(sh, argv[i]);
        rb_ary_push(ary, val ? *val : Qnil);
    }

    return ary;
}