Class: String

Inherits:
Object
  • Object
show all
Defined in:
(unknown)

Instance Method Summary collapse

Instance Method Details

#bit_clear(*args) ⇒ Object



1230
1231
1232
1233
1234
# File 'ext/string_bits/string_bits.c', line 1230

static VALUE
rb_str_bit_clear(int argc, VALUE *argv, VALUE self)
{
    return rb_str_mutate_bits(argc, argv, self, SB_MUT_CLEAR);
}

#bit_count(*args) ⇒ Object



693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
# File 'ext/string_bits/string_bits.c', line 693

static VALUE
rb_str_bit_count(int argc, VALUE *argv, VALUE self)
{
    const unsigned char *str = (const unsigned char *)RSTRING_PTR(self);
    ssize_t src_len = RSTRING_LEN(self);

    VALUE v0 = Qnil, v1 = Qnil, opts = Qnil;
    rb_scan_args(argc, argv, "02:", &v0, &v1, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);

    /* No positional args: count the whole string; lsb_first: is ignored (order-independent) */
    if (NIL_P(v0))
        return SSIZET2NUM(count_set_bits(str, src_len));

    int lsb_first = parse_lsb_first_opt(opts);
    int64_t total_bits = SB_BIT_LEN(src_len);
    ssize_t bit_offset, bit_length;

    if (rb_obj_is_kind_of(v0, rb_cRange)) {
        if (!NIL_P(v1))
            rb_raise(rb_eArgError, "wrong number of arguments");
        ssize_t beg, len;
        if (sb_bit_range_beg_len(v0, &beg, &len, total_bits) == SB_RANGE_OUT)
            return INT2FIX(0);
        bit_offset = beg;
        bit_length = len;
    }
    else if (!NIL_P(v1)) {
        uint64_t off = sb_bit_offset(v0);
        uint64_t len = sb_bit_length(v1);
        /* A region starting at or past the end holds no bits, and one that
         * runs off the end contributes only the part that exists. */
        if (off >= (uint64_t)total_bits) return INT2FIX(0);
        bit_offset = sb_narrow_bit_pos(off, total_bits);
        bit_length = sb_clamp_bit_length(len, bit_offset, total_bits);
    }
    else {
        rb_raise(rb_eArgError,
                 "wrong number of arguments (given 1, expected 0, 1 Range, or 2)");
    }

    if (lsb_first)
        return SSIZET2NUM(count_set_bits_range(str, src_len, bit_offset, bit_length));
    else
        return SSIZET2NUM(count_set_bits_range_msb(str, src_len, bit_offset, bit_length));
}

#bit_fields(*args) ⇒ Object



1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
# File 'ext/string_bits/string_bits.c', line 1519

static VALUE
rb_str_bit_fields(int argc, VALUE *argv, VALUE self)
{
    VALUE rest, opts;
    rb_scan_args(argc, argv, "*:", &rest, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);

    ssize_t num_fields = RARRAY_LEN(rest);
    if (num_fields == 0) {
        rb_raise(rb_eArgError, "wrong number of arguments (given 0, expected 1+)");
    }

    ssize_t *bitlens = ALLOCA_N(ssize_t, num_fields);
    ssize_t step = 0;
    for (ssize_t f = 0; f < num_fields; f++) {
        VALUE v = RARRAY_AREF(rest, f);
        if (!rb_integer_type_p(v)) {
            rb_raise(rb_eTypeError, "bitlen must be an integer");
        }
        ssize_t bl = NUM2SSIZET(v);
        if (bl <= 0) {
            rb_raise(rb_eArgError, "bitlen must be positive");
        }
        if (bl > 64) {
            rb_raise(rb_eArgError, "bitlen must be <= 64 (got %" PRIdPTR ")", (intptr_t)bl);
        }
        bitlens[f] = bl;
        step += bl;
    }

    int lsb_first = parse_lsb_first_opt(opts);

    ssize_t src_len = RSTRING_LEN(self);
    int64_t total_bits = SB_BIT_LEN(src_len);
    ssize_t iterations = (ssize_t)(total_bits / step);

    int have_block = rb_block_given_p();
    VALUE result = have_block ? Qnil : rb_ary_new_capa(iterations);

    VALUE *field_vals = ALLOCA_N(VALUE, num_fields);

    for (ssize_t iter = 0; iter < iterations; iter++) {
        ssize_t base_bit = iter * step;
        const unsigned char *src = (const unsigned char *)RSTRING_PTR(self);
        ssize_t field_bit = base_bit;
        for (ssize_t f = 0; f < num_fields; f++) {
            uint64_t val = extract_uint64(src, src_len, field_bit, bitlens[f], lsb_first);
            field_vals[f] = ULL2NUM(val);
            field_bit += bitlens[f];
        }
        if (have_block) {
            rb_yield_values2((int)num_fields, field_vals);
        } else if (num_fields == 1) {
            rb_ary_push(result, field_vals[0]);
        } else {
            rb_ary_push(result, rb_ary_new_from_values(num_fields, field_vals));
        }
    }

    return have_block ? self : result;
}

