summaryrefslogtreecommitdiff
path: root/ext/date
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-10-01 08:52:42 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-10-01 08:52:42 +0000
commitc943e59603ca644ec44b1e861e12cc41db5d7ea7 (patch)
tree338a2753faaaefae599155893f2286f96aa5d4db /ext/date
parentfbe91115d12c63a221e058cbf2c797e3213df2b4 (diff)
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
Diffstat (limited to 'ext/date')
-rw-r--r--ext/date/date_parse.c169
1 files changed, 59 insertions, 110 deletions
diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c
index efb414e..7a5ed72 100644
--- a/ext/date/date_parse.c
+++ b/ext/date/date_parse.c
@@ -7,6 +7,9 @@
#include "ruby/re.h"
#include <ctype.h>
+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);
}
}
}