ruby-changes:56970
From: Nobuyoshi <ko1@a...>
Date: Mon, 12 Aug 2019 20:41:24 +0900 (JST)
Subject: [ruby-changes:56970] Nobuyoshi Nakada: d96feee37c (master): date_parse.c: avoid copying
https://git.ruby-lang.org/ruby.git/commit/?id=d96feee37c From d96feee37c2d109d0103f08985e85641a23108bf Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada <nobu@r...> Date: Fri, 30 Sep 2016 20:38:23 +0900 Subject: date_parse.c: avoid copying * ext/date/date_parse.c (date_zone_to_diff): get rid of copying the whole argument string. diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index ab46bda..8717850 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -361,64 +361,88 @@ do { \ https://github.com/ruby/ruby/blob/trunk/ext/date/date_parse.c#L361 #include "zonetab.h" static int -str_end_with(const char *s, long l, const char *w) +str_end_with_word(const char *s, long l, const char *w) { int n = (int)strlen(w); - return (l >= n && strncmp(s - n, w, n) == 0); + if (l <= n || !isspace(s[l - n - 1])) return 0; + if (strncasecmp(&s[l - n], w, n)) return 0; + do ++n; while (l > n && isspace(s[l - n - 1])); + return n; } -VALUE -date_zone_to_diff(VALUE str) +static long +shrunk_size(const char *s, long l) { - VALUE offset = Qnil; - VALUE vbuf = 0; - - long l, i; - char *s, *dest, *d; - int sp = 1; - - l = RSTRING_LEN(str); - s = RSTRING_PTR(str); - - dest = d = ALLOCV_N(char, vbuf, l + 1); - - for (i = 0; i < l; i++) { - if (isspace((unsigned char)s[i]) || s[i] == '\0') { - if (!sp) - *d++ = ' '; - sp = 1; + long i, ni; + int sp = 0; + for (i = ni = 0; i < l; ++i) { + if (!isspace(s[i])) { + if (sp) ni++; + sp = 0; + ni++; } else { - if (isalpha((unsigned char)s[i])) - *d++ = tolower((unsigned char)s[i]); - else - *d++ = s[i]; - sp = 0; + sp = 1; } } - if (d > dest) { - if (*(d - 1) == ' ') - --d; - *d = '\0'; + return ni < l ? ni : 0; +} + +static long +shrink_space(char *d, const char *s, long l) +{ + long i, ni; + int sp = 0; + for (i = ni = 0; i < l; ++i) { + if (!isspace(s[i])) { + if (sp) d[ni++] = ' '; + sp = 0; + d[ni++] = s[i]; + } + else { + sp = 1; + } } - l = d - dest; - s = dest; + return ni; +} + +VALUE +date_zone_to_diff(VALUE str) +{ + VALUE offset = Qnil; + VALUE vbuf = 0; + long l = RSTRING_LEN(str); + const char *s = RSTRING_PTR(str); + { - static const char STD[] = " standard time"; - static const char DST1[] = " daylight time"; - static const char DST2[] = " dst"; int dst = 0; + int w; - if (str_end_with(d, l, STD)) { - l -= sizeof(STD) - 1; + if ((w = str_end_with_word(s, l, "time")) > 0) { + int wtime = w; + l -= w; + if ((w = str_end_with_word(s, l, "standard")) > 0) { + l -= w; + } + else if ((w = str_end_with_word(s, l, "daylight")) > 0) { + l -= w; + dst = 1; + } + else { + l += wtime; + } } - else if (str_end_with(d, l, DST1)) { - l -= sizeof(DST1) - 1; + else if ((w = str_end_with_word(s, l, "dst")) > 0) { + l -= w; dst = 1; } - else if (str_end_with(d, l, DST2)) { - l -= sizeof(DST2) - 1; - dst = 1; + { + long sl = shrunk_size(s, l); + if (sl) { + char *d = ALLOCV_N(char, vbuf, sl); + l = shrink_space(d, s, l); + s = d; + } } { const struct zone *z = zonetab(s, (unsigned int)l); @@ -436,8 +460,8 @@ date_zone_to_diff(VALUE str) https://github.com/ruby/ruby/blob/trunk/ext/date/date_parse.c#L460 long hour = 0, min = 0, sec = 0; if (l > 3 && - (strncmp(s, "gmt", 3) == 0 || - strncmp(s, "utc", 3) == 0)) { + (strncasecmp(s, "gmt", 3) == 0 || + strncasecmp(s, "utc", 3) == 0)) { s += 3; l -= 3; } diff --git a/ext/date/prereq.mk b/ext/date/prereq.mk index c0c55d2..4aff03a 100644 --- a/ext/date/prereq.mk +++ b/ext/date/prereq.mk @@ -1,7 +1,7 @@ https://github.com/ruby/ruby/blob/trunk/ext/date/prereq.mk#L1 .SUFFIXES: .list .list.h: - gperf -E -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \ + gperf --ignore-case -E -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \ | sed -f $(top_srcdir)/tool/gperf.sed \ > $(@F) diff --git a/ext/date/zonetab.h b/ext/date/zonetab.h index 2dfa9b9..c76056d 100644 --- a/ext/date/zonetab.h +++ b/ext/date/zonetab.h @@ -1,5 +1,5 @@ https://github.com/ruby/ruby/blob/trunk/ext/date/zonetab.h#L1 /* ANSI-C code produced by gperf version 3.1 */ -/* Command-line: gperf -E -C -c -P -p -j1 -i 1 -g -o -t -N zonetab zonetab.list */ +/* Command-line: gperf --ignore-case -E -C -c -P -p -j1 -i 1 -g -o -t -N zonetab zonetab.list */ /* Computed positions: -k'1-4,$' */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ @@ -41,6 +41,51 @@ static const struct zone *zonetab(); https://github.com/ruby/ruby/blob/trunk/ext/date/zonetab.h#L41 struct zone; /* maximum key range = 434, duplicates = 0 */ +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 + }; +#endif + +#ifndef GPERF_CASE_STRNCMP +#define GPERF_CASE_STRNCMP 1 +static int +gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n) +{ + for (; n > 0;) + { + unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; + unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; + if (c1 != 0 && c1 == c2) + { + n--; + continue; + } + return (int)c1 - (int)c2; + } + return 0; +} +#endif + #ifdef __GNUC__ __inline #else @@ -59,10 +104,10 @@ hash (register const char *str, register size_t len) https://github.com/ruby/ruby/blob/trunk/ext/date/zonetab.h#L104 439, 439, 19, 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, 2, 4, 439, 439, 439, 439, 439, 8, 6, 3, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 7, 63, 53, + 439, 439, 439, 439, 439, 7, 63, 53, 2, 4, + 32, 110, 88, 78, 90, 68, 47, 108, 10, 73, + 81, 124, 3, 1, 4, 77, 116, 88, 15, 96, + 45, 5, 439, 439, 439, 439, 439, 7, 63, 53, 2, 4, 32, 110, 88, 78, 90, 68, 47, 108, 10, 73, 81, 124, 3, 1, 4, 77, 116, 88, 15, 96, 45, 5, 439, 439, 439, 439, 439, 439, @@ -884,7 +929,7 @@ zonetab (register const char *str, register size_t len) https://github.com/ruby/ruby/blob/trunk/ext/date/zonetab.h#L929 { register const char *s = o + stringpool; - if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') return &wordlist[key]; } } diff --git a/test/date/test_date_strptime.rb b/test/date/test_date_strptime.rb index bf3002a..bbc0da5 100644 --- a/test/date/test_date_strptime.rb +++ b/test/date/test_date_strptime.rb @@ -178,7 +178,8 @@ class TestDateStrptime < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/date/test_date_strptime.rb#L178 [['11:33:44 PM AMT', '%I:%M:%S %p %Z'], [nil,nil,nil,23,33,44,'AMT',nil,nil], __LINE__], [['11:33:44 P.M. AMT', '%I:%M:%S %p %Z'], [nil,nil,nil,23,33,44,'AMT',nil,nil], __LINE__], - [['fri1feb034pm+5', '%a%d%b%y%H%p%Z'], [2003,2,1,16,nil,nil,'+5',5*3600,5]] + [['fri1feb034pm+5', '%a%d%b%y%H%p%Z'], [2003,2,1,16,nil,nil,'+5',5*3600,5]], + [['E. Australia Standard Time', '%Z'], [nil,nil,nil,nil,nil,nil,'E. Australia Standard Time',10*3600,nil], __LINE__], ].each do |x, y| h = Date._strptime(*x) a = h.values_at(:year,:mon,:mday,:hour,:min,:sec,:zone,:offset,:wday) -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/