#bit_flip(*args) ⇒ Object



1236
1237
1238
1239
1240
# File 'ext/string_bits/string_bits.c', line 1236

static VALUE
rb_str_bit_flip(int argc, VALUE *argv, VALUE self)
{
    return rb_str_mutate_bits(argc, argv, self, SB_MUT_FLIP);
}

#bit_get(*args) ⇒ Object



553
554
555
556
557
558
# File 'ext/string_bits/string_bits.c', line 553

static VALUE
rb_str_bit_get(int argc, VALUE *argv, VALUE self)
{
    int bit = str_bit_read(argc, argv, self);
    return bit < 0 ? Qnil : INT2FIX(bit);
}

#bit_offsets(*args) ⇒ Object



944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
# File 'ext/string_bits/string_bits.c', line 944

static VALUE
rb_str_bit_offsets(int argc, VALUE *argv, VALUE self)
{
    VALUE bit_val, start_offset_v = Qnil, opts = Qnil;
    rb_scan_args(argc, argv, "11:", &bit_val, &start_offset_v, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);
    int target    = parse_bit_target(bit_val);
    ssize_t start_offset = parse_start_offset(self, start_offset_v);

    ssize_t len = RSTRING_LEN(self);
    const unsigned char *str = (const unsigned char *)RSTRING_PTR(self);

    if (rb_block_given_p()) {
        emit_bit_offsets(str, len, target, lsb_first, start_offset, Qnil);
        return self;
    }

    /* Pre-size the Array using popcount to avoid repeated reallocation.
     * For target=0 the expected count is (len * 8 - popcount). */
    ssize_t set_count = count_set_bits(str, len);
    ssize_t count     = (target == 1) ? set_count : (ssize_t)(SB_BIT_LEN(len) - set_count);
    VALUE ary = rb_ary_new_capa(count);
    emit_bit_offsets(str, len, target, lsb_first, start_offset, ary);
    return ary;
}

#bit_run_count(*args) ⇒ Object



1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
# File 'ext/string_bits/string_bits.c', line 1651

static VALUE
rb_str_bit_run_count(int argc, VALUE *argv, VALUE self)
{
    VALUE bit_offset_v, bit_val, opts;
    rb_scan_args(argc, argv, "20:", &bit_val, &bit_offset_v, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);

    if (!rb_integer_type_p(bit_offset_v)) {
        rb_raise(rb_eTypeError, "position must be an integer");
    }
    int target = parse_bit_target(bit_val);
    ssize_t src_len = RSTRING_LEN(self);
    /* A position with no run starting at it and a position outside the string
     * are the same answer here -- nil -- so a negative or past-the-end offset
     * is not an error (see ProposedMethods.md, "Why bit_run_count never
     * returns 0"). */
    uint64_t off;
    if (sb_bit_position_soft(bit_offset_v, &off) < 0) return Qnil;
    if (off >= (uint64_t)SB_BIT_LEN(src_len)) return Qnil;
    ssize_t bit_offset = (ssize_t)off;

    const unsigned char *src = (const unsigned char *)RSTRING_PTR(self);
    if (lsb_first) {
        if (((src[bit_offset >> 3] >> (bit_offset & 7)) & 1) != target) return Qnil;
        return SSIZET2NUM(count_run_lsb(src, src_len, bit_offset, target));
    }

    if (logical_get_bit(src, bit_offset, 0) != target) return Qnil;

    ssize_t run = 1;
    int64_t total_bits = SB_BIT_LEN(src_len);
    while (bit_offset + run < total_bits && logical_get_bit(src, bit_offset + run, 0) == target) {
        run++;
    }
    return SSIZET2NUM(run);
}

