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



1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
# File 'ext/swiss_hash/swiss_hash.c', line 1015

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



1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
# File 'ext/swiss_hash/swiss_hash.c', line 1069

static VALUE swiss_hash_aref(VALUE self, VALUE key) {
    SwissHash *sh = (SwissHash *)RTYPEDDATA_DATA(self);
    VALUE *val;
    if (FIXNUM_P(key)) {
        val = swiss_lookup_hashed(sh, key, hash_fixnum(key), 1);
    } else {
        val = swiss_lookup(sh, key);
    }
    return val ? *val : Qnil;
}

#[]=(key, value) ⇒ Object



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

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

#__compact_storage!Object



1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
# File 'ext/swiss_hash/swiss_hash.c', line 1691

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



1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
# File 'ext/swiss_hash/swiss_hash.c', line 1444

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



1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
# File 'ext/swiss_hash/swiss_hash.c', line 1097

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



1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
# File 'ext/swiss_hash/swiss_hash.c', line 1607

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



1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
# File 'ext/swiss_hash/swiss_hash.c', line 1623

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



1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
# File 'ext/swiss_hash/swiss_hash.c', line 1691

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



1080
1081
1082
1083
# File 'ext/swiss_hash/swiss_hash.c', line 1080

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

#delete_ifObject



1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
# File 'ext/swiss_hash/swiss_hash.c', line 1507

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



1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
# File 'ext/swiss_hash/swiss_hash.c', line 1110

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



1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
# File 'ext/swiss_hash/swiss_hash.c', line 1154

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



1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
# File 'ext/swiss_hash/swiss_hash.c', line 1110

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



1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
# File 'ext/swiss_hash/swiss_hash.c', line 1170

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)


1091
1092
1093
1094
1095
# File 'ext/swiss_hash/swiss_hash.c', line 1091

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



1420
1421
1422
1423
1424
1425
1426
# File 'ext/swiss_hash/swiss_hash.c', line 1420

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



1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
# File 'ext/swiss_hash/swiss_hash.c', line 1219

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



1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
# File 'ext/swiss_hash/swiss_hash.c', line 1385

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



1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
# File 'ext/swiss_hash/swiss_hash.c', line 1547

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



1591
1592
1593
1594
1595
1596
1597
# File 'ext/swiss_hash/swiss_hash.c', line 1591

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)


1292
1293
1294
1295
1296
# File 'ext/swiss_hash/swiss_hash.c', line 1292

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)


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

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)


1292
1293
1294
1295
1296
# File 'ext/swiss_hash/swiss_hash.c', line 1292

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



1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
# File 'ext/swiss_hash/swiss_hash.c', line 1028

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



1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
# File 'ext/swiss_hash/swiss_hash.c', line 1428

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



1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
# File 'ext/swiss_hash/swiss_hash.c', line 1527

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



1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
# File 'ext/swiss_hash/swiss_hash.c', line 1276

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)


1292
1293
1294
1295
1296
# File 'ext/swiss_hash/swiss_hash.c', line 1292

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



1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
# File 'ext/swiss_hash/swiss_hash.c', line 1126

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



1085
1086
1087
1088
1089
# File 'ext/swiss_hash/swiss_hash.c', line 1085

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)


1292
1293
1294
1295
1296
# File 'ext/swiss_hash/swiss_hash.c', line 1292

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



1368
1369
1370
1371
1372
# File 'ext/swiss_hash/swiss_hash.c', line 1368

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



1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
# File 'ext/swiss_hash/swiss_hash.c', line 1357

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



1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
# File 'ext/swiss_hash/swiss_hash.c', line 1463

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



1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
# File 'ext/swiss_hash/swiss_hash.c', line 1569

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



1599
1600
1601
1602
1603
1604
1605
# File 'ext/swiss_hash/swiss_hash.c', line 1599

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



1374
1375
1376
1377
1378
1379
# File 'ext/swiss_hash/swiss_hash.c', line 1374

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



1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
# File 'ext/swiss_hash/swiss_hash.c', line 1547

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



1591
1592
1593
1594
1595
1596
1597
# File 'ext/swiss_hash/swiss_hash.c', line 1591

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



1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
# File 'ext/swiss_hash/swiss_hash.c', line 1482

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



1085
1086
1087
1088
1089
# File 'ext/swiss_hash/swiss_hash.c', line 1085

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



1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
# File 'ext/swiss_hash/swiss_hash.c', line 1405

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



1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
# File 'ext/swiss_hash/swiss_hash.c', line 1702

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"));
#elif defined(SWISS_USE_NEON)
    rb_hash_aset(hash, ID2SYM(rb_intern("simd")), rb_str_new_cstr("NEON"));
#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



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

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

#to_aObject



1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
# File 'ext/swiss_hash/swiss_hash.c', line 1201

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



1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
# File 'ext/swiss_hash/swiss_hash.c', line 1186

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



1381
1382
1383
# File 'ext/swiss_hash/swiss_hash.c', line 1381

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

#transform_keysObject



1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
# File 'ext/swiss_hash/swiss_hash.c', line 1673

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



1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
# File 'ext/swiss_hash/swiss_hash.c', line 1639

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



1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
# File 'ext/swiss_hash/swiss_hash.c', line 1657

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



1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
# File 'ext/swiss_hash/swiss_hash.c', line 1357

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)


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

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



1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
# File 'ext/swiss_hash/swiss_hash.c', line 1140

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



1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
# File 'ext/swiss_hash/swiss_hash.c', line 1248

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;
}