summaryrefslogtreecommitdiff
path: root/ext/date
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2016-09-30 20:38:23 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-08-12 20:41:11 +0900
commitd96feee37c2d109d0103f08985e85641a23108bf (patch)
tree36f18fafde299f291a178a23185602f520f60ece /ext/date
parente6a0a954c9ef5170b8b25088455106b3748c2187 (diff)
date_parse.c: avoid copying
* ext/date/date_parse.c (date_zone_to_diff): get rid of copying the whole argument string.
Diffstat (limited to 'ext/date')
-rw-r--r--ext/date/date_parse.c112
-rw-r--r--ext/date/prereq.mk2
-rw-r--r--ext/date/zonetab.h57
3 files changed, 120 insertions, 51 deletions
diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c
index ab46bda4ad..8717850eba 100644
--- a/ext/date/date_parse.c
+++ b/ext/date/date_parse.c
@@ -361,64 +361,88 @@ do { \
#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)
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 c0c55d2c27..4aff03a4f6 100644
--- a/ext/date/prereq.mk
+++ b/ext/date/prereq.mk
@@ -1,7 +1,7 @@
.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 2dfa9b988a..c76056d548 100644
--- a/ext/date/zonetab.h
+++ b/ext/date/zonetab.h
@@ -1,5 +1,5 @@
/* 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();
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)
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)
{
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];
}
}