| | 3211 | /**********************************************************************************/ |
| | 3212 | #if WITH_OBJC |
| | 3213 | static inline double |
| | 3214 | nsnum_cdouble(VALUE num) |
| | 3215 | { |
| | 3216 | double val; CFNumberGetValue((CFNumberRef)num, kCFNumberDoubleType, &val); |
| | 3217 | return val; |
| | 3218 | } |
| | 3219 | |
| | 3220 | static inline long long |
| | 3221 | nsnum_cLL(VALUE num) |
| | 3222 | { |
| | 3223 | long long val; CFNumberGetValue((CFNumberRef)num, kCFNumberLongLongType, &val); |
| | 3224 | return val; |
| | 3225 | } |
| | 3226 | |
| | 3227 | static VALUE |
| | 3228 | nsnum_to_i(VALUE num) |
| | 3229 | { |
| | 3230 | return LL2NUM(nsnum_cLL(num)); |
| | 3231 | } |
| | 3232 | |
| | 3233 | static VALUE |
| | 3234 | nsnum_to_f(VALUE num) |
| | 3235 | { |
| | 3236 | return DOUBLE2NUM(nsnum_cdouble(num)); |
| | 3237 | } |
| | 3238 | |
| | 3239 | static VALUE |
| | 3240 | nsnum_class(VALUE num) |
| | 3241 | { |
| | 3242 | CFNumberType t = CFNumberGetType((CFNumberRef)num); |
| | 3243 | switch (t) { |
| | 3244 | case kCFNumberSInt8Type: |
| | 3245 | case kCFNumberSInt16Type: |
| | 3246 | case kCFNumberSInt32Type: |
| | 3247 | case kCFNumberSInt64Type: |
| | 3248 | case kCFNumberCharType: |
| | 3249 | case kCFNumberShortType: |
| | 3250 | case kCFNumberIntType: |
| | 3251 | case kCFNumberLongType: |
| | 3252 | case kCFNumberLongLongType: |
| | 3253 | case kCFNumberCFIndexType: |
| | 3254 | case kCFNumberNSIntegerType: |
| | 3255 | return rb_cFixnum; |
| | 3256 | case kCFNumberFloat32Type: |
| | 3257 | case kCFNumberFloat64Type: |
| | 3258 | case kCFNumberFloatType: |
| | 3259 | case kCFNumberDoubleType: |
| | 3260 | case kCFNumberMaxType: |
| | 3261 | return rb_cFloat; |
| | 3262 | } |
| | 3263 | if (CFNumberIsFloatType((CFNumberRef)num)) return rb_cFloat; |
| | 3264 | return rb_cNSNumber; //This could be something exotic like a struct |
| | 3265 | } |
| | 3266 | |
| | 3267 | static VALUE |
| | 3268 | nsnum_to_rb(VALUE num) |
| | 3269 | { |
| | 3270 | if (FIXNUM_P(num)) return num; |
| | 3271 | VALUE c = CLASS_OF(num); |
| | 3272 | if (c!=rb_cCFNumber && c!=rb_cNSNumber) return num; |
| | 3273 | VALUE num_class = nsnum_class(num); |
| | 3274 | if (num_class==rb_cFloat) return DOUBLE2NUM(nsnum_cdouble(num)); |
| | 3275 | if (num_class==rb_cFixnum) return LL2NUM(nsnum_cLL(num)); |
| | 3276 | return num; |
| | 3277 | } |
| | 3278 | |
| | 3279 | static void |
| | 3280 | nsnum_fail_coerce(VALUE num) |
| | 3281 | { |
| | 3282 | VALUE nsn_desc = rb_funcall(num, rb_intern("description"), 0); |
| | 3283 | const char* numdesc = StringValueCStr(nsn_desc); |
| | 3284 | rb_raise(rb_eTypeError, "Cannot coerce NSNumber %s into a ruby number", numdesc); |
| | 3285 | } |
| | 3286 | |
| | 3287 | static VALUE |
| | 3288 | nsnum_to_rb_force(VALUE num) |
| | 3289 | { |
| | 3290 | if (FIXNUM_P(num)) return num; |
| | 3291 | VALUE c = CLASS_OF(num); |
| | 3292 | if (c!=rb_cCFNumber && c!=rb_cNSNumber) return num; |
| | 3293 | VALUE num_class = nsnum_class(num); |
| | 3294 | if (num_class==rb_cFloat) return DOUBLE2NUM((nsnum_cdouble(num))); |
| | 3295 | if (num_class==rb_cFixnum) return LL2NUM((nsnum_cLL(num))); |
| | 3296 | nsnum_fail_coerce(num); |
| | 3297 | return Qnil; |
| | 3298 | } |
| | 3299 | |
| | 3300 | static VALUE |
| | 3301 | nsnum_to_rb_abs(VALUE num) |
| | 3302 | { |
| | 3303 | VALUE num_class = nsnum_class(num); |
| | 3304 | if (num_class==rb_cFloat) return DOUBLE2NUM(fabs(nsnum_cdouble(num))); |
| | 3305 | if (num_class==rb_cFixnum) return LL2NUM(llabs(nsnum_cLL(num))); |
| | 3306 | nsnum_fail_coerce(num); |
| | 3307 | return Qnil; |
| | 3308 | } |
| | 3309 | |
| | 3310 | static VALUE |
| | 3311 | nsnum_to_rb_neg(VALUE num) |
| | 3312 | { |
| | 3313 | VALUE num_class = nsnum_class(num); |
| | 3314 | if (num_class==rb_cFloat) return DOUBLE2NUM(-(nsnum_cdouble(num))); |
| | 3315 | if (num_class==rb_cFixnum) return LL2NUM(-(nsnum_cLL(num))); |
| | 3316 | nsnum_fail_coerce(num); |
| | 3317 | return Qnil; |
| | 3318 | } |
| | 3319 | |
| | 3320 | static VALUE |
| | 3321 | nsnum_cmp(VALUE l, VALUE r) |
| | 3322 | { |
| | 3323 | if (!do_coerce(&l, &r, Qtrue)) return Qnil; |
| | 3324 | return rb_funcall(l, id_spaceship, 1, r); |
| | 3325 | } |
| | 3326 | |
| | 3327 | static VALUE |
| | 3328 | nsnum_eq(VALUE l, VALUE r) |
| | 3329 | { |
| | 3330 | if (!do_coerce(&l, &r, Qtrue)) return Qnil; |
| | 3331 | return rb_funcall(l, id_eq, 1, r); |
| | 3332 | } |
| | 3333 | |
| | 3334 | static VALUE |
| | 3335 | nsnum_coerce(VALUE num, VALUE b) |
| | 3336 | { |
| | 3337 | return num_coerce(nsnum_to_rb_force(num),b); |
| | 3338 | } |
| | 3339 | |
| | 3340 | static VALUE |
| | 3341 | nsnum_init_copy(VALUE x) |
| | 3342 | { |
| | 3343 | /* Numerics are immutable values, which should not be copied */ |
| | 3344 | rb_raise(rb_eTypeError, "can't copy %s",rb_class2name(nsnum_class(x))); |
| | 3345 | return Qnil; /* not reached */ |
| | 3346 | } |
| | 3347 | |
| | 3348 | static VALUE |
| | 3349 | nsnum_dup(VALUE x) |
| | 3350 | { |
| | 3351 | /* Numerics are immutable values, which should not be copied */ |
| | 3352 | rb_raise(rb_eTypeError, "can't dup %s", rb_class2name(nsnum_class(x))); |
| | 3353 | return Qnil; /* not reached */ |
| | 3354 | } |
| | 3355 | |
| | 3356 | /*static VALUE |
| | 3357 | nsnum_missing(int argc, VALUE* argv, VALUE self) |
| | 3358 | { |
| | 3359 | VALUE rb_self = nsnum_to_rb(self); |
| | 3360 | rb_p(rb_self); |
| | 3361 | static ID to_s = Qnil; |
| | 3362 | if (to_s==Qnil) to_s = rb_intern("to_s"); |
| | 3363 | printf("to_s: %s\n", rb_id2name(to_s)); |
| | 3364 | VALUE sel_name = rb_funcall(argv[0], to_s, 0); |
| | 3365 | rb_p(sel_name); |
| | 3366 | ID sel = rb_to_id(sel_name); |
| | 3367 | printf("sel: %s\n", rb_id2name(sel)); |
| | 3368 | if (rb_respond_to(rb_self, sel)) { |
| | 3369 | return rb_self;//rb_funcall2(rb_self, sel, argc-1, argv+1); |
| | 3370 | } else { |
| | 3371 | rb_raise(rb_eNoMethodError, "undefined method `%s' for %s", rb_id2name(sel), rb_obj_classname(rb_self)); |
| | 3372 | } |
| | 3373 | return Qnil; |
| | 3374 | }*/ |
| | 3375 | |
| | 3376 | static VALUE |
| | 3377 | nsnum_quo(VALUE a, VALUE b) |
| | 3378 | { |
| | 3379 | static ID sel = 0; |
| | 3380 | if (!sel) sel = rb_intern("quo"); |
| | 3381 | do_coerce(&a,&b,Qtrue); |
| | 3382 | return rb_funcall(a, sel, 1, b); |
| | 3383 | } |
| | 3384 | |
| | 3385 | static VALUE |
| | 3386 | nsnum_fdiv(VALUE a, VALUE b) |
| | 3387 | { |
| | 3388 | static ID sel = 0; |
| | 3389 | if (!sel) sel = rb_intern("fdiv"); |
| | 3390 | do_coerce(&a,&b,Qtrue); |
| | 3391 | return rb_funcall(a, sel, 1, b); |
| | 3392 | } |
| | 3393 | |
| | 3394 | static VALUE |
| | 3395 | nsnum_divmod(VALUE a, VALUE b) |
| | 3396 | { |
| | 3397 | static ID sel = 0; |
| | 3398 | if (!sel) sel = rb_intern("divmod"); |
| | 3399 | do_coerce(&a,&b,Qtrue); |
| | 3400 | return rb_funcall(a, sel, 1, b); |
| | 3401 | } |
| | 3402 | |
| | 3403 | static VALUE |
| | 3404 | nsnum_modulo(VALUE a, VALUE b) |
| | 3405 | { |
| | 3406 | static ID sel = 0; |
| | 3407 | if (!sel) sel = rb_intern("modulo"); |
| | 3408 | do_coerce(&a,&b,Qtrue); |
| | 3409 | return rb_funcall(a, sel, 1, b); |
| | 3410 | } |
| | 3411 | |
| | 3412 | static VALUE |
| | 3413 | nsnum_remainder(VALUE a, VALUE b) |
| | 3414 | { |
| | 3415 | static ID sel = 0; |
| | 3416 | if (!sel) sel = rb_intern("remainder"); |
| | 3417 | do_coerce(&a,&b,Qtrue); |
| | 3418 | return rb_funcall(a, sel, 1, b); |
| | 3419 | } |
| | 3420 | |
| | 3421 | static VALUE |
| | 3422 | nsnum_true(VALUE a) |
| | 3423 | { |
| | 3424 | return Qtrue; |
| | 3425 | } |
| | 3426 | |
| | 3427 | static VALUE |
| | 3428 | nsnum_integer_p(VALUE a) |
| | 3429 | { |
| | 3430 | VALUE num_class = nsnum_class(a); |
| | 3431 | if (num_class==rb_cFloat) return Qfalse; |
| | 3432 | if (num_class==rb_cFixnum) return Qtrue; |
| | 3433 | nsnum_fail_coerce(a); |
| | 3434 | return Qnil; |
| | 3435 | } |
| | 3436 | |
| | 3437 | static VALUE |
| | 3438 | nsnum_zero_p(VALUE num) |
| | 3439 | { |
| | 3440 | VALUE num_class = nsnum_class(num); |
| | 3441 | if (num_class==rb_cFloat) return nsnum_cdouble(num)==0; |
| | 3442 | if (num_class==rb_cFixnum) return nsnum_cLL(num)==0; |
| | 3443 | nsnum_fail_coerce(num); |
| | 3444 | return Qnil; |
| | 3445 | } |
| | 3446 | |
| | 3447 | static VALUE |
| | 3448 | nsnum_nonzero_p(VALUE num) |
| | 3449 | { |
| | 3450 | VALUE num_class = nsnum_class(num); |
| | 3451 | if (num_class==rb_cFloat) return nsnum_cdouble(num)!=0; |
| | 3452 | if (num_class==rb_cFixnum) return nsnum_cLL(num)!=0; |
| | 3453 | nsnum_fail_coerce(num); |
| | 3454 | return Qnil; |
| | 3455 | } |
| | 3456 | |
| | 3457 | static VALUE |
| | 3458 | nsnum_floor(VALUE num) |
| | 3459 | { |
| | 3460 | VALUE num_class = nsnum_class(num); |
| | 3461 | if (num_class==rb_cFixnum) return num; |
| | 3462 | |
| | 3463 | if (num_class!=rb_cFloat) { |
| | 3464 | nsnum_fail_coerce(num); |
| | 3465 | return Qnil; |
| | 3466 | } |
| | 3467 | double v = floor(nsnum_cdouble(num)); |
| | 3468 | if (!FIXABLE(v)) return rb_dbl2big(v); |
| | 3469 | return LL2NUM((long long)v); |
| | 3470 | } |
| | 3471 | |
| | 3472 | static VALUE |
| | 3473 | nsnum_ceil(VALUE num) |
| | 3474 | { |
| | 3475 | VALUE num_class = nsnum_class(num); |
| | 3476 | if (num_class==rb_cFixnum) return num; |
| | 3477 | |
| | 3478 | if (num_class!=rb_cFloat) { |
| | 3479 | nsnum_fail_coerce(num); |
| | 3480 | return Qnil; |
| | 3481 | } |
| | 3482 | double v = ceil(nsnum_cdouble(num)); |
| | 3483 | if (!FIXABLE(v)) return rb_dbl2big(v); |
| | 3484 | return LL2NUM((long long)v); |
| | 3485 | } |
| | 3486 | |
| | 3487 | static VALUE |
| | 3488 | nsnum_round(int argc, VALUE* argv, VALUE self) |
| | 3489 | { |
| | 3490 | VALUE num_class = nsnum_class(self); |
| | 3491 | if (num_class==rb_cFloat) return flo_round(argc, argv, DOUBLE2NUM(nsnum_cdouble(self))); |
| | 3492 | if (num_class==rb_cFixnum) return int_round(argc, argv, LL2NUM(nsnum_cLL(self))); |
| | 3493 | nsnum_fail_coerce(self); |
| | 3494 | return Qnil; |
| | 3495 | } |
| | 3496 | |
| | 3497 | static VALUE |
| | 3498 | nsnum_truncate(VALUE self) |
| | 3499 | { |
| | 3500 | VALUE num_class = nsnum_class(self); |
| | 3501 | if (num_class==rb_cFloat) return LL2NUM(nsnum_cdouble(self)); |
| | 3502 | if (num_class==rb_cFixnum) return self; |
| | 3503 | nsnum_fail_coerce(self); |
| | 3504 | return Qnil; |
| | 3505 | } |
| | 3506 | |
| | 3507 | static VALUE |
| | 3508 | nsnum_step(int argc, VALUE* argv, VALUE self) |
| | 3509 | { |
| | 3510 | VALUE num_class = nsnum_class(self); |
| | 3511 | if (num_class==rb_cFloat) return num_step(argc, argv, DOUBLE2NUM(nsnum_cdouble(self))); |
| | 3512 | if (num_class==rb_cFixnum) return num_step(argc, argv, LL2NUM(nsnum_cLL(self))); |
| | 3513 | nsnum_fail_coerce(self); |
| | 3514 | return Qnil; |
| | 3515 | } |
| | 3516 | |
| | 3517 | static VALUE |
| | 3518 | nsnum_numerator(VALUE a) |
| | 3519 | { |
| | 3520 | VALUE num_class = nsnum_class(a); |
| | 3521 | if (num_class==rb_cFloat) return num_numerator(DOUBLE2NUM(nsnum_cdouble(a))); |
| | 3522 | if (num_class==rb_cFixnum) return LL2NUM(nsnum_cLL(a)); |
| | 3523 | nsnum_fail_coerce(a); |
| | 3524 | return Qnil; |
| | 3525 | } |
| | 3526 | |
| | 3527 | static VALUE |
| | 3528 | nsnum_denominator(VALUE a) |
| | 3529 | { |
| | 3530 | VALUE num_class = nsnum_class(a); |
| | 3531 | if (num_class==rb_cFloat) return num_denominator(DOUBLE2NUM(nsnum_cdouble(a))); |
| | 3532 | if (num_class==rb_cFixnum) return LONG2FIX(1); |
| | 3533 | nsnum_fail_coerce(a); |
| | 3534 | return Qnil; |
| | 3535 | } |
| | 3536 | |
| | 3537 | static VALUE |
| | 3538 | nsnum_even_p(VALUE a) |
| | 3539 | { |
| | 3540 | VALUE num_class = nsnum_class(a); |
| | 3541 | if (num_class==rb_cFloat) //TODO: it will still respond_to the method even if it shouldn't |
| | 3542 | rb_raise(rb_eNoMethodError, "undefined method `even?' for %s", rb_obj_classname(a)); |
| | 3543 | if (num_class==rb_cFixnum) return (nsnum_cLL(a)&1)?Qfalse:Qtrue; |
| | 3544 | return Qnil; |
| | 3545 | } |
| | 3546 | |
| | 3547 | static VALUE |
| | 3548 | nsnum_odd_p(VALUE a) |
| | 3549 | { |
| | 3550 | VALUE num_class = nsnum_class(a); |
| | 3551 | if (num_class==rb_cFloat) //TODO: it will still respond_to the method even if it shouldn't |
| | 3552 | rb_raise(rb_eNoMethodError, "undefined method `odd?' for %s", rb_obj_classname(a)); |
| | 3553 | if (num_class==rb_cFixnum) return (nsnum_cLL(a)&1)?Qtrue:Qfalse; |
| | 3554 | return Qnil; |
| | 3555 | } |
| | 3556 | |
| | 3557 | static VALUE |
| | 3558 | nsnum_upto(VALUE a, VALUE b) |
| | 3559 | { |
| | 3560 | if (FIXNUM_P(b)) { |
| | 3561 | long i = nsnum_cLL(a); |
| | 3562 | long j = FIX2LONG(b); |
| | 3563 | while (i<=j) { |
| | 3564 | rb_yield(LONG2FIX(i)); |
| | 3565 | i++; |
| | 3566 | } |
| | 3567 | return a; |
| | 3568 | } |
| | 3569 | VALUE i = a; |
| | 3570 | VALUE c; |
| | 3571 | while (1) { |
| | 3572 | c = rb_funcall(i, '>', 1, b); |
| | 3573 | if (c==Qnil || c==Qtrue) break; |
| | 3574 | rb_yield(i); |
| | 3575 | i = rb_funcall(i, '+', 1, INT2FIX(1)); |
| | 3576 | } |
| | 3577 | if (NIL_P(c)) rb_cmperr(i, b); |
| | 3578 | return a; |
| | 3579 | } |
| | 3580 | |
| | 3581 | static VALUE |
| | 3582 | nsnum_downto(VALUE a, VALUE b) |
| | 3583 | { |
| | 3584 | long long i = nsnum_cLL(a); |
| | 3585 | if (FIXNUM_P(b) && FIXABLE(i)) { |
| | 3586 | long j = FIX2LONG(b); |
| | 3587 | while (i>=j) { |
| | 3588 | rb_yield(LONG2FIX(i)); |
| | 3589 | i--; |
| | 3590 | } |
| | 3591 | return a; |
| | 3592 | } |
| | 3593 | VALUE ii = a; |
| | 3594 | VALUE c; |
| | 3595 | while (1) { |
| | 3596 | c = rb_funcall(ii, '<', 1, b); |
| | 3597 | if (c==Qnil || c==Qtrue) break; |
| | 3598 | rb_yield(ii); |
| | 3599 | ii = rb_funcall(ii, '-', 1, INT2FIX(1)); |
| | 3600 | } |
| | 3601 | if (NIL_P(c)) rb_cmperr(ii, b); |
| | 3602 | return a; |
| | 3603 | } |
| | 3604 | |
| | 3605 | static VALUE |
| | 3606 | nsnum_dotimes(VALUE a) |
| | 3607 | { |
| | 3608 | long long j = nsnum_cLL(a); |
| | 3609 | long long i = 0; |
| | 3610 | for (; i<j; i++) rb_yield(LL2NUM(i)); |
| | 3611 | return a; |
| | 3612 | } |
| | 3613 | |
| | 3614 | static VALUE |
| | 3615 | nsnum_succ(VALUE a) |
| | 3616 | { |
| | 3617 | long long j = nsnum_cLL(a); |
| | 3618 | if (j+1<j) { |
| | 3619 | VALUE r = LL2NUM(j); |
| | 3620 | return rb_funcall(r, '+', 1, INT2FIX(1)); |
| | 3621 | } |
| | 3622 | return LL2NUM(j+1); |
| | 3623 | } |
| | 3624 | |
| | 3625 | static VALUE |
| | 3626 | nsnum_pred(VALUE a) |
| | 3627 | { |
| | 3628 | long long j = nsnum_cLL(a); |
| | 3629 | if (j-1>j) { |
| | 3630 | VALUE r = LL2NUM(j); |
| | 3631 | return rb_funcall(r, '-', 1, INT2FIX(1)); |
| | 3632 | } |
| | 3633 | return LL2NUM(j-1); |
| | 3634 | } |
| | 3635 | |
| | 3636 | static VALUE |
| | 3637 | nsnum_nan_p(VALUE a) |
| | 3638 | { |
| | 3639 | VALUE num_class = nsnum_class(a); |
| | 3640 | if (num_class==rb_cFloat) return isnan(nsnum_cdouble(a))?Qtrue:Qfalse; |
| | 3641 | if (num_class==rb_cFixnum) //TODO: it will still respond_to the method even if it shouldn't |
| | 3642 | rb_raise(rb_eNoMethodError, "undefined method `is_nan?' for %s", rb_obj_classname(a)); |
| | 3643 | nsnum_fail_coerce(a); |
| | 3644 | return Qnil; |
| | 3645 | } |
| | 3646 | |
| | 3647 | static VALUE |
| | 3648 | nsnum_inf_p(VALUE a) |
| | 3649 | { |
| | 3650 | VALUE num_class = nsnum_class(a); |
| | 3651 | if (num_class==rb_cFloat) return isinf(nsnum_cdouble(a))?Qtrue:Qfalse; |
| | 3652 | if (num_class==rb_cFixnum) //TODO: it will still respond_to the method even if it shouldn't |
| | 3653 | rb_raise(rb_eNoMethodError, "undefined method `is_nan?' for %s", rb_obj_classname(a)); |
| | 3654 | nsnum_fail_coerce(a); |
| | 3655 | return Qnil; |
| | 3656 | } |
| | 3657 | |
| | 3658 | static VALUE |
| | 3659 | nsnum_notinf_p(VALUE a) |
| | 3660 | { |
| | 3661 | VALUE num_class = nsnum_class(a); |
| | 3662 | if (num_class==rb_cFloat) return isinf(nsnum_cdouble(a))?Qfalse:Qtrue; |
| | 3663 | if (num_class==rb_cFixnum) //TODO: it will still respond_to the method even if it shouldn't |
| | 3664 | rb_raise(rb_eNoMethodError, "undefined method `is_nan?' for %s", rb_obj_classname(a)); |
| | 3665 | nsnum_fail_coerce(a); |
| | 3666 | return Qnil; |
| | 3667 | } |
| | 3668 | |
| | 3669 | static VALUE |
| | 3670 | nsnum_pow(VALUE a, VALUE b) |
| | 3671 | { |
| | 3672 | VALUE num_class = nsnum_class(a); |
| | 3673 | b = nsnum_to_rb_force(b); |
| | 3674 | if (num_class==rb_cFloat) return flo_pow(DOUBLE2NUM(nsnum_cdouble(a)), b); |
| | 3675 | if (num_class==rb_cFixnum) return fix_pow(LL2NUM(nsnum_cLL(a)), b); |
| | 3676 | nsnum_fail_coerce(a); |
| | 3677 | return Qnil; |
| | 3678 | } |
| | 3679 | |
| | 3680 | static VALUE |
| | 3681 | nsnum_plus(VALUE a, VALUE b) |
| | 3682 | { |
| | 3683 | VALUE num_class = nsnum_class(a); |
| | 3684 | b = nsnum_to_rb_force(b); |
| | 3685 | if (num_class==rb_cFloat) return flo_plus(DOUBLE2NUM(nsnum_cdouble(a)), b); |
| | 3686 | if (num_class==rb_cFixnum) return fix_plus(LL2NUM(nsnum_cLL(a)), b); |
| | 3687 | nsnum_fail_coerce(a); |
| | 3688 | return Qnil; |
| | 3689 | } |
| | 3690 | |
| | 3691 | static VALUE |
| | 3692 | nsnum_minus(VALUE a, VALUE b) |
| | 3693 | { |
| | 3694 | VALUE num_class = nsnum_class(a); |
| | 3695 | b = nsnum_to_rb_force(b); |
| | 3696 | if (num_class==rb_cFloat) return flo_minus(DOUBLE2NUM(nsnum_cdouble(a)), b); |
| | 3697 | if (num_class==rb_cFixnum) return fix_minus(LL2NUM(nsnum_cLL(a)), b); |
| | 3698 | nsnum_fail_coerce(a); |
| | 3699 | return Qnil; |
| | 3700 | } |
| | 3701 | |
| | 3702 | static VALUE |
| | 3703 | nsnum_times(VALUE a, VALUE b) |
| | 3704 | { |
| | 3705 | VALUE num_class = nsnum_class(a); |
| | 3706 | b = nsnum_to_rb_force(b); |
| | 3707 | if (num_class==rb_cFloat) return flo_mul(DOUBLE2NUM(nsnum_cdouble(a)), b); |
| | 3708 | if (num_class==rb_cFixnum) return fix_mul(LL2NUM(nsnum_cLL(a)), b); |
| | 3709 | nsnum_fail_coerce(a); |
| | 3710 | return Qnil; |
| | 3711 | } |
| | 3712 | |
| | 3713 | static VALUE |
| | 3714 | nsnum_div(VALUE a, VALUE b) |
| | 3715 | { |
| | 3716 | VALUE num_class = nsnum_class(a); |
| | 3717 | b = nsnum_to_rb_force(b); |
| | 3718 | if (num_class==rb_cFloat) return flo_div(DOUBLE2NUM(nsnum_cdouble(a)), b); |
| | 3719 | if (num_class==rb_cFixnum) return fix_div(LL2NUM(nsnum_cLL(a)), b); |
| | 3720 | nsnum_fail_coerce(a); |
| | 3721 | return Qnil; |
| | 3722 | } |
| | 3723 | |
| | 3724 | static VALUE |
| | 3725 | nsnum_rev(VALUE a) |
| | 3726 | { |
| | 3727 | return LONG2FIX(~FIX2LONG(a)); |
| | 3728 | } |
| | 3729 | |
| | 3730 | static VALUE |
| | 3731 | nsnum_and(VALUE a, VALUE b) |
| | 3732 | { |
| | 3733 | b = bit_coerce(nsnum_to_rb_force(b)); |
| | 3734 | if (!FIXNUM_P(b)) { |
| | 3735 | return rb_big_and(nsnum_to_rb_force(a), b); |
| | 3736 | } |
| | 3737 | return LONG2NUM(nsnum_cLL(a) & FIX2LONG(b)); |
| | 3738 | } |
| | 3739 | |
| | 3740 | static VALUE |
| | 3741 | nsnum_or(VALUE a, VALUE b) |
| | 3742 | { |
| | 3743 | b = bit_coerce(nsnum_to_rb_force(b)); |
| | 3744 | if (!FIXNUM_P(b)) { |
| | 3745 | return rb_big_or(nsnum_to_rb_force(a), b); |
| | 3746 | } |
| | 3747 | return LONG2NUM(nsnum_cLL(a) | FIX2LONG(b)); |
| | 3748 | } |
| | 3749 | |
| | 3750 | static VALUE |
| | 3751 | nsnum_xor(VALUE a, VALUE b) |
| | 3752 | { |
| | 3753 | b = bit_coerce(nsnum_to_rb_force(b)); |
| | 3754 | if (!FIXNUM_P(b)) { |
| | 3755 | return rb_big_xor(nsnum_to_rb_force(a), b); |
| | 3756 | } |
| | 3757 | return LONG2NUM(nsnum_cLL(a) ^ FIX2LONG(b)); |
| | 3758 | } |
| | 3759 | |
| | 3760 | static VALUE |
| | 3761 | nsnum_aref(VALUE l, VALUE idx) |
| | 3762 | { |
| | 3763 | long long v = nsnum_cLL(l); |
| | 3764 | idx = rb_to_int(idx); |
| | 3765 | if (!FIXNUM_P(idx)) { |
| | 3766 | idx = rb_big_norm(idx); |
| | 3767 | if (!FIXNUM_P(idx)) { |
| | 3768 | if (!RBIGNUM_SIGN(idx) || v >= 0) |
| | 3769 | return INT2FIX(0); |
| | 3770 | return INT2FIX(1); |
| | 3771 | } |
| | 3772 | } |
| | 3773 | long i = FIX2LONG(idx); |
| | 3774 | if (i<0) return INT2FIX(0); |
| | 3775 | if (SIZEOF_LONG*CHAR_BIT-1 < i) { |
| | 3776 | if (v < 0) return INT2FIX(1); |
| | 3777 | return INT2FIX(0); |
| | 3778 | } |
| | 3779 | if (v & (1L<<i)) |
| | 3780 | return INT2FIX(1); |
| | 3781 | return INT2FIX(0); |
| | 3782 | } |
| | 3783 | |
| | 3784 | static VALUE |
| | 3785 | nsnum_shl(VALUE v, VALUE amt) |
| | 3786 | { |
| | 3787 | VALUE num_class = nsnum_class(v); |
| | 3788 | if (num_class==rb_cFloat) |
| | 3789 | rb_raise(rb_eNoMethodError, "undefined method `<<' for %s", rb_obj_classname(v)); |
| | 3790 | return rb_funcall(nsnum_to_rb_force(v), id_shl, 1, nsnum_to_rb_force(amt)); |
| | 3791 | } |
| | 3792 | |
| | 3793 | static VALUE |
| | 3794 | nsnum_shr(VALUE v, VALUE amt) |
| | 3795 | { |
| | 3796 | VALUE num_class = nsnum_class(v); |
| | 3797 | if (num_class==rb_cFloat) |
| | 3798 | rb_raise(rb_eNoMethodError, "undefined method `>>' for %s", rb_obj_classname(v)); |
| | 3799 | return rb_funcall(nsnum_to_rb_force(v), id_shr, 1, nsnum_to_rb_force(amt)); |
| | 3800 | } |
| | 3801 | |
| | 3802 | |
| | 3803 | static void |
| | 3804 | rb_install_nsnumber_methods() { |
| | 3805 | id_spaceship = rb_intern("<=>"); |
| | 3806 | id_shl = rb_intern("<<"); |
| | 3807 | id_shr = rb_intern(">>"); |
| | 3808 | id_pow = rb_intern("**"); |
| | 3809 | rb_cNSNumber = (VALUE)objc_getClass("NSNumber"); |
| | 3810 | rb_define_method(rb_cNSNumber, "to_i", nsnum_to_i,0); |
| | 3811 | rb_define_method(rb_cNSNumber, "to_f", nsnum_to_f,0); |
| | 3812 | rb_define_method(rb_cNSNumber, "to_rb", nsnum_to_rb,0); |
| | 3813 | |
| | 3814 | //rb_define_method(rb_cNSNumber, "class", nsnum_class,0); |
| | 3815 | rb_define_method(rb_cNSNumber, "dup", nsnum_dup,0); |
| | 3816 | rb_define_method(rb_cNSNumber, "initialize_copy", nsnum_init_copy,0); |
| | 3817 | rb_define_method(rb_cNSNumber, "coerce", nsnum_coerce, 1); |
| | 3818 | |
| | 3819 | rb_define_method(rb_cNSNumber, "+@", nsnum_to_rb, 0); |
| | 3820 | rb_define_method(rb_cNSNumber, "-@", nsnum_to_rb_neg, 0); |
| | 3821 | rb_define_method(rb_cNSNumber, "<=>", nsnum_cmp, 1); |
| | 3822 | rb_define_method(rb_cNSNumber, "eql?", nsnum_eq, 1); |
| | 3823 | rb_define_method(rb_cNSNumber, "quo", nsnum_quo, 1); |
| | 3824 | rb_define_method(rb_cNSNumber, "fdiv", nsnum_fdiv, 1); |
| | 3825 | rb_define_method(rb_cNSNumber, "div", nsnum_div, 1); |
| | 3826 | rb_define_method(rb_cNSNumber, "divmod", nsnum_divmod, 1); |
| | 3827 | rb_define_method(rb_cNSNumber, "modulo", nsnum_modulo, 1); |
| | 3828 | rb_define_method(rb_cNSNumber, "%", nsnum_modulo, 1); |
| | 3829 | rb_define_method(rb_cNSNumber, "remainder", nsnum_remainder, 1); |
| | 3830 | rb_define_method(rb_cNSNumber, "abs", nsnum_to_rb_abs, 0); |
| | 3831 | rb_define_method(rb_cNSNumber, "to_int", nsnum_to_i, 0); |
| | 3832 | |
| | 3833 | rb_define_method(rb_cNSNumber, "scalar?", nsnum_true, 0); |
| | 3834 | rb_define_method(rb_cNSNumber, "integer?", nsnum_integer_p, 0); |
| | 3835 | rb_define_method(rb_cNSNumber, "zero?", nsnum_zero_p, 0); |
| | 3836 | rb_define_method(rb_cNSNumber, "nonzero?", nsnum_nonzero_p, 0); |
| | 3837 | |
| | 3838 | rb_define_method(rb_cNSNumber, "floor", nsnum_floor, 0); |
| | 3839 | rb_define_method(rb_cNSNumber, "ceil", nsnum_ceil, 0); |
| | 3840 | rb_define_method(rb_cNSNumber, "round", nsnum_round, -1); |
| | 3841 | rb_define_method(rb_cNSNumber, "truncate", nsnum_truncate, 0); |
| | 3842 | rb_define_method(rb_cNSNumber, "step", nsnum_step, -1); |
| | 3843 | |
| | 3844 | rb_define_method(rb_cNSNumber, "numerator", nsnum_numerator, 0); |
| | 3845 | rb_define_method(rb_cNSNumber, "denominator", nsnum_denominator, 0); |
| | 3846 | |
| | 3847 | rb_define_method(rb_cNSNumber, "odd?", nsnum_odd_p, 0); |
| | 3848 | rb_define_method(rb_cNSNumber, "even?", nsnum_even_p, 0); |
| | 3849 | |
| | 3850 | rb_define_method(rb_cNSNumber, "upto", nsnum_upto, 1); |
| | 3851 | rb_define_method(rb_cNSNumber, "downto", nsnum_downto, 1); |
| | 3852 | rb_define_method(rb_cNSNumber, "times", nsnum_dotimes, 0); |
| | 3853 | |
| | 3854 | rb_define_method(rb_cNSNumber, "succ", nsnum_succ, 0); |
| | 3855 | rb_define_method(rb_cNSNumber, "next", nsnum_succ, 0); |
| | 3856 | rb_define_method(rb_cNSNumber, "pred", nsnum_pred, 0); |
| | 3857 | |
| | 3858 | rb_define_method(rb_cNSNumber, "nan?", nsnum_nan_p, 0); |
| | 3859 | rb_define_method(rb_cNSNumber, "infinite?", nsnum_inf_p, 0); |
| | 3860 | rb_define_method(rb_cNSNumber, "finite?", nsnum_notinf_p, 0); |
| | 3861 | |
| | 3862 | rb_define_method(rb_cNSNumber, "**", nsnum_pow, 1); |
| | 3863 | rb_define_method(rb_cNSNumber, "+", nsnum_plus, 1); |
| | 3864 | rb_define_method(rb_cNSNumber, "-", nsnum_minus, 1); |
| | 3865 | rb_define_method(rb_cNSNumber, "*", nsnum_times, 1); |
| | 3866 | rb_define_method(rb_cNSNumber, "/", nsnum_div, 1); |
| | 3867 | |
| | 3868 | rb_define_method(rb_cNSNumber, "~", nsnum_rev, 0); |
| | 3869 | rb_define_method(rb_cNSNumber, "&", nsnum_and, 1); |
| | 3870 | rb_define_method(rb_cNSNumber, "|", nsnum_or, 1); |
| | 3871 | rb_define_method(rb_cNSNumber, "^", nsnum_xor, 1); |
| | 3872 | rb_define_method(rb_cNSNumber, "[]", nsnum_aref, 1); |
| | 3873 | rb_define_method(rb_cNSNumber, "<<", nsnum_shl, 1); |
| | 3874 | rb_define_method(rb_cNSNumber, ">>", nsnum_shr, 1); |
| | 3875 | |
| | 3876 | |
| | 3877 | //rb_define_method(rb_cNSNumber, "method_missing", nsnum_missing, -1); |
| | 3878 | rb_include_module(rb_cNSNumber, rb_mComparable); |
| | 3879 | } |
| | 3880 | #endif /*WITH_OBJC*/ |
| | 3881 | /**********************************************************************************/ |
| | 3882 | |