Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/spinel_rt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7547,6 +7547,12 @@ static int sp_poly_both_arrays(sp_RbVal a, sp_RbVal b) {
return a.tag == SP_TAG_OBJ && sp_poly_is_array_kind(a.cls_id) &&
b.tag == SP_TAG_OBJ && sp_poly_is_array_kind(b.cls_id);
}
/* Two Integers, one of them a Bignum: sp_poly_bitop keeps the width, where
the int64 arm below cut `28 | 2**64` to 28. */
static int sp_poly_bitop_wide(sp_RbVal a, sp_RbVal b) {
return (a.tag == SP_TAG_INT && b.tag == SP_TAG_BIGINT) ||
(a.tag == SP_TAG_BIGINT && (b.tag == SP_TAG_INT || b.tag == SP_TAG_BIGINT));
}
static sp_RbVal sp_poly_band(sp_RbVal a, sp_RbVal b) {
if (a.tag == SP_TAG_NIL) return sp_box_bool(0);
if (a.tag == SP_TAG_BOOL) return sp_box_bool(a.v.b && sp_poly_truthy(b));
Expand All @@ -7559,6 +7565,7 @@ static sp_RbVal sp_poly_band(sp_RbVal a, sp_RbVal b) {
if (sp_poly_is_user_obj(a)) return sp_poly_binop_bad("&", a, b);
/* Integer#& is Integer's alone (see sp_poly_bitop) */
if (a.tag != SP_TAG_INT && a.tag != SP_TAG_BIGINT) return sp_poly_binop_bad("&", a, b);
if (sp_poly_bitop_wide(a, b)) return sp_poly_bitop(a, b, 0);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return sp_box_int(sp_poly_to_i(a) & sp_poly_bit_operand(b, 0));
}
static sp_RbVal sp_poly_bor(sp_RbVal a, sp_RbVal b) {
Expand All @@ -7573,6 +7580,7 @@ static sp_RbVal sp_poly_bor(sp_RbVal a, sp_RbVal b) {
if (sp_poly_is_user_obj(a)) return sp_poly_binop_bad("|", a, b);
/* Integer#| is Integer's alone (see sp_poly_bitop) */
if (a.tag != SP_TAG_INT && a.tag != SP_TAG_BIGINT) return sp_poly_binop_bad("|", a, b);
if (sp_poly_bitop_wide(a, b)) return sp_poly_bitop(a, b, 1);
return sp_box_int(sp_poly_to_i(a) | sp_poly_bit_operand(b, 0));
}
static sp_RbVal sp_poly_bxor(sp_RbVal a, sp_RbVal b) {
Expand All @@ -7581,6 +7589,7 @@ static sp_RbVal sp_poly_bxor(sp_RbVal a, sp_RbVal b) {
if (sp_poly_is_user_obj(a)) return sp_poly_binop_bad("^", a, b);
/* Integer#^ is Integer's alone (see sp_poly_bitop) */
if (a.tag != SP_TAG_INT && a.tag != SP_TAG_BIGINT) return sp_poly_binop_bad("^", a, b);
if (sp_poly_bitop_wide(a, b)) return sp_poly_bitop(a, b, 2);
return sp_box_int(sp_poly_to_i(a) ^ sp_poly_bit_operand(b, 0));
}
/* Unary minus on a boxed value. Only Float and Integer were handled, and
Expand Down
41 changes: 41 additions & 0 deletions test/poly_bitop_bignum_width.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# spinel: int64
# Integer#&, #| and #^ on a boxed Integer and a Bignum keep the Bignum's
# width. sp_poly_band, sp_poly_bor and sp_poly_bxor read both sides as
# int64, so a `|` or `^` line below answered 28 (or 29) where CRuby answers
# a Bignum. A fold by a Symbol, an element's OP= and a receiver of an
# unknown kind reach them. A `&` that masks a Bignum fits an int, and stays
# as it was.
big = 2**64

pa = [28, big, "x"]
pa.pop
p pa.reduce(:|)
p pa.reduce(:^)
p [big, 28, :s].first(2).inject(:|)
p [big + 4, 4, :s].first(2).reduce(:&)

ops = [:|, :+]
op = ops[ARGV.size]
p pa.reduce(op)

a = [28, "s"]
a[0] |= big
p a[0]

h = {n: 28, s: "t"}
h[:n] |= big
p h[:n]
h[:n] ^= 1
p h[:n]

r = ARGV.size == 0 ? [28] : {0 => 28}
r[0] |= big
p r[0]

# a pair of machine words, and an operand that is not an Integer, as before
p [28, 3, :s].first(2).reduce(:|)
begin
p [big, 1.5, :s].first(2).reduce(:|)
rescue TypeError => e
p e.message
end
11 changes: 11 additions & 0 deletions test/poly_bitop_bignum_width.rb.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
18446744073709551644
18446744073709551644
18446744073709551644
4
18446744073709551644
18446744073709551644
18446744073709551644
18446744073709551645
18446744073709551644
31
"1.5 can't be coerced into Integer"
Loading