From c943e59603ca644ec44b1e861e12cc41db5d7ea7 Mon Sep 17 00:00:00 2001 From: nobu Date: Sat, 1 Oct 2016 08:52:42 +0000 Subject: date_parse.c: refactor * ext/date/date_parse.c (date_zone_to_diff): refactor without allocating strings. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56312 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/date/date_parse.c | 169 ++++++++++++++++++-------------------------------- 1 file changed, 59 insertions(+), 110 deletions(-) (limited to 'ext/date') diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index efb414e2ee..7a5ed723b4 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -7,6 +7,9 @@ #include "ruby/re.h" #include +RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y); +RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow); + /* #define TIGHT_PARSER */ #define sizeof_array(o) (sizeof o / sizeof o[0]) @@ -373,44 +376,30 @@ date_zone_to_diff(VALUE str) --d; *d = '\0'; } - str = rb_str_new2(dest); + l = d - dest; + s = dest; { -#define STD " standard time" -#define DST " daylight time" - char *ss, *ds; - long sl, dl; + static const char STD[] = " standard time"; + static const char DST1[] = " daylight time"; + static const char DST2[] = " dst"; int dst = 0; - sl = RSTRING_LEN(str) - (sizeof STD - 1); - ss = RSTRING_PTR(str) + sl; - dl = RSTRING_LEN(str) - (sizeof DST - 1); - ds = RSTRING_PTR(str) + dl; - - if (sl >= 0 && strcmp(ss, STD) == 0) { - str = rb_str_new(RSTRING_PTR(str), sl); + if (l >= (int)sizeof(STD) - 1 && strcmp(d - (sizeof(STD) - 1), STD) == 0) { + l -= sizeof(STD) - 1; + s[l] = '\0'; } - else if (dl >= 0 && strcmp(ds, DST) == 0) { - str = rb_str_new(RSTRING_PTR(str), dl); + else if (l >= (int)sizeof(DST1) - 1 && strcmp(d - (sizeof(DST1) - 1), DST1) == 0) { + l -= sizeof(DST1) - 1; + s[l] = '\0'; dst = 1; } -#undef STD -#undef DST - else { -#define DST " dst" - char *ds; - long dl; - - dl = RSTRING_LEN(str) - (sizeof DST - 1); - ds = RSTRING_PTR(str) + dl; - - if (dl >= 0 && strcmp(ds, DST) == 0) { - str = rb_str_new(RSTRING_PTR(str), dl); - dst = 1; - } -#undef DST + else if (l >= (int)sizeof(DST2) - 1 && strcmp(d - (sizeof(DST2) - 1), DST2) == 0) { + l -= sizeof(DST2) - 1; + s[l] = '\0'; + dst = 1; } { - const struct zone *z = zonetab(RSTRING_PTR(str), (unsigned int)RSTRING_LEN(str)); + const struct zone *z = zonetab(s, (unsigned int)l); if (z) { int d = z->offset; if (dst) @@ -420,100 +409,60 @@ date_zone_to_diff(VALUE str) } } { - char *s, *p; - VALUE sign; - VALUE hour = Qnil, min = Qnil, sec = Qnil; - VALUE str_orig; + char *p; + int sign = 0; + unsigned long hour = 0, min = 0, sec = 0; - s = RSTRING_PTR(str); - str_orig = str; - - if (strncmp(s, "gmt", 3) == 0 || - strncmp(s, "utc", 3) == 0) + if (l > 3 && + (strncmp(s, "gmt", 3) == 0 || + strncmp(s, "utc", 3) == 0)) { s += 3; + l -= 3; + } if (issign(*s)) { - sign = rb_str_new(s, 1); + sign = *s == '-'; s++; + l--; - str = rb_str_new2(s); - - if ((p = strchr(s, ':')) != NULL) { - hour = rb_str_new(s, p - s); + hour = STRTOUL(s, &p, 10); + if (*p == ':') { s = ++p; - if ((p = strchr(s, ':')) != NULL) { - min = rb_str_new(s, p - s); + min = STRTOUL(s, &p, 10); + if (*p == ':') { s = ++p; - if ((p = strchr(s, ':')) != NULL) { - sec = rb_str_new(s, p - s); - } - else - sec = rb_str_new2(s); + sec = STRTOUL(s, &p, 10); } - else - min = rb_str_new2(s); - RB_GC_GUARD(str_orig); - goto num; - } - if (strpbrk(RSTRING_PTR(str), ",.")) { - VALUE astr = 0; - char *a, *b; - - a = ALLOCV_N(char, astr, RSTRING_LEN(str) + 1); - strcpy(a, RSTRING_PTR(str)); - b = strpbrk(a, ",."); - *b = '\0'; - b++; - - hour = cstr2num(a); - min = f_mul(rb_rational_new2 - (cstr2num(b), - f_expt(INT2FIX(10), - LONG2NUM((long)strlen(b)))), - INT2FIX(60)); - ALLOCV_END(astr); goto num; } - { - const char *cs = RSTRING_PTR(str); - long cl = RSTRING_LEN(str); - - if (cl % 2) { - if (cl >= 1) - hour = rb_str_new(&cs[0], 1); - if (cl >= 3) - min = rb_str_new(&cs[1], 2); - if (cl >= 5) - sec = rb_str_new(&cs[3], 2); - } - else { - if (cl >= 2) - hour = rb_str_new(&cs[0], 2); - if (cl >= 4) - min = rb_str_new(&cs[2], 2); - if (cl >= 6) - sec = rb_str_new(&cs[4], 2); + if (*p == ',' || *p == '.') { + char *e = 0; + p++; + min = STRTOUL(p, &e, 10) * 3600; + if (sign) { + hour = -hour; + min = -min; } + offset = rb_rational_new(INT2FIX(min), + rb_int_positive_pow(10, (int)(e - p))); + offset = f_add(INT2FIX(hour * 3600), offset); + goto ok; + } + else if (l > 2) { + size_t n; + int ov; + + if (l >= 1) + hour = ruby_scan_digits(&s[0], 2 - l % 2, 10, &n, &ov); + if (l >= 3) + min = ruby_scan_digits(&s[2 - l % 2], 2, 10, &n, &ov); + if (l >= 5) + sec = ruby_scan_digits(&s[4 - l % 2], 2, 10, &n, &ov); goto num; } num: - if (NIL_P(hour)) - offset = INT2FIX(0); - else { - if (RB_TYPE_P(hour, T_STRING)) - hour = str2num(hour); - offset = f_mul(hour, INT2FIX(3600)); - } - if (!NIL_P(min)) { - if (RB_TYPE_P(min, T_STRING)) - min = str2num(min); - offset = f_add(offset, f_mul(min, INT2FIX(60))); - } - if (!NIL_P(sec)) - offset = f_add(offset, str2num(sec)); - if (!NIL_P(sign) && - RSTRING_LEN(sign) == 1 && - *RSTRING_PTR(sign) == '-') - offset = f_negate(offset); + sec += min * 60 + hour * 3600; + if (sign) sec = -sec; + offset = INT2FIX(sec); } } } -- cgit v1.2.3