#bit_runs(*args) ⇒ Object



1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
# File 'ext/string_bits/string_bits.c', line 1753

static VALUE
rb_str_bit_runs(int argc, VALUE *argv, VALUE self)
{
    VALUE start_offset_v = Qnil, opts = Qnil;
    rb_scan_args(argc, argv, "01:", &start_offset_v, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);
    ssize_t start_offset = parse_start_offset(self, start_offset_v);

    if (rb_block_given_p()) {
        emit_bit_runs(self, lsb_first, start_offset, Qnil);
        return self;
    }

    VALUE ary = rb_ary_new();
    emit_bit_runs(self, lsb_first, start_offset, ary);
    return ary;
}

#bit_set(*args) ⇒ Object



1224
1225
1226
1227
1228
# File 'ext/string_bits/string_bits.c', line 1224

static VALUE
rb_str_bit_set(int argc, VALUE *argv, VALUE self)
{
    return rb_str_mutate_bits(argc, argv, self, SB_MUT_SET);
}

#bit_set?(*args) ⇒ Object



561
562
563
564
565
566
567
# File 'ext/string_bits/string_bits.c', line 561

static VALUE
rb_str_bit_set_p(int argc, VALUE *argv, VALUE self)
{
    int bit = str_bit_read(argc, argv, self);
    if (bit < 0) return Qnil;
    return bit ? Qtrue : Qfalse;
}

#bit_slice(*args) ⇒ Object



1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
# File 'ext/string_bits/string_bits.c', line 1066

static VALUE
rb_str_bit_slice(int argc, VALUE *argv, VALUE self)
{
    ssize_t src_len = RSTRING_LEN(self);
    int64_t total_bits = SB_BIT_LEN(src_len);
    ssize_t bit_offset, bit_length;
    VALUE v0, v1, opts;
    int n_pos = rb_scan_args(argc, argv, "11:", &v0, &v1, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);

    if (n_pos == 1 && rb_obj_is_kind_of(v0, rb_cRange)) {
        ssize_t beg, len;
        if (sb_bit_range_beg_len(v0, &beg, &len, total_bits) == SB_RANGE_OUT) {
            return Qnil;
        }
        bit_offset = beg;
        bit_length = len;
    }
    else if (n_pos == 2) {
        uint64_t off, len;
        if (sb_bit_position_soft(v0, &off) < 0) return Qnil;
        if (sb_bit_position_soft(v1, &len) < 0) return Qnil;
        if (off > (uint64_t)total_bits) return Qnil;

        bit_offset = sb_narrow_bit_pos(off, total_bits);
        bit_length = sb_clamp_bit_length(len, bit_offset, total_bits);
    }
    else if (n_pos == 1) {
        return Qnil;
    }
    else {
        rb_raise(rb_eArgError,
                 "wrong number of arguments (given %d, expected 1 or 2)", n_pos);
    }

    if (bit_offset > total_bits) return Qnil;
    int64_t available = total_bits - bit_offset;
    if (bit_length > available) bit_length = (ssize_t)available;

    if (bit_length == 0) return rb_str_new("", 0);

    ssize_t out_bytes = (bit_length + 7) / 8;
    VALUE result = rb_str_buf_new(out_bytes);
    rb_str_resize(result, out_bytes);
    /* A bit-aligned slice is a repacked byte sequence, not a substring, so the
     * result carries BINARY like every other String returned by this API. */
    rb_enc_associate(result, rb_ascii8bit_encoding());
    ENC_CODERANGE_CLEAR(result);
    unsigned char *dst = (unsigned char *)RSTRING_PTR(result);
    const unsigned char *src = (const unsigned char *)RSTRING_PTR(self);

    memset(dst, 0, out_bytes);

    if (lsb_first) {
        bit_copy_core(dst, 0, src, src_len, bit_offset, bit_length);
    } else {
        ssize_t dst_bit = 0;
        ssize_t start_byte = bit_offset >> 3;
        ssize_t end_byte = (bit_offset + bit_length - 1) >> 3;

        for (ssize_t b = start_byte; b <= end_byte; b++) {
            ssize_t b_start_l = b << 3;
            ssize_t b_end_l = b_start_l + 7;
            ssize_t l_min = (bit_offset > b_start_l) ? bit_offset : b_start_l;
            ssize_t l_max = ((bit_offset + bit_length - 1) < b_end_l) ? (bit_offset + bit_length - 1) : b_end_l;

            ssize_t p_min = b_start_l + (7 - (l_max & 7L));
            ssize_t p_max = b_start_l + (7 - (l_min & 7L));
            ssize_t chunk_len = p_max - p_min + 1;

            bit_copy_core(dst, dst_bit, src, src_len, p_min, chunk_len);
            dst_bit += chunk_len;
        }
    }
    return result;
}

