diff --git a/vm/capi/bignum.cpp b/vm/capi/bignum.cpp index 13b3f02507..e93d1398ff 100644 --- a/vm/capi/bignum.cpp +++ b/vm/capi/bignum.cpp @@ -81,7 +81,27 @@ extern "C" { rb_raise(rb_eArgError, "parameter is not a Bignum"); return 0; + } + + unsigned long long rb_big2ull(VALUE obj) { + NativeMethodEnvironment* env = NativeMethodEnvironment::get(); + + Object* object = env->get_object(obj); + + if(object->nil_p()) { + rb_raise(rb_eTypeError, "no implicit conversion from nil to unsigned long"); + } else if(Bignum* big = try_as(object)) { + if((size_t)mp_count_bits(big->mp_val()) > sizeof(unsigned long long) * CHAR_BIT) + rb_raise(rb_eRangeError, "bignum too big to convert into unsigned long long"); + + unsigned long long val = big->to_ulong_long(); + if(big->mp_val()->sign == MP_NEG) return -val; + return val; + } + + rb_raise(rb_eArgError, "parameter is not a Bignum"); + return 0; } double rb_big2dbl(VALUE obj) { diff --git a/vm/capi/ruby.h b/vm/capi/ruby.h index 814434721a..54eb6aea45 100644 --- a/vm/capi/ruby.h +++ b/vm/capi/ruby.h @@ -795,6 +795,8 @@ double rb_num2dbl(VALUE); long long rb_big2ll(VALUE obj); + unsigned long long rb_big2ull(VALUE); + double rb_big2dbl(VALUE obj); int rb_big_bytes_used(VALUE obj);