bfs_num.c
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- BIGNUM_P
- NUMERIC_P
- ROBJ_AS_CSTR
- my_raise_range_error
- my_big2ullong
- my_num2ullong
- my_big2llong
- my_num2llong
- my_num2ulong
- my_big2long
- my_num2long
- my_num2ushrt
- my_num2shrt
- my_num2uchar
- my_num2char
- my_llong2big
- my_llong2num
- my_ullong2big
- my_ullong2num
/*
* bfs_num.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <ruby.h>
#ifndef BIGNUM_P
# define BIGNUM_P(x) (TYPE(x) == T_BIGNUM)
/* [<][>][^][v][top][bottom][index][help] */
#endif
#ifndef NUMERIC_P
# define NUMERIC_P(x) rb_obj_is_kind_of((x), rb_cNumeric)
/* [<][>][^][v][top][bottom][index][help] */
#endif
#ifndef ROBJ_AS_CSTR
# define ROBJ_AS_CSTR(x) (RSTRING(rb_obj_as_string(x))->ptr)
/* [<][>][^][v][top][bottom][index][help] */
#endif
#define Less_Than(x, y) rb_funcall((x), rb_intern("<"), 1, (y))
#define Greater_Than(x, y) rb_funcall((x), rb_intern(">"), 1, (y))
static void
my_raise_range_error(VALUE x, const char *type)
/* [<][>][^][v][top][bottom][index][help] */
{
rb_raise(rb_eRangeError, "numeric `%s' out of range of `%s'",
ROBJ_AS_CSTR(x), type);
}
#define Check_Negative_Num(x, type) { \
if (NUMERIC_P(x) && Less_Than((x), INT2FIX(0))) { \
my_raise_range_error((x), (type)); \
} \
}
static unsigned long long
my_big2ullong(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
VALUE str;
int base = 16;
unsigned long long num;
str = rb_big2str(x, base);
errno = 0;
num = strtoull(RSTRING(str)->ptr, NULL, base);
if (num == ULONGLONG_MAX && errno) {
my_raise_range_error(x, "unsigned long long");
}
return num;
}
unsigned long long
my_num2ullong(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
Check_Negative_Num(x, "unsigned long long");
if (BIGNUM_P(x)) {
return my_big2ullong(x);
}
return (unsigned long long)rb_num2long(x);
}
static long long
my_big2llong(VALUE x, const char *type)
/* [<][>][^][v][top][bottom][index][help] */
{
VALUE str;
int base = 16;
long long num;
str = rb_big2str(x, base);
errno = 0;
num = strtoll(RSTRING(str)->ptr, NULL, base);
if ((num == LONGLONG_MAX || num == LONGLONG_MIN) && errno) {
my_raise_range_error(x, type);
}
return num;
}
long long
my_num2llong(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
if (BIGNUM_P(x)) {
return my_big2llong(x, "long long");
}
return (long long)rb_num2long(x);
}
unsigned long
my_num2ulong(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
Check_Negative_Num(x, "unsigned long");
if (BIGNUM_P(x)) {
return rb_big2ulong(x);
}
return (unsigned long)rb_num2long(x);
}
static long
my_big2long(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
VALUE str;
int base = 16;
long num;
str = rb_big2str(x, base);
errno = 0;
num = strtol(RSTRING(str)->ptr, NULL, base);
if ((num == LONG_MAX || num == LONG_MIN) && errno) {
my_raise_range_error(x, "long");
}
return num;
}
long
my_num2long(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
if (BIGNUM_P(x)) {
return my_big2long(x);
}
return rb_num2long(x);
}
#define Check_Num_Range(x, max, min, type) { \
long long n = (BIGNUM_P(x) \
? my_big2llong((x), (type)) \
: (long long)rb_num2long(x)); \
if (n < (min) || n > (max)) { \
my_raise_range_error((x), (type)); \
} \
}
unsigned short
my_num2ushrt(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
Check_Num_Range(x, USHRT_MAX, 0, "unsigned short");
return (unsigned short)(my_num2ulong(x) & 0xffff);
}
short
my_num2shrt(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
Check_Num_Range(x, SHRT_MAX, SHRT_MIN, "short");
return (short)(my_num2long(x) & 0xffff);
}
unsigned char
my_num2uchar(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
Check_Num_Range(x, UCHAR_MAX, 0, "unsigned char");
return (unsigned char)(my_num2ulong(x) & 0xff);
}
char
my_num2char(VALUE x)
/* [<][>][^][v][top][bottom][index][help] */
{
Check_Num_Range(x, SCHAR_MAX, SCHAR_MIN, "char");
return (char)(my_num2long(x) & 0xff);
}
static VALUE
my_llong2big(long long n)
/* [<][>][^][v][top][bottom][index][help] */
{
char str[21];
sprintf(str, "%+lld", n);
return rb_cstr2inum(str, 10);
}
VALUE
my_llong2num(long long n)
/* [<][>][^][v][top][bottom][index][help] */
{
if (FIXABLE(n)) {
return INT2FIX(n);
}
return my_llong2big(n);
}
static VALUE
my_ullong2big(unsigned long long n)
/* [<][>][^][v][top][bottom][index][help] */
{
char str[21];
sprintf(str, "%llu", n);
return rb_cstr2inum(str, 10);
}
VALUE
my_ullong2num(unsigned long long n)
/* [<][>][^][v][top][bottom][index][help] */
{
if (POSFIXABLE(n)) {
return INT2FIX(n);
}
return my_ullong2big(n);
}