1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

date_parse.c: avoid copying

* ext/date/date_parse.c (date_zone_to_diff): get rid of copying
  the whole argument string.
This commit is contained in:
Nobuyoshi Nakada 2016-09-30 20:38:23 +09:00
parent e6a0a954c9
commit d96feee37c
No known key found for this signature in database
GPG key ID: 4BC7D6DF58D8DF60
4 changed files with 122 additions and 52 deletions

View file

@ -361,10 +361,49 @@ 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;
}
static long
shrunk_size(const char *s, long l)
{
long i, ni;
int sp = 0;
for (i = ni = 0; i < l; ++i) {
if (!isspace(s[i])) {
if (sp) ni++;
sp = 0;
ni++;
}
else {
sp = 1;
}
}
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;
}
}
return ni;
}
VALUE
@ -372,53 +411,38 @@ date_zone_to_diff(VALUE str)
{
VALUE offset = Qnil;
VALUE vbuf = 0;
long l = RSTRING_LEN(str);
const char *s = RSTRING_PTR(str);
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;
}
else {
if (isalpha((unsigned char)s[i]))
*d++ = tolower((unsigned char)s[i]);
else
*d++ = s[i];
sp = 0;
}
}
if (d > dest) {
if (*(d - 1) == ' ')
--d;
*d = '\0';
}
l = d - dest;
s = dest;
{
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;
}

View file

@ -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)

View file

@ -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];
}
}

View file

@ -178,7 +178,8 @@ class TestDateStrptime < Test::Unit::TestCase
[['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)