1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* time.c: wide value condition changed.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27090 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2010-03-29 10:47:00 +00:00
parent b1b3e13570
commit 33d1647252
2 changed files with 132 additions and 122 deletions

View file

@ -1,3 +1,7 @@
Mon Mar 29 19:45:09 2010 Tanaka Akira <akr@fsij.org>
* time.c: wide value condition changed.
Mon Mar 29 18:10:03 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/optparse.rb (Numeric): accept rationals.

192
time.c
View file

@ -56,43 +56,44 @@ typedef unsigned LONG_LONG unsigned_time_t;
#define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (~(unsigned_time_t)0))
#define TIMET_MIN (~(time_t)0 <= 0 ? (time_t)(((unsigned_time_t)1) << (sizeof(time_t) * CHAR_BIT - 1)) : (time_t)0)
#if defined(HAVE_UINT64_T) && SIZEOF_VALUE < SIZEOF_UINT64_T
#define WIDEINT_IS_UINT64 1
#if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T
# define WIDEVALUE_IS_WIDER 1
# define FIXWV_P(tv) ((tv) & 1)
#define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEINT)(tv), 1)
#define INT64toFIXWV(i64) ((WIDEINT)((SIGNED_WIDEINT)(i64) << 1 | FIXNUM_FLAG))
# define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1)
# define INT64toFIXWV(i64) ((WIDEVALUE)((SIGNED_WIDEVALUE)(i64) << 1 | FIXNUM_FLAG))
# define FIXWV_MAX (((int64_t)1 << 62) - 1)
# define FIXWV_MIN (-((int64_t)1 << 62))
# define POSFIXWVABLE(i64) ((i64) < FIXWV_MAX+1)
# define NEGFIXWVABLE(i64) ((i64) >= FIXWV_MIN)
# define FIXWVABLE(i64) (POSFIXWVABLE(i64) && NEGFIXWVABLE(i64))
typedef uint64_t WIDEINT;
typedef int64_t SIGNED_WIDEINT;
typedef uint64_t WIDEVALUE;
typedef int64_t SIGNED_WIDEVALUE;
#else
#define WIDEINT_IS_UINT64 0
# define WIDEVALUE_IS_WIDER 0
# define FIXWV_P(tv) FIXNUM_P(tv)
typedef VALUE WIDEINT;
typedef SIGNED_VALUE SIGNED_WIDEINT;
typedef VALUE WIDEVALUE;
typedef SIGNED_VALUE SIGNED_WIDEVALUE;
#endif
#define STRUCT_WIDEVAL
/* #define STRUCT_WIDEVAL */
#ifdef STRUCT_WIDEVAL
/* for type checking */
typedef struct {
WIDEINT value;
WIDEVALUE value;
} wideval_t;
static inline wideval_t WIDEVAL_WRAP(WIDEVALUE v) { wideval_t w = { v }; return w; }
# define WIDEVAL_GET(w) ((w).value)
#define WIDEVAL_SET(w, v) ((w).value = (v))
#else
typedef WIDEINT wideval_t;
typedef WIDEVALUE wideval_t;
# define WIDEVAL_WRAP(v) (v)
# define WIDEVAL_GET(w) (w)
#define WIDEVAL_SET(w, v) ((w) = (v))
#endif
static inline VALUE
w2xv(wideval_t w)
{
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(w)))
return INT64toNUM(FIXWVtoINT64(WIDEVAL_GET(w)));
return (VALUE)WIDEVAL_GET(w);
@ -100,30 +101,26 @@ w2xv(wideval_t w)
return WIDEVAL_GET(w);
#endif
}
static inline wideval_t
xv2w(VALUE xv) {
wideval_t w;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
# if SIZEOF_UINT64_T % SIZEOF_BDIGITS != 0
# error SIZEOF_UINT64 is not multiple of SIZEOF_BDIGITS
# endif
long len;
static wideval_t
xv2w_bignum(VALUE xv)
{
long len = RBIGNUM_LEN(xv);
BDIGIT *ds;
if (FIXNUM_P(xv)) {
WIDEVAL_SET(w, (WIDEINT)(SIGNED_WIDEINT)(SIGNED_VALUE)xv);
return w;
}
else if (TYPE(xv) == T_BIGNUM &&
(len = RBIGNUM_LEN(xv)) * sizeof(BDIGIT) <= sizeof(WIDEINT)) {
wideval_t w;
ds = RBIGNUM_DIGITS(xv);
WIDEVAL_SET(w, xv);
w = WIDEVAL_WRAP(xv);
if (RBIGNUM_POSITIVE_P(xv)) {
if (ds[len-1] < ((BDIGIT)1 << (sizeof(BDIGIT)*CHAR_BIT-2))) {
int64_t i = 0;
while (len)
i = (i << sizeof(BDIGIT)*CHAR_BIT) | ds[--len];
if (FIXWVABLE(i))
WIDEVAL_SET(w, INT64toFIXWV(i));
w = WIDEVAL_WRAP(INT64toFIXWV(i));
}
}
else {
@ -131,26 +128,36 @@ xv2w(VALUE xv) {
int64_t i = 0;
while (len)
i = (i << sizeof(BDIGIT)*CHAR_BIT) | ds[--len];
WIDEVAL_SET(w, INT64toFIXWV(-i));
w = WIDEVAL_WRAP(INT64toFIXWV(-i));
}
}
return w;
}
#endif
WIDEVAL_SET(w, xv);
return w;
static inline wideval_t
xv2w(VALUE xv)
{
#if WIDEVALUE_IS_WIDER
if (FIXNUM_P(xv)) {
return WIDEVAL_WRAP((WIDEVALUE)(SIGNED_WIDEVALUE)(SIGNED_VALUE)xv);
}
else if (TYPE(xv) == T_BIGNUM &&
RBIGNUM_LEN(xv) * sizeof(BDIGIT) <= sizeof(WIDEVALUE)) {
return xv2w_bignum(xv);
}
#endif
return WIDEVAL_WRAP(xv);
}
static wideval_t rb_time_magnify(VALUE v);
static wideval_t
timet2wideval(time_t t)
{
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
int64_t i64 = t;
wideval_t w;
if (-((-FIXWV_MIN)/TIME_SCALE) <= i64 && i64 <= FIXWV_MAX/TIME_SCALE) {
WIDEVAL_SET(w, INT64toFIXWV(i64 * TIME_SCALE));
return w;
return WIDEVAL_WRAP(INT64toFIXWV(i64 * TIME_SCALE));
}
#endif
return rb_time_magnify(TIMET2NUM(t));
@ -215,10 +222,26 @@ rb_localtime(const time_t *tm, struct tm *result)
static ID id_divmod, id_mul, id_submicro, id_nano_num, id_nano_den, id_offset;
static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift;
#define eq(x,y) (RTEST(rb_funcall((x), id_eq, 1, (y))))
#define ne(x,y) (RTEST(rb_funcall((x), id_ne, 1, (y))))
#define lt(x,y) (RTEST(rb_funcall((x), '<', 1, (y))))
#define gt(x,y) (RTEST(rb_funcall((x), '>', 1, (y))))
static int
eq(VALUE x, VALUE y)
{
if (FIXNUM_P(x) && FIXNUM_P(y)) {
return x == y;
}
return RTEST(rb_funcall(x, id_eq, 1, y));
}
static int
lt(VALUE x, VALUE y)
{
if (FIXNUM_P(x) && FIXNUM_P(y)) {
return (long)x < (long)y;
}
return RTEST(rb_funcall(x, '<', 1, y));
}
#define ne(x,y) (!eq(x,y))
#define gt(x,y) (lt(y,x))
#define le(x,y) (!gt(x,y))
#define ge(x,y) (!lt(x,y))
@ -325,26 +348,30 @@ divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
*r = rb_ary_entry(ary, 1);
}
static int
static inline int
weq(wideval_t wx, wideval_t wy)
{
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wx)) && FIXWV_P(WIDEVAL_GET(wy))) {
return FIXWVtoINT64(WIDEVAL_GET(wx)) == FIXWVtoINT64(WIDEVAL_GET(wy));
return WIDEVAL_GET(wx) == WIDEVAL_GET(wy);
}
#endif
return RTEST(rb_funcall(w2xv(wx), id_eq, 1, w2xv(wy)));
#else
return eq(WIDEVAL_GET(wx), WIDEVAL_GET(wy));
#endif
}
static int
static inline int
wlt(wideval_t wx, wideval_t wy)
{
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wx)) && FIXWV_P(WIDEVAL_GET(wy))) {
return FIXWVtoINT64(WIDEVAL_GET(wx)) < FIXWVtoINT64(WIDEVAL_GET(wy));
return (SIGNED_WIDEVALUE)WIDEVAL_GET(wx) < (SIGNED_WIDEVALUE)WIDEVAL_GET(wy);
}
#endif
return RTEST(rb_funcall(w2xv(wx), '<', 1, w2xv(wy)));
#else
return lt(WIDEVAL_GET(wx), WIDEVAL_GET(wy));
#endif
}
#define wne(x,y) (!weq(x,y))
@ -356,13 +383,11 @@ static wideval_t
wadd(wideval_t wx, wideval_t wy)
{
VALUE x;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wx)) && FIXWV_P(WIDEVAL_GET(wy))) {
int64_t r = FIXWVtoINT64(WIDEVAL_GET(wx)) + FIXWVtoINT64(WIDEVAL_GET(wy));
if (FIXWVABLE(r)) {
wideval_t z;
WIDEVAL_SET(z, INT64toFIXWV(r));
return z;
return WIDEVAL_WRAP(INT64toFIXWV(r));
}
return xv2w(INT64toNUM(r));
}
@ -377,13 +402,11 @@ static wideval_t
wsub(wideval_t wx, wideval_t wy)
{
VALUE x;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wx)) && FIXWV_P(WIDEVAL_GET(wy))) {
int64_t r = FIXWVtoINT64(WIDEVAL_GET(wx)) - FIXWVtoINT64(WIDEVAL_GET(wy));
if (FIXWVABLE(r)) {
wideval_t z;
WIDEVAL_SET(z, INT64toFIXWV(r));
return z;
return WIDEVAL_WRAP(INT64toFIXWV(r));
}
return xv2w(INT64toNUM(r));
}
@ -399,7 +422,7 @@ static wideval_t
wmul(wideval_t wx, wideval_t wy)
{
VALUE x;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wx)) && FIXWV_P(WIDEVAL_GET(wy))) {
int64_t a, b, c;
a = FIXWVtoINT64(WIDEVAL_GET(wx));
@ -407,9 +430,7 @@ wmul(wideval_t wx, wideval_t wy)
b = FIXWVtoINT64(WIDEVAL_GET(wy));
c = a * b;
if (c / a == b && FIXWVABLE(c)) {
wideval_t z;
WIDEVAL_SET(z, INT64toFIXWV(c));
return z;
return WIDEVAL_WRAP(INT64toFIXWV(c));
}
}
#endif
@ -422,7 +443,7 @@ static int
wcmp(wideval_t wx, wideval_t wy)
{
VALUE x, y;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wx)) && FIXWV_P(WIDEVAL_GET(wy))) {
int64_t a, b;
a = FIXWVtoINT64(WIDEVAL_GET(wx));
@ -443,7 +464,7 @@ static wideval_t
wquo(wideval_t wx, wideval_t wy)
{
VALUE x, y, ret;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wx)) && FIXWV_P(WIDEVAL_GET(wy))) {
int64_t a, b, c;
a = FIXWVtoINT64(WIDEVAL_GET(wx));
@ -451,12 +472,9 @@ wquo(wideval_t wx, wideval_t wy)
if (b == 0) rb_num_zerodiv();
c = a / b;
if (c * b == a) {
wideval_t z;
if (FIXWVABLE(c))
WIDEVAL_SET(z, INT64toFIXWV(c));
else
WIDEVAL_SET(z, INT64toNUM(c));
return z;
return WIDEVAL_WRAP(INT64toFIXWV(c));
return WIDEVAL_WRAP(INT64toNUM(c));
}
}
#endif
@ -477,29 +495,29 @@ static void
wdivmodv(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr)
{
VALUE tmp, ary;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(wn)) && FIXWV_P(WIDEVAL_GET(wd))) {
int64_t n, d, q, r;
d = FIXWVtoINT64(WIDEVAL_GET(wd));
if (d == 0) rb_num_zerodiv();
if (d == 1) {
*wq = wn;
WIDEVAL_SET(*wr, INT64toFIXWV(0));
*wr = WIDEVAL_WRAP(INT64toFIXWV(0));
return;
}
if (d == -1) {
int64_t xneg = -FIXWVtoINT64(WIDEVAL_GET(wn));
if (FIXWVABLE(xneg))
WIDEVAL_SET(*wq, INT64toFIXWV(xneg));
*wq = WIDEVAL_WRAP(INT64toFIXWV(xneg));
else
WIDEVAL_SET(*wq, INT64toNUM(xneg));
WIDEVAL_SET(*wr, INT64toFIXWV(0));
*wq = WIDEVAL_WRAP(INT64toNUM(xneg));
*wr = WIDEVAL_WRAP(INT64toFIXWV(0));
return;
}
n = FIXWVtoINT64(WIDEVAL_GET(wn));
if (n == 0) {
WIDEVAL_SET(*wq, INT64toFIXWV(0));
WIDEVAL_SET(*wr, INT64toFIXWV(0));
*wq = WIDEVAL_WRAP(INT64toFIXWV(0));
*wr = WIDEVAL_WRAP(INT64toFIXWV(0));
return;
}
if (d < 0) {
@ -522,8 +540,8 @@ wdivmodv(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr)
r = n % d;
}
}
WIDEVAL_SET(*wq, INT64toFIXWV(q));
WIDEVAL_SET(*wr, INT64toFIXWV(r));
*wq = WIDEVAL_WRAP(INT64toFIXWV(q));
*wr = WIDEVAL_WRAP(INT64toFIXWV(r));
return;
}
#endif
@ -585,32 +603,20 @@ num_exact(VALUE v)
static wideval_t
rb_time_magnify(VALUE v)
{
wideval_t ret;
if (FIXNUM_P(v)) {
#if WIDEINT_IS_UINT64 && SIZEOF_LONG * 2 <= SIZEOF_INT64_T
#if WIDEVALUE_IS_WIDER
int64_t i64 = (int64_t)FIX2LONG(v) * TIME_SCALE;
WIDEVAL_SET(ret, INT64toFIXWV(i64));
return ret;
return WIDEVAL_WRAP(INT64toFIXWV(i64));
#else
long a, b, c;
a = FIX2LONG(v);
if (a == 0) {
#if WIDEINT_IS_UINT64
WIDEVAL_SET(ret, INT64toFIXWV(0));
#else
WIDEVAL_SET(ret, INT2FIX(0));
#endif
return ret;
return WIDEVAL_WRAP(INT2FIX(0));
}
b = TIME_SCALE;
c = a * b;
if (c / a == b) {
#if WIDEINT_IS_UINT64
WIDEVAL_SET(ret, INT64toFIXWV(c));
#else
WIDEVAL_SET(ret, LONG2NUM(c));
#endif
return ret;
return WIDEVAL_WRAP(LONG2NUM(c));
}
#endif
}
@ -621,7 +627,7 @@ static VALUE
rb_time_unmagnify(wideval_t w)
{
VALUE v;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(w))) {
int64_t a, b, c;
a = FIXWVtoINT64(WIDEVAL_GET(w));
@ -640,7 +646,7 @@ static VALUE
rb_time_unmagnify_to_float(wideval_t w)
{
VALUE v;
#if WIDEINT_IS_UINT64
#if WIDEVALUE_IS_WIDER
if (FIXWV_P(WIDEVAL_GET(w))) {
int64_t a, b, c;
a = FIXWVtoINT64(WIDEVAL_GET(w));
@ -1398,7 +1404,7 @@ static int
timew_out_of_timet_range(wideval_t timew)
{
VALUE timexv;
#if WIDEINT_IS_UINT64 && SIZEOF_TIME_T < SIZEOF_INT64_T
#if WIDEVALUE_IS_WIDER && SIZEOF_TIME_T < SIZEOF_INT64_T
if (FIXWV_P(WIDEVAL_GET(timew))) {
int64_t t = FIXWVtoINT64(WIDEVAL_GET(timew));
if (t < TIME_SCALE * (int64_t)TIMET_MIN ||