#bit_splice(*args) ⇒ Object



1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
# File 'ext/string_bits/string_bits.c', line 1773

static VALUE
rb_str_bit_splice(int argc, VALUE *argv, VALUE self)
{
    ssize_t dst_bit_off, dst_bit_len;
    ssize_t src_bit_off;
    VALUE str;
    int64_t dst_total = SB_BIT_LEN(RSTRING_LEN(self));
    VALUE v0, v1, v2, v3, opts;

    int n_pos = rb_scan_args(argc, argv, "22:", &v0, &v1, &v2, &v3, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);

    uint64_t dst_off_u, dst_len_u, src_off_u, src_len_u;

    if (n_pos <= 3 && rb_obj_is_kind_of(v0, rb_cRange)) {
        /* bit_splice(range, str) and bit_splice(range, str, str_bit_index) */
        ssize_t beg, len;
        if (sb_bit_range_beg_len(v0, &beg, &len, dst_total) == SB_RANGE_OUT) {
            rb_raise(rb_eIndexError,
                     "bit_splice: destination range starts past the end "
                     "(total %" PRId64 " bits)", (int64_t)dst_total);
        }
        dst_off_u = (uint64_t)beg;
        dst_len_u = (uint64_t)len;
        str = v1;
        Check_Type(str, T_STRING);
        if (n_pos == 3) {
            if (!rb_integer_type_p(v2)) {
                rb_raise(rb_eTypeError, "third argument must be an Integer");
            }
            src_off_u = sb_bit_offset(v2);
        }
        else {
            src_off_u = 0;
        }
        src_len_u = dst_len_u;
    }
    else if (n_pos == 3) {
        /* bit_splice(bit_index, bit_length, str) */
        if (!rb_integer_type_p(v0) || !rb_integer_type_p(v1)) {
            rb_raise(rb_eTypeError, "bit index and length must be integers");
        }
        dst_off_u = sb_bit_offset(v0);
        dst_len_u = sb_bit_length(v1);

        /*
         * Integer source support was prototyped here, but it is intentionally
         * disabled in the current proposal to keep the public API limited to
         * String-to-String splicing.
         */
        if (rb_integer_type_p(v2)) {
            rb_raise(rb_eArgError,
                     "bit_splice source must be a String in the current proposal");
        }

        str = v2;
        Check_Type(str, T_STRING);
        src_off_u = 0;
        src_len_u = dst_len_u;
    }
    else if (n_pos == 4) {
        /* bit_splice(bit_index, bit_length, str, str_bit_index) */
        if (!rb_integer_type_p(v0) || !rb_integer_type_p(v1) || !rb_integer_type_p(v3)) {
            rb_raise(rb_eTypeError, "bit indices and lengths must be integers");
        }
        dst_off_u = sb_bit_offset(v0);
        dst_len_u = sb_bit_length(v1);
        str = v2;
        Check_Type(str, T_STRING);
        src_off_u = sb_bit_offset(v3);
        src_len_u = dst_len_u;
    }
    else {
        rb_raise(rb_eArgError,
                 "wrong number of arguments (given %d, expected 2, 3, or 4)", n_pos);
    }

    /* Both ranges are checked in 64 bits: a position past the end of the
     * string is well-formed input here, so it must reach this bounds check
     * rather than being rejected while it is parsed. */
    if (dst_off_u > (uint64_t)dst_total || dst_len_u > (uint64_t)dst_total - dst_off_u) {
        rb_raise(rb_eIndexError,
                 "bit_splice: destination range [%" PRIu64 ", %" PRIu64
                 "] out of bounds (total %" PRId64 " bits)",
                 dst_off_u, dst_len_u, (int64_t)dst_total);
    }

    int64_t src_total_bits = SB_BIT_LEN(RSTRING_LEN(str));
    if (src_off_u > (uint64_t)src_total_bits ||
        src_len_u > (uint64_t)src_total_bits - src_off_u) {
        rb_raise(rb_eIndexError,
                 "bit_splice: source range [%" PRIu64 ", %" PRIu64
                 "] out of bounds (total %" PRId64 " bits)",
                 src_off_u, src_len_u, (int64_t)src_total_bits);
    }

    /* Both ranges are inside their strings now, so narrowing only fails on an
     * ILP32 build whose bit length exceeds the internal index (see
     * sb_narrow_bit_pos). */
    dst_bit_off = sb_narrow_bit_pos(dst_off_u, dst_total);
    dst_bit_len = (ssize_t)dst_len_u;
    if (dst_len_u > (uint64_t)(sb_addressable_bits(dst_total) - dst_bit_off)) {
        rb_raise(rb_eArgError, "bit index out of representable range");
    }
    src_bit_off = sb_narrow_bit_pos(src_off_u, src_total_bits);
    if (src_len_u > (uint64_t)(sb_addressable_bits(src_total_bits) - src_bit_off)) {
        rb_raise(rb_eArgError, "bit index out of representable range");
    }

    if (dst_bit_len == 0) return self;

    /* Guard against self-aliasing: duplicate src before modifying self */
    VALUE src_str = (str == self) ? rb_str_dup(str) : str;

    rb_str_modify(self);

    unsigned char       *dst          = (unsigned char *)RSTRING_PTR(self);
    const unsigned char *src          = (const unsigned char *)RSTRING_PTR(src_str);
    ssize_t                 src_len_bytes = RSTRING_LEN(src_str);

    if (lsb_first) {
        bit_copy_core(dst, dst_bit_off, src, src_len_bytes, src_bit_off, dst_bit_len);
    } else {
        ssize_t current_src_bit = src_bit_off;
        ssize_t start_byte = dst_bit_off >> 3;
        ssize_t end_byte = (dst_bit_off + dst_bit_len - 1) >> 3;

        for (ssize_t b = start_byte; b <= end_byte; b++) {
            ssize_t b_start_l = b << 3;
            ssize_t b_end_l = b_start_l + 7;
            ssize_t l_min = (dst_bit_off > b_start_l) ? dst_bit_off : b_start_l;
            ssize_t l_max = ((dst_bit_off + dst_bit_len - 1) < b_end_l) ? (dst_bit_off + dst_bit_len - 1) : b_end_l;

            ssize_t p_min = b_start_l + (7 - (l_max & 7L));
            ssize_t p_max = b_start_l + (7 - (l_min & 7L));
            ssize_t chunk_len = p_max - p_min + 1;

            bit_copy_core(dst, p_min, src, src_len_bytes, current_src_bit, chunk_len);
            current_src_bit += chunk_len;
        }
    }

    RB_GC_GUARD(src_str);
    return self;
}

