/*
Copyright (C) 2003-2010, Parrot Foundation.
=head1 NAME
src/pmc/integer.pmc - Integer PMC class
=head1 DESCRIPTION
C<Integer> provides an integer for languages that want a value-restricted
integer type without going to an I register.
=head2 Functions
=over 4
=cut
*/
#include "pmc/pmc_bigint.h"
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
static void maybe_throw_overflow_error(PARROT_INTERP)
__attribute__nonnull__(1);
PARROT_IGNORABLE_RESULT
PARROT_CANNOT_RETURN_NULL
static PMC* upgrade_self_to_bignum(PARROT_INTERP, ARGMOD(PMC *self))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
FUNC_MODIFIES(*self);
#define ASSERT_ARGS_maybe_throw_overflow_error __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_upgrade_self_to_bignum __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(self))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
=item C<static void maybe_throw_overflow_error(PARROT_INTERP)>
Checks to see if the interpreter is set to throw an exception on overflow.
If so, throw the exception, otherwise ignore.
=cut
*/
static void
maybe_throw_overflow_error(PARROT_INTERP)
{
ASSERT_ARGS(maybe_throw_overflow_error)
/* check to see what the behavior is. If the interpreter is set
to throw an exception on overflow. If so, throw the exception,
otherwise, chill out it's no big deal. */
if (PARROT_ERRORS_test(interp, PARROT_ERRORS_OVERFLOW_FLAG))
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_ERR_OVERFLOW,
"Integer overflow");
}
/*
=item C<static PMC* upgrade_self_to_bignum(PARROT_INTERP, PMC *self)>
Returns a pointer of *self upgraded to a bignum
=cut
*/
PARROT_IGNORABLE_RESULT
PARROT_CANNOT_RETURN_NULL
static PMC*
upgrade_self_to_bignum(PARROT_INTERP, ARGMOD(PMC *self))
{
ASSERT_ARGS(upgrade_self_to_bignum)
/* Do an in-place upgrade to a Bignum of SELF and return a pointer
to it (which is probably redundant, but whatever). */
const INTVAL a = VTABLE_get_integer(interp, self);
Parrot_pmc_reuse(interp, self, enum_class_BigInt, 0);
VTABLE_set_integer_native(interp, self, a);
return self;
}
pmclass Integer extends scalar provides integer provides scalar auto_attrs {
ATTR INTVAL iv; /* the value of this Integer */
/*
=item C<PMC init_pmc(PMC *init)>
Create a new Integer with arguments passed according to pdd03.
=item C<void init()>
Initializes the integer with a default value of C<0>.
=cut
*/
VTABLE void init() {
Parrot_Integer_attributes * const attrs =
(Parrot_Integer_attributes *)PMC_data(SELF);
attrs->iv = 0;
}
VTABLE void init_pmc(PMC *init) {
Parrot_Integer_attributes * const attrs =
(Parrot_Integer_attributes *)PMC_data(SELF);
attrs->iv = VTABLE_get_integer(INTERP, init);
}
VTABLE void init_int(INTVAL init) {
Parrot_Integer_attributes * const attrs =
(Parrot_Integer_attributes *)PMC_data(SELF);
attrs->iv = init;
}
/*
=item C<PMC *clone()>
Creates an exact duplicate of this PMC.
=cut
*/
VTABLE PMC *clone() {
return Parrot_pmc_new_init_int(INTERP, SELF->vtable->base_type,
SELF.get_integer());
}
/*
=item C<void set_pmc(PMC *value)>
Sets the value of the integer to the value in C<*value>.
=cut
*/
VTABLE void set_pmc(PMC *value) {
SELF.set_integer_native(VTABLE_get_integer(INTERP, value));
}
/*
=item C<void share()>
Sets this PMC as shared and read-only.
=cut
*/
VTABLE void share() {
/*
* assume that the access to a long is atomic.
* integers are most often (1) equal to C longs,
* not C ints, and this makes a difference in 64-bit
* platforms where longs are 64-bit but ints are 32-bit.
* (1) Not equal when integers have been configured
* to be software-emulated long longs.
*/
if (sizeof (INTVAL) != sizeof (long))
SUPER();
}
/*
=item C<INTVAL get_integer()>
Returns the integer value of the Integer.
=cut
*/
VTABLE INTVAL get_integer() {
INTVAL iv;
GET_ATTR_iv(INTERP, SELF, iv);
return iv;
}
/*
=item C<INTVAL get_bool()>
Returns the boolean value of the Integer.
=cut
*/
VTABLE INTVAL get_bool() {
INTVAL iv;
GET_ATTR_iv(INTERP, SELF, iv);
return iv ? 1 : 0;
}
/*
=item C<FLOATVAL get_number()>
Returns the floating-point value of the integer.
=cut
*/
VTABLE FLOATVAL get_number() {
INTVAL iv;
GET_ATTR_iv(INTERP, SELF, iv);
return (FLOATVAL)iv;
}
/*
=item C<STRING *get_string()>
=item C<STRING *get_repr()>
Returns the string value of the integer.
=cut
*/
VTABLE STRING *get_string() {
return Parrot_str_from_int(INTERP, SELF.get_integer());
}
VTABLE STRING *get_repr() {
return Parrot_str_from_int(INTERP, SELF.get_integer());
}
/*
=item C<void set_integer_native(INTVAL value)>
Sets the value of the integer to the value of the native integer C<*value>.
=cut
*/
VTABLE void set_integer_native(INTVAL value) {
SET_ATTR_iv(INTERP, SELF, value);
}
/*
=item C<void set_number_native(FLOATVAL value)>
Morphs the integer to a C<Float> and sets the value from C<value>.
=item C<void set_bool(INTVAL value)>
Morphs the integer to a C<Boolean> and sets the value from C<value>.
=item C<void set_string_native(STRING *value)>
Morphs the integer to a C<String> and sets the value from C<value>.
=cut
*/
VTABLE void set_number_native(FLOATVAL value) {
Parrot_pmc_reuse(INTERP, SELF,
Parrot_hll_get_ctx_HLL_type(INTERP, enum_class_Float), 0);
SELF.set_number_native(value);
}
VTABLE void set_bool(INTVAL value) {
Parrot_pmc_reuse(INTERP, SELF,
Parrot_hll_get_ctx_HLL_type(INTERP, enum_class_Boolean), 0);
SELF.set_bool(value);
}
VTABLE void set_string_native(STRING *value) {
Parrot_pmc_reuse(INTERP, SELF,
Parrot_hll_get_ctx_HLL_type(INTERP, enum_class_String), 0);
SELF.set_string_native(value);
}
/*
=item C<PMC *add(PMC *value, PMC *dest)>
=item C<PMC *add_int(INTVAL value, PMC *dest)>
Adds C<value> to the integer and returns the result in C<*dest>.
=cut
*/
MULTI PMC *add(Integer value, PMC *dest) {
const INTVAL a = SELF.get_integer();
const INTVAL b = VTABLE_get_integer(INTERP, value);
const INTVAL c = a + b;
if ((c^a) >= 0 || (c^b) >= 0)
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), c);
else {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, a);
return VTABLE_add(INTERP, temp, value, dest);
}
}
MULTI PMC *add(Complex value, PMC *dest) {
const INTVAL a = SELF.get_integer();
dest = Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, value),
a + VTABLE_get_number_keyed_int(INTERP, value, 0));
VTABLE_set_number_keyed_int(INTERP, dest, 1,
VTABLE_get_number_keyed_int(INTERP, value, 1));
return dest;
}
MULTI PMC *add(BigInt value, PMC *dest) {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt,
SELF.get_integer());
return VTABLE_add(INTERP, temp, value, dest);
}
MULTI PMC *add(DEFAULT value, PMC *dest) {
dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, value));
VTABLE_set_number_native(INTERP, dest,
SELF.get_integer() + VTABLE_get_number(interp, value));
return dest;
}
VTABLE PMC *add_int(INTVAL b, PMC *dest) {
const INTVAL a = VTABLE_get_integer(INTERP, SELF);
const INTVAL c = a + b;
if ((c^a) >= 0 || (c^b) >= 0)
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), c);
else {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, a);
return VTABLE_add_int(INTERP, temp, b, dest);
}
}
/*
=item C<void i_add(PMC *value)>
=item C<void i_add(INTVAL value)>
=item C<void i_add(FLOATVAL value)>
Adds C<value> to C<SELF> inplace.
=cut
*/
MULTI void i_add(Integer value) {
STATICSELF.i_add_int(VTABLE_get_integer(INTERP, value));
}
MULTI void i_add(Complex value) {
const INTVAL a = SELF.get_integer();
UNUSED(a);
Parrot_pmc_reuse(INTERP, SELF, enum_class_Complex, 0);
VTABLE_set_number_native(INTERP, SELF,
SELF.get_integer() + VTABLE_get_number(INTERP, value));
}
MULTI void i_add(DEFAULT value) {
VTABLE_set_number_native(INTERP, SELF,
SELF.get_integer() + VTABLE_get_number(INTERP, value));
}
VTABLE void i_add_int(INTVAL b) {
const INTVAL a = SELF.get_integer();
const INTVAL c = a + b;
if ((c^a) >= 0 || (c^b) >= 0)
VTABLE_set_integer_native(INTERP, SELF, c);
else {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_add_int(INTERP, SELF, b);
}
}
VTABLE void i_add_float(FLOATVAL value) {
const INTVAL a = SELF.get_integer();
VTABLE_set_number_native(INTERP, SELF, a + value);
}
/*
=item C<PMC *subtract(PMC *value, PMC *dest)>
Subtracts C<*value> from the integer and returns the result in C<*dest>. If
C<dest> is NULL, a PMC of this type.
Please note: as C<SELF> or C<value> maybe be subclassed, we have to call
C<get_integer> and C<set_integer_native> always.
=cut
*/
MULTI PMC *subtract(Integer value, PMC *dest) {
const INTVAL a = SELF.get_integer();
const INTVAL b = VTABLE_get_integer(INTERP, value);
const INTVAL c = a - b;
if ((c^a) >= 0 || (c^~b) >= 0)
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), c);
else {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, a);
return VTABLE_subtract(INTERP, temp, value, dest);
}
}
MULTI PMC *subtract(Complex value, PMC *dest) {
const INTVAL a = SELF.get_integer();
dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, value));
VTABLE_set_number_native(INTERP, dest,
a - VTABLE_get_number_keyed_int(INTERP, value, 0));
VTABLE_set_number_keyed_int(INTERP, dest, 1,
-VTABLE_get_number_keyed_int(INTERP, value, 1));
return dest;
}
MULTI PMC *subtract(BigInt value, PMC *dest) {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt,
SELF.get_integer());
return VTABLE_subtract(INTERP, temp, value, dest);
}
MULTI PMC *subtract(DEFAULT value, PMC *dest) {
dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, value));
VTABLE_set_number_native(INTERP, dest,
SELF.get_integer() - VTABLE_get_number(INTERP, value));
return dest;
}
/*
=item C<PMC *subtract_int(INTVAL value, PMC *dest)>
Subtracts C<value> from the integer and returns the result in C<*dest>.
=cut
*/
VTABLE PMC *subtract_int(INTVAL b, PMC *dest) {
const INTVAL a = SELF.get_integer();
const INTVAL c = a - b;
if ((c^a) >= 0 || (c^~b) >= 0)
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), c);
else {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, a);
return VTABLE_subtract_int(INTERP, temp, b, dest);
}
}
/*
=item C<void i_subtract(PMC *value)>
=item C<void i_subtract_int(INTVAL value)>
=item C<void i_subtract_float(FLOATVAL value)>
Subtracts C<value> from C<SELF> inplace.
=cut
*/
MULTI void i_subtract(Integer value) {
const INTVAL a = SELF.get_integer();
const INTVAL b = VTABLE_get_integer(INTERP, value);
const INTVAL c = a - b;
if ((c^a) >= 0 || (c^~b) >= 0)
VTABLE_set_integer_native(INTERP, SELF, c);
else {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_subtract(INTERP, SELF, value);
}
}
MULTI void i_subtract(Complex value) {
const INTVAL a = SELF.get_integer();
Parrot_pmc_reuse(INTERP, SELF, enum_class_Complex, 0);
VTABLE_set_number_native(INTERP, SELF,
(FLOATVAL)a - VTABLE_get_number_keyed_int(INTERP, value, 0));
VTABLE_set_number_keyed_int(INTERP, SELF, 1,
-VTABLE_get_number_keyed_int(INTERP, value, 1));
}
MULTI void i_subtract(DEFAULT value) {
VTABLE_set_number_native(INTERP, SELF,
SELF.get_integer() - VTABLE_get_number(INTERP, value));
}
VTABLE void i_subtract_int(INTVAL b) {
const INTVAL a = SELF.get_integer();
const INTVAL c = a - b;
if ((c^a) >= 0 || (c^~b) >= 0)
VTABLE_set_integer_native(INTERP, SELF, c);
else {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_subtract_int(INTERP, SELF, b);
}
}
VTABLE void i_subtract_float(FLOATVAL value) {
const INTVAL a = SELF.get_integer();
VTABLE_set_number_native(INTERP, SELF, a - value);
}
/*
=item C<PMC *multiply(PMC *value, PMC *dest)>
=item C<PMC *multiply_int(INTVAL value, PMC *dest)>
Multiplies the integer by C<*value> and returns the result in C<*dest>.
=cut
*/
MULTI PMC *multiply(Integer value, PMC *dest) {
const INTVAL a = VTABLE_get_integer(INTERP, SELF);
const INTVAL b = VTABLE_get_integer(INTERP, value);
const INTVAL c = a * b;
const double cf = (double)a * (double)b;
if ((double) c == cf)
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), c);
else {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, a);
return VTABLE_multiply(INTERP, temp, value, dest);
}
}
MULTI PMC *multiply(Complex value, PMC *dest) {
return VTABLE_multiply(INTERP, value, SELF, dest);
}
MULTI PMC *multiply(BigInt value, PMC *dest) {
return VTABLE_multiply_int(INTERP, value, SELF.get_integer(), dest);
}
MULTI PMC *multiply(String value, PMC *dest) {
return Parrot_Integer_multi_multiply_Integer_PMC(INTERP, SELF, value, dest);
}
MULTI PMC *multiply(DEFAULT value, PMC *dest) {
const FLOATVAL valf = VTABLE_get_number(INTERP, value);
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
SELF.get_number() * valf);
}
VTABLE PMC *multiply_int(INTVAL b, PMC *dest) {
const INTVAL a = SELF.get_integer();
const INTVAL c = a * b;
const double cf = (double)a * (double)b;
if ((double) c == cf)
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), c);
else {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, a);
return VTABLE_multiply_int(INTERP, temp, b, dest);
}
}
/*
=item C<void i_multiply(PMC *value)>
=item C<void i_multiply_int(INTVAL value)>
=item C<void i_multiply_float(FLOATVAL value)>
Multiply C<value> with C<SELF> inplace.
=cut
*/
VTABLE void i_multiply(PMC * value) {
/*
VTABLE_i_multiply_int(INTERP, SELF, VTABLE_get_integer(INTERP, value));
*/
VTABLE_set_number_native(INTERP, SELF,
SELF.get_integer() * VTABLE_get_number(INTERP, value));
}
VTABLE void i_multiply_int(INTVAL b) {
const INTVAL a = SELF.get_integer();
const INTVAL c = a * b;
const double cf = (double)a * (double)b;
if ((double) c == cf)
SELF.set_integer_native(c);
else {
maybe_throw_overflow_error(INTERP);
upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_multiply_int(INTERP, SELF, b);
}
}
VTABLE void i_multiply_float(FLOATVAL value) {
const INTVAL a = SELF.get_integer();
VTABLE_set_number_native(INTERP, SELF, a * value);
}
/*
=item C<PMC *divide(PMC *value, PMC *dest)>
=item C<PMC *divide_int(INTVAL value, PMC *dest)>
=item C<PMC *divide_float(FLOATVAL value, PMC *dest)>
Divides the number by C<value> and returns the result in C<*dest>.
=item C<void i_divide(PMC *value)>
=item C<void i_divide_int(INTVAL value)>
=item C<void i_divide_float(FLOATVAL value)>
Divides C<SELF> by C<value> inplace.
=cut
*/
MULTI PMC *divide(BigInt value, PMC *dest) {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt,
SELF.get_integer());
return VTABLE_divide(INTERP, temp, value, dest);
}
MULTI PMC *divide(DEFAULT value, PMC *dest) {
const FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
SELF.get_number() / d);
}
MULTI void i_divide(BigInt value) {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_divide(INTERP, SELF, value);
}
MULTI void i_divide(DEFAULT value) {
const FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
VTABLE_set_number_native(INTERP, SELF, SELF.get_number() / d);
}
/*
=item C<PMC *floor_divide(PMC *value, PMC *dest)>
=item C<PMC *floor_divide_int(INTVAL value, PMC *dest)>
=item C<PMC *floor_divide_float(FLOATVAL value, PMC *dest)>
Divides the number by C<value> and returns the result in C<*dest>.
=item C<void i_floor_divide(PMC *value)>
=item C<void i_floor_divide_int(INTVAL value)>
=item C<void i_floor_divide_float(FLOATVAL value)>
Divides C<SELF> by C<value> inplace.
=cut
*/
MULTI PMC *floor_divide(BigInt value, PMC *dest) {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt,
SELF.get_integer());
return VTABLE_floor_divide(INTERP, temp, value, dest);
}
MULTI PMC *floor_divide(DEFAULT value, PMC *dest) {
const FLOATVAL d = VTABLE_get_number(INTERP, value);
FLOATVAL f;
if (FLOAT_IS_ZERO(d))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
f = floor(SELF.get_number() / d);
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
(INTVAL)f);
}
VTABLE PMC *floor_divide_int(INTVAL value, PMC *dest) {
FLOATVAL f;
if (value == 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
f = floor(SELF.get_number() / value);
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), (INTVAL)f);
}
VTABLE PMC *floor_divide_float(FLOATVAL value, PMC *dest) {
FLOATVAL f;
if (FLOAT_IS_ZERO(value))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
f = floor(SELF.get_number() / value);
return Parrot_pmc_new_init_int(INTERP,
VTABLE_type(INTERP, SELF), (INTVAL)f);
}
MULTI void i_floor_divide(BigInt value) {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_floor_divide(INTERP, SELF, value);
}
MULTI void i_floor_divide(DEFAULT value) {
const FLOATVAL d = VTABLE_get_number(INTERP, value);
FLOATVAL f;
if (FLOAT_IS_ZERO(d))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
f = floor(SELF.get_number() / d);
VTABLE_set_integer_native(INTERP, SELF, (INTVAL)f);
}
VTABLE void i_floor_divide_int(INTVAL value) {
FLOATVAL f;
if (value == 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
f = floor(SELF.get_number() / value);
VTABLE_set_integer_native(INTERP, SELF, (INTVAL)f);
}
VTABLE void i_floor_divide_float(FLOATVAL value) {
FLOATVAL f;
if (FLOAT_IS_ZERO(value))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"float division by zero");
f = floor(SELF.get_number() / value);
VTABLE_set_integer_native(INTERP, SELF, (INTVAL)f);
}
/*
=item C<PMC *modulus(PMC *value, PMC *dest)>
=item C<PMC *modulus(INTVAL value, PMC *dest)>
=item C<PMC *modulus(FLOATVAL value, PMC *dest)>
Calculates the value of corrected C<mod> C<value> and returns
the result in C<dest>. See also ops/math.ops.
=item C<void i_modulus(PMC *value)>
=item C<void i_modulus(INTVAL value)>
=item C<void i_modulus(FLOATVAL value)>
Calculates modulus in place.
=cut
*/
MULTI PMC *modulus(BigInt value, PMC *dest) {
PMC *temp;
maybe_throw_overflow_error(INTERP);
temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt,
SELF.get_integer());
return VTABLE_modulus(INTERP, temp, value, dest);
}
MULTI PMC *modulus(DEFAULT value, PMC *dest) {
const INTVAL d = VTABLE_get_integer(INTERP, value);
if (d == 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"int modulus by zero");
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
Parrot_util_intval_mod(SELF.get_integer(), d));
}
VTABLE PMC *modulus_int(INTVAL value, PMC *dest) {
if (value == 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"int modulus by zero");
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
Parrot_util_intval_mod(SELF.get_integer(), value));
}
VTABLE PMC *modulus_float(FLOATVAL value, PMC *dest) {
if (FLOAT_IS_ZERO(value))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"int modulus by zero");
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
Parrot_util_intval_mod(SELF.get_integer(), (INTVAL)value));
}
MULTI void i_modulus(BigInt value) {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_modulus(INTERP, SELF, value);
}
MULTI void i_modulus(DEFAULT value) {
const INTVAL d = VTABLE_get_integer(INTERP, value);
if (d == 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"int modulus by zero");
VTABLE_set_integer_native(INTERP, SELF,
Parrot_util_intval_mod(SELF.get_integer(), d));
}
VTABLE void i_modulus_int(INTVAL value) {
if (value == 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"int modulus by zero");
VTABLE_set_integer_native(INTERP, SELF,
Parrot_util_intval_mod(SELF.get_integer() , value));
}
VTABLE void i_modulus_float(FLOATVAL value) {
if (FLOAT_IS_ZERO(value))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
"int modulus by zero");
VTABLE_set_integer_native(INTERP, SELF,
Parrot_util_intval_mod(SELF.get_integer() , (INTVAL)value));
}
/*
=item C<PMC *neg(PMC *dest)>
=item C<void i_neg()>
Set C<dest> to the negated value of C<SELF>. If the value of C<SELF>
is the minimum integer, a BigInt is created.
=cut
*/
VTABLE PMC *neg(PMC *dest) {
const INTVAL a = SELF.get_integer();
if (a != PARROT_INTVAL_MIN)
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
-a);
else {
PMC *promoted;
maybe_throw_overflow_error(INTERP);
promoted = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, 0);
return VTABLE_subtract_int(INTERP, promoted, a, promoted);
}
}
VTABLE void i_neg() {
const INTVAL a = SELF.get_integer();
if (a != PARROT_INTVAL_MIN)
VTABLE_set_integer_native(INTERP, SELF, -a);
else {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_set_integer_native(INTERP, SELF, 0);
VTABLE_i_subtract_int(INTERP, SELF, a);
}
}
/*
=item C<INTVAL is_equal(PMC *value)>
The C<==> operation.
=cut
*/
VTABLE INTVAL is_equal(PMC *value) {
INTVAL retval;
switch (value->vtable->base_type) {
case enum_class_BigInt:
{
PMC const *temp = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt,
SELF.get_integer());
Parrot_mmd_multi_dispatch_from_c_args(INTERP,
"is_equal", "PP->I", temp, value, &retval);
return retval;
}
break;
default:
return (VTABLE_get_integer(INTERP, SELF)
== VTABLE_get_integer(INTERP, value));
break;
}
}
/*
=item C<INTVAL cmp(PMC *value)>
Returns the result of comparing the integer with C<*value>.
=cut
*/
MULTI INTVAL cmp(String value) {
INTVAL iv;
GET_ATTR_iv(INTERP, SELF, iv);
{
const FLOATVAL fdiff =
(FLOATVAL)iv - VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(fdiff)) {
const INTVAL idiff =
SELF.get_integer() - VTABLE_get_integer(INTERP, value);
return idiff > 0 ? 1 : idiff < 0 ? -1 : 0;
}
return fdiff > 0 ? 1 : -1;
}
}
MULTI INTVAL cmp(Float value) {
INTVAL iv;
GET_ATTR_iv(INTERP, SELF, iv);
{
const FLOATVAL diff = (FLOATVAL)iv - VTABLE_get_number(INTERP, value);
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
}
}
MULTI INTVAL cmp(DEFAULT value) {
/* int or undef */
INTVAL selfint;
GET_ATTR_iv(INTERP, SELF, selfint);
{
const INTVAL valueint = VTABLE_get_integer(INTERP, value);
return selfint > valueint ? 1 : selfint < valueint ? -1 : 0;
}
}
/*
=item C<INTVAL cmp_num(PMC *value)>
Returns the result of numerically comparing the integer with C<*value>.
=cut
*/
MULTI INTVAL cmp_num(String value) {
const FLOATVAL fdiff = SELF.get_number() - VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(fdiff)) {
const INTVAL idiff =
SELF.get_integer() - VTABLE_get_integer(INTERP, value);
return idiff > 0 ? 1 : idiff < 0 ? -1 : 0;
}
return fdiff > 0 ? 1 : -1;
}
MULTI INTVAL cmp_num(Float value) {
const FLOATVAL diff = SELF.get_number() - VTABLE_get_number(INTERP, value);
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
}
MULTI INTVAL cmp_num(DEFAULT value) {
/* int or undef */
const INTVAL diff = SELF.get_integer() - VTABLE_get_integer(INTERP, value);
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
}
/*
=item C<void increment()>
Increments the integer.
=cut
*/
VTABLE void increment() {
INTVAL a, c;
GET_ATTR_iv(INTERP, SELF, a);
c = a + 1;
/* did not overflow */
if ((c^a) >= 0 || (c^1) >= 0)
SET_ATTR_iv(INTERP, SELF, c);
else {
Parrot_pmc_reuse(INTERP, SELF, enum_class_BigInt, 0);
VTABLE_set_integer_native(INTERP, SELF, a);
VTABLE_increment(INTERP, SELF);
}
}
/*
=item C<void decrement()>
Decrements the integer.
=cut
*/
VTABLE void decrement() {
const INTVAL a = SELF.get_integer();
const INTVAL c = a - 1;
if ((c^a) >= 0 || (c^~1) >= 0)
VTABLE_set_integer_native(INTERP, SELF, c);
else {
Parrot_pmc_reuse(INTERP, SELF, enum_class_BigInt, 0);
VTABLE_set_integer_native(INTERP, SELF, a);
VTABLE_decrement(INTERP, SELF);
}
}
/*
=item C<PMC *absolute(PMC *dest)>
=item C<void absolute()>
Sets C<dest> to the absolute value of C<SELF>. If the value of C<SELF>
is the minimum integer, a BigInt is created.
=cut
*/
VTABLE PMC *absolute(PMC *dest) {
const INTVAL a = SELF.get_integer();
if (a != PARROT_INTVAL_MIN)
return Parrot_pmc_new_init_int(INTERP, VTABLE_type(INTERP, SELF),
abs(a));
else {
PMC *promoted;
maybe_throw_overflow_error(INTERP);
promoted = Parrot_pmc_new_init_int(INTERP, enum_class_BigInt, a);
return VTABLE_neg(INTERP, promoted, dest);
}
}
VTABLE void i_absolute() {
const INTVAL a = SELF.get_integer();
if (a != PARROT_INTVAL_MIN)
VTABLE_set_integer_native(INTERP, SELF, abs(a));
else {
maybe_throw_overflow_error(INTERP);
SELF = upgrade_self_to_bignum(INTERP, SELF);
VTABLE_i_neg(INTERP, SELF);
}
}
/*
=item C<STRING *get_as_base(INTVAL base)>
Converts and returns the integer in base C<base>. C<base> must be between 2
and 36, inclusive.
=cut
*/
METHOD get_as_base(INTVAL base) {
char buf[128];
STRING *result;
if ((base < 2) || (base > 36))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"get_as_base: base out of bounds");
result = Parrot_str_from_int_base(INTERP, buf,
(HUGEINTVAL)VTABLE_get_integer(INTERP, SELF),
(unsigned int)base);
RETURN(STRING *result);
}
/*
=item C<void freeze(PMC *info)>
Used to archive the integer.
=cut
*/
VTABLE void freeze(PMC *info) {
SUPER(info);
VTABLE_push_integer(INTERP, info, SELF.get_integer());
}
/*
=item C<void thaw(PMC *info)>
Used to unarchive the integer.
=cut
*/
VTABLE void thaw(PMC *info) {
SUPER(info);
SELF.set_integer_native(VTABLE_shift_integer(INTERP, info));
}
/*
=item C<void set_random(from, to)>
Set to a random value.
SELF.set_random() # value from [INTVAL_MIN..INTVAL_MAX]
SELF.set_random(0) # same
SELF.set_random(a) # value from [0..a] or [a..0] if a is negative
SELF.set_random(a, b) # value from [a..b] (b > a)
=cut
*/
METHOD set_random(INTVAL a :optional, INTVAL has_a :opt_flag,
INTVAL b :optional, INTVAL has_b :opt_flag)
{
INTVAL r;
if (has_a && a != 0) {
if (!has_b) {
if (a < 0)
b = 0;
if (a > 0) {
b = a;
a = 0;
}
}
if (a == b || a > b) {
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"set_random: range start must be less than range end (%d, %d)", a, b);
}
{
const double spread = (double)(b - a + 1);
const double randpart = Parrot_util_float_rand(0);
r = a + (INTVAL)(spread * randpart);
}
}
else
r = Parrot_util_int_rand(0);
SELF.set_integer_native(r);
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/