Refactored sub-seconds normalizations

* separated argument to `timespec2timew` from `timespec` to seconds and
  nano-seconds.

* unified nano-seconds and micro-seconds normalizations.
This commit is contained in:
Nobuyoshi Nakada 2021-04-01 12:00:10 +09:00 committed by GitHub
parent 2a02b61fae
commit a5567350f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2021-04-01 12:00:46 +09:00
Merged: https://github.com/ruby/ruby/pull/4343

Merged-By: nobu <nobu@ruby-lang.org>

61
time.c
View File

@ -1844,13 +1844,13 @@ time_modify(VALUE time)
} }
static wideval_t static wideval_t
timespec2timew(struct timespec *ts) timenano2timew(time_t sec, long nsec)
{ {
wideval_t timew; wideval_t timew;
timew = rb_time_magnify(TIMET2WV(ts->tv_sec)); timew = rb_time_magnify(TIMET2WV(sec));
if (ts->tv_nsec) if (nsec)
timew = wadd(timew, wmulquoll(WINT2WV(ts->tv_nsec), TIME_SCALE, 1000000000)); timew = wadd(timew, wmulquoll(WINT2WV(nsec), TIME_SCALE, 1000000000));
return timew; return timew;
} }
@ -1918,7 +1918,7 @@ time_init_now(rb_execution_context_t *ec, VALUE time, VALUE zone)
tobj->tm_got=0; tobj->tm_got=0;
tobj->timew = WINT2FIXWV(0); tobj->timew = WINT2FIXWV(0);
rb_timespec_now(&ts); rb_timespec_now(&ts);
tobj->timew = timespec2timew(&ts); tobj->timew = timenano2timew(ts.tv_sec, ts.tv_nsec);
if (!NIL_P(zone)) { if (!NIL_P(zone)) {
time_zonelocal(time, zone); time_zonelocal(time, zone);
@ -2409,26 +2409,26 @@ time_init_args(rb_execution_context_t *ec, VALUE time, VALUE year, VALUE mon, VA
} }
static void static void
time_overflow_p(time_t *secp, long *nsecp) subsec_normalize(time_t *secp, long *subsecp, const long maxsubsec)
{ {
time_t sec = *secp; time_t sec = *secp;
long nsec = *nsecp; long subsec = *subsecp;
long sec2; long sec2;
if (nsec >= 1000000000) { /* nsec positive overflow */ if (UNLIKELY(subsec >= maxsubsec)) { /* subsec positive overflow */
sec2 = nsec / 1000000000; sec2 = subsec / maxsubsec;
if (TIMET_MAX - sec2 < sec) { if (TIMET_MAX - sec2 < sec) {
rb_raise(rb_eRangeError, "out of Time range"); rb_raise(rb_eRangeError, "out of Time range");
} }
nsec -= sec2 * 1000000000; subsec -= sec2 * maxsubsec;
sec += sec2; sec += sec2;
} }
else if (nsec < 0) { /* nsec negative overflow */ else if (UNLIKELY(subsec < 0)) { /* subsec negative overflow */
sec2 = NDIV(nsec,1000000000); /* negative div */ sec2 = NDIV(subsec, maxsubsec); /* negative div */
if (sec < TIMET_MIN - sec2) { if (sec < TIMET_MIN - sec2) {
rb_raise(rb_eRangeError, "out of Time range"); rb_raise(rb_eRangeError, "out of Time range");
} }
nsec -= sec2 * 1000000000; subsec -= sec2 * maxsubsec;
sec += sec2; sec += sec2;
} }
#ifndef NEGATIVE_TIME_T #ifndef NEGATIVE_TIME_T
@ -2436,17 +2436,17 @@ time_overflow_p(time_t *secp, long *nsecp)
rb_raise(rb_eArgError, "time must be positive"); rb_raise(rb_eArgError, "time must be positive");
#endif #endif
*secp = sec; *secp = sec;
*nsecp = nsec; *subsecp = subsec;
} }
#define time_usec_normalize(secp, usecp) subsec_normalize(secp, usecp, 1000000)
#define time_nsec_normalize(secp, nsecp) subsec_normalize(secp, nsecp, 1000000000)
static wideval_t static wideval_t
nsec2timew(time_t sec, long nsec) nsec2timew(time_t sec, long nsec)
{ {
struct timespec ts; time_nsec_normalize(&sec, &nsec);
time_overflow_p(&sec, &nsec); return timenano2timew(sec, nsec);
ts.tv_sec = sec;
ts.tv_nsec = nsec;
return timespec2timew(&ts);
} }
static VALUE static VALUE
@ -2465,27 +2465,8 @@ time_new_timew(VALUE klass, wideval_t timew)
VALUE VALUE
rb_time_new(time_t sec, long usec) rb_time_new(time_t sec, long usec)
{ {
wideval_t timew; time_usec_normalize(&sec, &usec);
return time_new_timew(rb_cTime, timenano2timew(sec, usec * 1000));
if (usec >= 1000000) {
long sec2 = usec / 1000000;
if (sec > TIMET_MAX - sec2) {
rb_raise(rb_eRangeError, "out of Time range");
}
usec -= sec2 * 1000000;
sec += sec2;
}
else if (usec < 0) {
long sec2 = NDIV(usec,1000000); /* negative div */
if (sec < TIMET_MIN - sec2) {
rb_raise(rb_eRangeError, "out of Time range");
}
usec -= sec2 * 1000000;
sec += sec2;
}
timew = nsec2timew(sec, usec * 1000);
return time_new_timew(rb_cTime, timew);
} }
/* returns localtime time object */ /* returns localtime time object */