#bits(*args) ⇒ Object



797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
# File 'ext/string_bits/string_bits.c', line 797

static VALUE
rb_str_bits(int argc, VALUE *argv, VALUE self)
{
    VALUE start_offset_v = Qnil, opts = Qnil;
    rb_scan_args(argc, argv, "01:", &start_offset_v, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);
    ssize_t start_offset = parse_start_offset(self, start_offset_v);
    ssize_t len = RSTRING_LEN(self);
    const unsigned char *str = (const unsigned char *)RSTRING_PTR(self);

    if (rb_block_given_p()) {
        emit_bits(str, len, lsb_first, start_offset, Qnil);
        return self;
    }

    int64_t total_bits = SB_BIT_LEN(len);
    ssize_t nbits = (start_offset >= total_bits) ? 0 : (ssize_t)(total_bits - start_offset);
    VALUE ary = rb_ary_new_capa(nbits);
    emit_bits(str, len, lsb_first, start_offset, ary);
    return ary;
}

#bitwise_andObject

#bitwise_and!Object

#bitwise_notObject

#bitwise_not!Object

#bitwise_orObject

#bitwise_or!Object

#bitwise_xorObject

#bitwise_xor!Object

#each_bit(*args) ⇒ Object



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

static VALUE
rb_str_each_bit(int argc, VALUE *argv, VALUE self)
{
    RETURN_ENUMERATOR(self, argc, argv);

    VALUE start_offset_v = Qnil, opts = Qnil;
    rb_scan_args(argc, argv, "01:", &start_offset_v, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);
    ssize_t start_offset = parse_start_offset(self, start_offset_v);

    emit_bits((const unsigned char *)RSTRING_PTR(self), RSTRING_LEN(self),
              lsb_first, start_offset, Qnil);
    return self;
}

#each_bit_field(*args) ⇒ Object

Yield each packed bit-field record as one Integer per field.



1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
# File 'ext/string_bits/string_bits.c', line 1463

static VALUE
rb_str_each_bit_field(int argc, VALUE *argv, VALUE self)
{
    RETURN_ENUMERATOR(self, argc, argv);

    VALUE rest, opts;
    rb_scan_args(argc, argv, "*:", &rest, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);

    ssize_t num_fields = RARRAY_LEN(rest);
    if (num_fields == 0) {
        rb_raise(rb_eArgError, "wrong number of arguments (given 0, expected 1+)");
    }

    ssize_t *bitlens = ALLOCA_N(ssize_t, num_fields);
    ssize_t step = 0;
    for (ssize_t f = 0; f < num_fields; f++) {
        VALUE v = RARRAY_AREF(rest, f);
        if (!rb_integer_type_p(v)) {
            rb_raise(rb_eTypeError, "bitlen must be an integer");
        }
        ssize_t bl = NUM2SSIZET(v);
        if (bl <= 0) {
            rb_raise(rb_eArgError, "bitlen must be positive");
        }
        if (bl > 64) {
            rb_raise(rb_eArgError, "bitlen must be <= 64 (got %" PRIdPTR ")", (intptr_t)bl);
        }
        bitlens[f] = bl;
        step += bl;
    }

    int lsb_first = parse_lsb_first_opt(opts);

    ssize_t src_len = RSTRING_LEN(self);
    int64_t total_bits = SB_BIT_LEN(src_len);
    ssize_t iterations = (ssize_t)(total_bits / step);

    VALUE *field_vals = ALLOCA_N(VALUE, num_fields);

    for (ssize_t iter = 0; iter < iterations; iter++) {
        ssize_t base_bit = iter * step;
        const unsigned char *src = (const unsigned char *)RSTRING_PTR(self);
        ssize_t field_bit = base_bit;
        for (ssize_t f = 0; f < num_fields; f++) {
            uint64_t val = extract_uint64(src, src_len, field_bit, bitlens[f], lsb_first);
            field_vals[f] = ULL2NUM(val);
            field_bit += bitlens[f];
        }
        rb_yield_values2((int)num_fields, field_vals);
    }

    return self;
}

#each_bit_offset(*args) ⇒ Object



927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
# File 'ext/string_bits/string_bits.c', line 927

static VALUE
rb_str_each_bit_offset(int argc, VALUE *argv, VALUE self)
{
    RETURN_ENUMERATOR(self, argc, argv);

    VALUE bit_val, start_offset_v = Qnil, opts = Qnil;
    rb_scan_args(argc, argv, "11:", &bit_val, &start_offset_v, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);
    int target    = parse_bit_target(bit_val);
    ssize_t start_offset = parse_start_offset(self, start_offset_v);

    emit_bit_offsets((const unsigned char *)RSTRING_PTR(self), RSTRING_LEN(self),
                     target, lsb_first, start_offset, Qnil);
    return self;
}

#each_bit_run(*args) ⇒ Object



1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
# File 'ext/string_bits/string_bits.c', line 1737

static VALUE
rb_str_each_bit_run(int argc, VALUE *argv, VALUE self)
{
    RETURN_ENUMERATOR(self, argc, argv);

    VALUE start_offset_v = Qnil, opts = Qnil;
    rb_scan_args(argc, argv, "01:", &start_offset_v, &opts);
    validate_option_hash(opts, SB_KW_LSB_FIRST);
    int lsb_first = parse_lsb_first_opt(opts);
    ssize_t start_offset = parse_start_offset(self, start_offset_v);

    emit_bit_runs(self, lsb_first, start_offset, Qnil);
    return self;
}