diff options
author | sebres <sebres@users.sourceforge.net> | 2017-01-10 22:15:36 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2017-01-10 22:15:36 (GMT) |
commit | c313bacc9f0d53d7090a7bc98b24b78ecb92d2f4 (patch) | |
tree | 541ebaaa7aa56442851f0531ae4bbaa094b9d5bc | |
parent | 3f06a6ec89b41434fe38bede870563e35b809019 (diff) | |
download | tcl-c313bacc9f0d53d7090a7bc98b24b78ecb92d2f4.zip tcl-c313bacc9f0d53d7090a7bc98b24b78ecb92d2f4.tar.gz tcl-c313bacc9f0d53d7090a7bc98b24b78ecb92d2f4.tar.bz2 |
[temp-commit]: clock scan tokenizer logic ready (still needs many rules)
caching extended (currentYearCentury, yearOfCenturySwitch, lastBaseDate ...)
-rw-r--r-- | generic/tclClock.c | 69 | ||||
-rw-r--r-- | generic/tclClockFmt.c | 218 | ||||
-rw-r--r-- | generic/tclDate.c | 1 | ||||
-rw-r--r-- | generic/tclDate.h | 88 | ||||
-rw-r--r-- | generic/tclGetDate.y | 1 | ||||
-rw-r--r-- | tests-perf/clock.perf.tcl | 98 |
6 files changed, 372 insertions, 103 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c index e00d6a2..2e7b854 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -117,6 +117,8 @@ typedef struct ClockClientData { Tcl_Obj **literals; /* Pool of object literals. */ /* Cache for current clock parameters, imparted via "configure" */ unsigned long LastTZEpoch; + int currentYearCentury; + int yearOfCenturySwitch; Tcl_Obj *SystemTimeZone; Tcl_Obj *SystemSetupTZData; Tcl_Obj *GMTSetupTimeZone; @@ -126,6 +128,9 @@ typedef struct ClockClientData { Tcl_Obj *LastUnnormSetupTimeZone; Tcl_Obj *LastSetupTimeZone; Tcl_Obj *LastSetupTZData; + /* Cache for last base (fast convert if base/tz not changed) */ + Tcl_Obj *lastBaseTimeZone; + TclDateFields lastBaseDate; /* /* [SB] TODO: back-port (from tclSE) the same date caching ... * Cache for last date (fast convert if date parsed was the same) * / @@ -325,6 +330,8 @@ TclClockInit( Tcl_IncrRefCount(data->literals[i]); } data->LastTZEpoch = 0; + data->currentYearCentury = -1; + data->yearOfCenturySwitch = -1; data->SystemTimeZone = NULL; data->SystemSetupTZData = NULL; data->GMTSetupTimeZone = NULL; @@ -335,6 +342,8 @@ TclClockInit( data->LastSetupTimeZone = NULL; data->LastSetupTZData = NULL; + data->lastBaseTimeZone = NULL; + /* * Install the commands. */ @@ -368,6 +377,8 @@ ClockConfigureClear( ClockClientData *data) { data->LastTZEpoch = 0; + data->currentYearCentury = -1; + data->yearOfCenturySwitch = -1; Tcl_UnsetObjRef(data->SystemTimeZone); Tcl_UnsetObjRef(data->SystemSetupTZData); Tcl_UnsetObjRef(data->GMTSetupTimeZone); @@ -708,11 +719,16 @@ ClockCurrentYearCentury( { ClockClientData *dataPtr = clientData; Tcl_Obj **literals = dataPtr->literals; - int year = 2000; + int year = dataPtr->currentYearCentury; - Tcl_Obj * yearObj = Tcl_ObjGetVar2(interp, - literals[LIT_CURRENTYEARCENTURY], NULL, TCL_LEAVE_ERR_MSG); - Tcl_GetIntFromObj(NULL, yearObj, &year); + if (year == -1) { + Tcl_Obj * yearObj; + year = 2000; + yearObj = Tcl_ObjGetVar2(interp, + literals[LIT_CURRENTYEARCENTURY], NULL, TCL_LEAVE_ERR_MSG); + Tcl_GetIntFromObj(NULL, yearObj, &year); + dataPtr->currentYearCentury = year; + } return year; } inline int @@ -722,11 +738,16 @@ ClockGetYearOfCenturySwitch( { ClockClientData *dataPtr = clientData; Tcl_Obj **literals = dataPtr->literals; - int year = 37; - - Tcl_Obj * yearObj = Tcl_ObjGetVar2(interp, - literals[LIT_YEAROFCENTURYSWITCH], NULL, TCL_LEAVE_ERR_MSG); - Tcl_GetIntFromObj(NULL, yearObj, &year); + int year = dataPtr->yearOfCenturySwitch; + + if (year == -1) { + Tcl_Obj * yearObj; + year = 37; + yearObj = Tcl_ObjGetVar2(interp, + literals[LIT_YEAROFCENTURYSWITCH], NULL, TCL_LEAVE_ERR_MSG); + Tcl_GetIntFromObj(NULL, yearObj, &year); + dataPtr->yearOfCenturySwitch = year; + } return year; } @@ -2557,12 +2578,27 @@ ClockScanObjCmd( if (yydate.tzData == NULL) { goto done; } - yydate.seconds = baseVal; - if (ClockGetDateFields(interp, &yydate, yydate.tzData, GREGORIAN_CHANGE_DATE) - != TCL_OK) { - goto done; + Tcl_SetObjRef(yydate.tzName, opts.timezoneObj); + + /* check cached */ + if ( dataPtr->lastBaseTimeZone == opts.timezoneObj + && dataPtr->lastBaseDate.seconds == baseVal) { + memcpy(&yydate, &dataPtr->lastBaseDate, ClockCacheableDateFieldsSize); + } else { + /* extact fields from base */ + yydate.seconds = baseVal; + if (ClockGetDateFields(interp, &yydate, yydate.tzData, GREGORIAN_CHANGE_DATE) + != TCL_OK) { + goto done; + } + /* cache last base */ + memcpy(&dataPtr->lastBaseDate, &yydate, ClockCacheableDateFieldsSize); + dataPtr->lastBaseTimeZone = opts.timezoneObj; } + /* seconds are in localSeconds (relative base date), so reset time here */ + yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; + /* If free scan */ if (opts.formatObj == NULL) { /* Use compiled version of FreeScan - */ @@ -2593,7 +2629,7 @@ ClockScanObjCmd( else { /* Use compiled version of Scan - */ - ret = ClockScan(clientData, interp, &yydate, objv[1], &opts); + ret = ClockScan(clientData, interp, info, objv[1], &opts); } if (ret != TCL_OK) { @@ -2710,6 +2746,9 @@ ClockFreeScan( if (yydate.tzData == NULL) { goto done; } + + Tcl_SetObjRef(yydate.tzName, opts->timezoneObj); + } /* on demand (lazy) assemble julianDay using new year, month, etc. */ @@ -2719,8 +2758,6 @@ ClockFreeScan( * Assemble date, time, zone into seconds-from-epoch */ - Tcl_SetObjRef(yydate.tzName, opts->timezoneObj); - if (yyHaveTime == -1) { yySeconds = 0; } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 93416af..b074681 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -400,35 +400,48 @@ Tcl_GetClockFrmScnFromObj( (tok) = (chain) + (tokCnt); \ (tokCnt) += CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE; \ } \ - *(tok) = NULL; + memset(tok, 0, sizeof(*(tok))); const char *ScnSTokenMapChars = "dmyYHMS"; -static ClockScanToken ScnSTokenMap[] = { - {CTOKT_DIGIT, 1, 2, 0}, - {CTOKT_DIGIT, 1, 2, 0}, - {CTOKT_DIGIT, 1, 2, 0}, - {CTOKT_DIGIT, 1, 4, 0}, - {CTOKT_DIGIT, 1, 2, 0}, - {CTOKT_DIGIT, 1, 2, 0}, - {CTOKT_DIGIT, 1, 2, 0}, +static ClockScanTokenMap ScnSTokenMap[] = { + {CTOKT_DIGIT, CLF_DATE, 1, 2, TclOffset(DateInfo, date.dayOfMonth), + NULL}, + {CTOKT_DIGIT, CLF_DATE, 1, 2, TclOffset(DateInfo, date.month), + NULL}, + {CTOKT_DIGIT, CLF_DATE, 1, 2, TclOffset(DateInfo, date.year), + NULL}, + {CTOKT_DIGIT, CLF_DATE, 1, 4, TclOffset(DateInfo, date.year), + NULL}, + {CTOKT_DIGIT, CLF_TIME, 1, 2, TclOffset(DateInfo, date.hour), + NULL}, + {CTOKT_DIGIT, CLF_TIME, 1, 2, TclOffset(DateInfo, date.minutes), + NULL}, + {CTOKT_DIGIT, CLF_TIME, 1, 2, TclOffset(DateInfo, date.secondOfDay), + NULL}, }; const char *ScnSpecTokenMapChars = - " %"; -static ClockScanToken ScnSpecTokenMap[] = { - {CTOKT_SPACE, 1, 0xffff, 0}, + " "; +static ClockScanTokenMap ScnSpecTokenMap[] = { + {CTOKT_SPACE, 0, 1, 0xffff, 0, + NULL}, +}; + +static ClockScanTokenMap ScnWordTokenMap = { + CTOKT_WORD, 0, 1, 0, 0, + NULL }; /* *---------------------------------------------------------------------- */ -ClockScanToken ** +ClockScanToken * ClockGetOrParseScanFormat( Tcl_Interp *interp, /* Tcl interpreter */ Tcl_Obj *formatObj) /* Format container */ { ClockFmtScnStorage *fss; - ClockScanToken **tok; + ClockScanToken *tok; if (formatObj->typePtr != &ClockFmtObjType) { if (ClockFmtObj_SetFromAny(interp, formatObj) != TCL_OK) { @@ -448,27 +461,30 @@ ClockGetOrParseScanFormat( /* if first time scanning - tokenize format */ if (fss->scnTok == NULL) { const char *strFmt; - register const char *p, *e, *cp, *word_start = NULL; + register const char *p, *e, *cp; Tcl_MutexLock(&ClockFmtMutex); fss->scnTokC = CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE; fss->scnTok = tok = ckalloc(sizeof(*tok) * CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE); - *tok = NULL; + memset(tok, 0, sizeof(*(tok))); strFmt = TclGetString(formatObj); for (e = p = strFmt, e += formatObj->length; p != e; p++) { switch (*p) { case '%': if (p+1 >= e) { - word_start = p; - continue; + goto word_tok; } p++; /* try to find modifier: */ switch (*p) { case '%': - word_start = p-1; + /* begin new word token - don't join with previous word token, + * because current mapping should be "...%%..." -> "...%..." */ + tok->map = &ScnWordTokenMap; + tok->tokWord.start = tok->tokWord.end = p; + AllocTokenInChain(tok, fss->scnTok, fss->scnTokC); continue; break; case 'E': @@ -480,10 +496,24 @@ ClockGetOrParseScanFormat( default: cp = strchr(ScnSTokenMapChars, *p); if (!cp || *cp == '\0') { - word_start = p-1; - continue; + p--; + goto word_tok; + } + tok->map = &ScnSTokenMap[cp - ScnSTokenMapChars]; + /* calculate look ahead value by standing together tokens */ + if (tok > fss->scnTok) { + ClockScanToken *prevTok = tok - 1; + unsigned int lookAhead = tok->map->minSize; + + while (prevTok >= fss->scnTok) { + if (prevTok->map->type != tok->map->type) { + break; + } + prevTok->lookAhead += lookAhead; + prevTok--; + } } - *tok = &ScnSTokenMap[cp - ScnSTokenMapChars]; + /* next token */ AllocTokenInChain(tok, fss->scnTok, fss->scnTokC); break; } @@ -494,18 +524,33 @@ ClockGetOrParseScanFormat( p--; goto word_tok; } - *tok = &ScnSpecTokenMap[cp - ScnSpecTokenMapChars]; + tok->map = &ScnSpecTokenMap[cp - ScnSpecTokenMapChars]; AllocTokenInChain(tok, fss->scnTok, fss->scnTokC); break; default: word_tok: - - continue; + if (1) { + ClockScanToken *wordTok = tok; + if (tok > fss->scnTok && (tok-1)->map == &ScnWordTokenMap) { + wordTok = tok-1; + } + wordTok->tokWord.end = p; + if (wordTok == tok) { + wordTok->tokWord.start = p; + wordTok->map = &ScnWordTokenMap; + AllocTokenInChain(tok, fss->scnTok, fss->scnTokC); + } + continue; + } } continue; + ext_tok_E: + /*******************/ + continue; + ext_tok_O: /*******************/ @@ -527,23 +572,134 @@ int ClockScan( ClientData clientData, /* Client data containing literal pool */ Tcl_Interp *interp, /* Tcl interpreter */ - TclDateFields *date, /* Date fields used for converting */ + register DateInfo *info, /* Date fields used for parsing & converting */ Tcl_Obj *strObj, /* String containing the time to scan */ ClockFmtScnCmdArgs *opts) /* Command options */ { - ClockScanToken **tok; + ClockScanToken *tok; + ClockScanTokenMap *map; + register const char *p, *x, *end; + unsigned short int flags = 0; + int ret = TCL_ERROR; if ((tok = ClockGetOrParseScanFormat(interp, opts->formatObj)) == NULL) { return TCL_ERROR; } + + /* prepare parsing */ + + yyMeridian = MER24; + + /* bypass spaces at begin of string */ + + p = TclGetString(strObj); + end = p + strObj->length; + while (p < end && isspace(UCHAR(*p))) { + p++; + } + info->dateStart = yyInput = p; + + /* parse string */ + for (; tok->map != NULL; yyInput = p, tok++) { + map = tok->map; + switch (map->type) + { + case CTOKT_DIGIT: + if (1) { + unsigned int val = 0; + int size = map->maxSize; + /* greedy find digits (look forward), corresponding pre-calculated lookAhead */ + size += tok->lookAhead; + x = yyInput + size; + while (isdigit(UCHAR(*p)) && p < x) { p++; }; + /* consider reserved (lookAhead) for next tokens */ + p -= tok->lookAhead; + size = p - yyInput; + if (size < map->minSize) { + /* missing input -> error */ + goto done; + } + /* string 2 number */ + p = yyInput; x = p + size; + while (p < x) { + val = val * 10 + (*p++ - '0'); + } + /* put number into info by offset */ + *(time_t *)(((char *)info) + map->offs) = val; + flags |= map->flags; + } + break; + case CTOKT_SPACE: + while (p < end && isspace(UCHAR(*p))) { + p++; + } + break; + case CTOKT_WORD: + x = tok->tokWord.start; + if (x == tok->tokWord.end) { /* single char word */ + if (*p != *x) { + /* no match -> error */ + goto done; + } + p++; + continue; + } + /* multi-char word */ + while (p < end && x < tok->tokWord.end && *p++ == *x++) {}; + if (x < tok->tokWord.end) { + /* no match -> error */ + goto done; + } + break; + } + } - //*********************************** + /* ignore spaces at end */ + while (p < end && isspace(UCHAR(*p))) { + p++; + } + /* check end was reached */ + if (p < end) { + /* something after last token - wrong format */ + goto done; + } - Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)tok)); - return TCL_OK; + /* invalidate result */ + if (flags & CLF_DATE) { + yydate.julianDay = CL_INVALIDATE; + + if (yyYear < 100) { + if (yyYear >= ClockGetYearOfCenturySwitch(clientData, interp)) { + yyYear -= 100; + } + yyYear += ClockCurrentYearCentury(clientData, interp); + } + yydate.era = CE; + if (!(flags & CLF_TIME)) { + yydate.localSeconds = 0; + } + } + + if (flags & CLF_TIME) { + yySeconds = ToSeconds(yyHour, yyMinutes, + yySeconds, yyMeridian); + } else { + yySeconds = yydate.localSeconds % 86400; + } + + ret = TCL_OK; + +done: + + if (ret != TCL_OK) { + Tcl_SetResult(interp, + "input string does not match supplied format", TCL_STATIC); + Tcl_SetErrorCode(interp, "CLOCK", "badInputString", NULL); + return ret; + } - return TCL_ERROR; + return ret; } diff --git a/generic/tclDate.c b/generic/tclDate.c index a47f43d..97d13b4 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -2691,7 +2691,6 @@ TclClockFreeScan( yyHaveDate = 0; yyHaveTime = 0; - yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; yyHaveZone = 0; yyTimezone = 0; yyDSTmode = DSTmaybe; diff --git a/generic/tclDate.h b/generic/tclDate.h index 49420a2..4b0b47e 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -22,60 +22,64 @@ typedef struct TclDateFields { * epoch */ Tcl_WideInt localSeconds; /* Local time expressed in nominal seconds * from the Posix epoch */ - int tzOffset; /* Time zone offset in seconds east of + time_t tzOffset; /* Time zone offset in seconds east of * Greenwich */ + time_t julianDay; /* Julian Day Number in local time zone */ + enum {BCE=1, CE=0} era; /* Era */ + time_t gregorian; /* Flag == 1 if the date is Gregorian */ + time_t year; /* Year of the era */ + time_t dayOfYear; /* Day of the year (1 January == 1) */ + time_t month; /* Month number */ + time_t dayOfMonth; /* Day of the month */ + time_t iso8601Year; /* ISO8601 week-based year */ + time_t iso8601Week; /* ISO8601 week number */ + time_t dayOfWeek; /* Day of the week */ + time_t hour; /* Hours of day (in-between time only calculation) */ + time_t minutes; /* Minutes of day (in-between time only calculation) */ + time_t secondOfDay; /* Seconds of day (in-between time only calculation) */ + Tcl_Obj *tzName; /* Time zone name (if set the refCount is incremented) */ Tcl_Obj *tzData; /* Time zone data object (internally referenced) */ - int julianDay; /* Julian Day Number in local time zone */ - enum {BCE=1, CE=0} era; /* Era */ - int gregorian; /* Flag == 1 if the date is Gregorian */ - int year; /* Year of the era */ - int dayOfYear; /* Day of the year (1 January == 1) */ - int month; /* Month number */ - int dayOfMonth; /* Day of the month */ - int iso8601Year; /* ISO8601 week-based year */ - int iso8601Week; /* ISO8601 week number */ - int dayOfWeek; /* Day of the week */ - int hour; /* Hours of day (in-between time only calculation) */ - int minutes; /* Minutes of day (in-between time only calculation) */ - int secondOfDay; /* Seconds of day (in-between time only calculation) */ } TclDateFields; +#define ClockCacheableDateFieldsSize \ + TclOffset(TclDateFields, tzName) + /* * Structure contains return parsed fields. */ typedef struct DateInfo { + const char *dateStart; + const char *dateInput; TclDateFields date; - int dateHaveDate; + time_t dateHaveDate; - int dateMeridian; - int dateHaveTime; + time_t dateMeridian; + time_t dateHaveTime; time_t dateTimezone; - int dateDSTmode; - int dateHaveZone; + time_t dateDSTmode; + time_t dateHaveZone; time_t dateRelMonth; time_t dateRelDay; time_t dateRelSeconds; - int dateHaveRel; + time_t dateHaveRel; time_t dateMonthOrdinalIncr; time_t dateMonthOrdinal; - int dateHaveOrdinalMonth; + time_t dateHaveOrdinalMonth; time_t dateDayOrdinal; time_t dateDayNumber; - int dateHaveDay; + time_t dateHaveDay; - const char *dateStart; - const char *dateInput; time_t *dateRelPointer; - int dateDigitCount; + time_t dateDigitCount; Tcl_Obj* messages; /* Error messages */ const char* separatrix; /* String separating messages */ @@ -140,8 +144,19 @@ typedef enum _MERIDIAN { #define CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE 12 +typedef struct ClockScanToken ClockScanToken; + + +typedef int ClockScanTokenProc( + DateInfo *info, + ClockScanToken *tok); + + +#define CLF_DATE (1 << 2) +#define CLF_TIME (1 << 3) + typedef enum _CLCKTOK_TYPE { - CTOKT_EOB=0, CTOKT_DIGIT, CTOKT_SPACE + CTOKT_DIGIT = 1, CTOKT_SPACE, CTOKT_WORD } CLCKTOK_TYPE; typedef struct ClockFmtScnStorage ClockFmtScnStorage; @@ -150,18 +165,29 @@ typedef struct ClockFormatToken { CLCKTOK_TYPE type; } ClockFormatToken; -typedef struct ClockScanToken { +typedef struct ClockScanTokenMap { unsigned short int type; + unsigned short int flags; unsigned short int minSize; unsigned short int maxSize; unsigned short int offs; + ClockScanTokenProc *parser; +} ClockScanTokenMap; + +typedef struct ClockScanToken { + ClockScanTokenMap *map; + unsigned int lookAhead; + struct { + const char *start; + const char *end; + } tokWord; } ClockScanToken; typedef struct ClockFmtScnStorage { int objRefCount; /* Reference count shared across threads */ - ClockScanToken **scnTok; + ClockScanToken *scnTok; unsigned int scnTokC; - ClockFormatToken **fmtTok; + ClockFormatToken *fmtTok; unsigned int fmtTokC; #if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0 ClockFmtScnStorage *nextPtr; @@ -191,8 +217,8 @@ MODULE_SCOPE ClockFmtScnStorage * Tcl_Obj *objPtr); MODULE_SCOPE int ClockScan(ClientData clientData, Tcl_Interp *interp, - TclDateFields *date, Tcl_Obj *strObj, - ClockFmtScnCmdArgs *opts); + register DateInfo *info, + Tcl_Obj *strObj, ClockFmtScnCmdArgs *opts); /* * Other externals. diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 571b7df..54087ca 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -902,7 +902,6 @@ TclClockFreeScan( yyHaveDate = 0; yyHaveTime = 0; - yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; yyHaveZone = 0; yyTimezone = 0; yyDSTmode = DSTmaybe; diff --git a/tests-perf/clock.perf.tcl b/tests-perf/clock.perf.tcl index 969e279..93a78e4 100644 --- a/tests-perf/clock.perf.tcl +++ b/tests-perf/clock.perf.tcl @@ -25,19 +25,82 @@ proc _test_get_commands {lst} { regsub -all {(?:^|\n)[ \t]*(\#[^\n]*)(?=\n\s*[\{\#])} $lst "\n{\\1}" } +proc _test_out_total {} { + upvar _ _ + + puts [string repeat ** 40] + puts [format "Total %d cases in %.2f sec.:" [llength $_(itcnt)] [expr {[llength $_(itcnt)] * $_(reptime) / 1000.0}]] + lset _(m) 0 [format %.6f [expr [join $_(ittm) +]]] + lset _(m) 2 [expr [join $_(itcnt) +]] + lset _(m) 4 [expr {[lindex $_(m) 2] / ([llength $_(itcnt)] * $_(reptime) / 1000.0)}] + puts $_(m) + puts "Average:" + lset _(m) 0 [format %.6f [expr {[lindex $_(m) 0] / [llength $_(itcnt)]}]] + lset _(m) 2 [expr {[lindex $_(m) 2] / [llength $_(itcnt)]}] + lset _(m) 4 [expr {[lindex $_(m) 2] * (1000 / $_(reptime))}] + puts $_(m) + puts [string repeat ** 40] + puts "" +} + +proc _test_run {reptime lst {outcmd {puts {$_(r)}}}} { + upvar _ _ + array set _ [list ittm {} itcnt {} itrate {} reptime $reptime] + + foreach _(c) [_test_get_commands $lst] { + puts "% [regsub -all {\n[ \t]*} $_(c) {; }]" + if {[regexp {\s*\#} $_(c)]} continue + set _(r) [if 1 $_(c)] + if {$outcmd ne {}} $outcmd + puts [set _(m) [timerate $_(c) $reptime]] + lappend _(ittm) [lindex $_(m) 0] + lappend _(itcnt) [lindex $_(m) 2] + lappend _(itrate) [lindex $_(m) 4] + puts "" + } + _test_out_total +} + proc test-scan {{reptime 1000}} { - foreach _(c) [_test_get_commands { - # Scan : date + _test_run $reptime { + # Scan : date (in gmt) {clock scan "25.11.2015" -format "%d.%m.%Y" -base 0 -gmt 1} + # Scan : date (system time zone, with base) + {clock scan "25.11.2015" -format "%d.%m.%Y" -base 0} + # Scan : date (system time zone, without base) + {clock scan "25.11.2015" -format "%d.%m.%Y"} + # Scan : greedy match + {clock scan "111" -format "%d%m%y" -base 0 -gmt 1} {clock scan "1111" -format "%d%m%y" -base 0 -gmt 1} - {**STOP** : Wed Nov 25 01:00:00 CET 2015} - # Scan : long format test (allock chain) - {clock scan "25.11.2015" -format "%d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y" -base 0 -gmt 1} - # Scan : dynamic, very long format test (create obj representation, allock chain, GC, etc): - {clock scan "25.11.2015" -format [string repeat "[incr i] %d.%m.%Y %d.%m.%Y" 10] -base 0 -gmt 1} - # Scan : again: - {clock scan "25.11.2015" -format [string repeat "[incr i -1] %d.%m.%Y %d.%m.%Y" 10] -base 0 -gmt 1} + {clock scan "11111" -format "%d%m%y" -base 0 -gmt 1} + {clock scan "111111" -format "%d%m%y" -base 0 -gmt 1} + + # Scan : date-time (in gmt) + {clock scan "25.11.2015 10:35:55" -format "%d.%m.%Y %H:%M:%S" -base 0 -gmt 1} + # Scan : date-time (system time zone with base) + {clock scan "25.11.2015 10:35:55" -format "%d.%m.%Y %H:%M:%S" -base 0} + # Scan : date-time (system time zone without base) + {clock scan "25.11.2015 10:35:55" -format "%d.%m.%Y %H:%M:%S"} + # Scan : dynamic format (cacheable) + {clock scan "25.11.2015 10:35:55" -format [string trim "%d.%m.%Y %H:%M:%S "] -base 0 -gmt 1} + + # Scan : zone only + {clock scan "CET" -format "%z"} + {clock scan "EST" -format "%z"} + #{**STOP** : Wed Nov 25 01:00:00 CET 2015} + + # # Scan : long format test (allock chain) + # {clock scan "25.11.2015" -format "%d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y %d.%m.%Y" -base 0 -gmt 1} + # # Scan : dynamic, very long format test (create obj representation, allock chain, GC, etc): + # {clock scan "25.11.2015" -format [string repeat "[incr i] %d.%m.%Y %d.%m.%Y" 10] -base 0 -gmt 1} + # # Scan : again: + # {clock scan "25.11.2015" -format [string repeat "[incr i -1] %d.%m.%Y %d.%m.%Y" 10] -base 0 -gmt 1} + } {puts [clock format $_(r) -locale en]} +} + +proc test-freescan {{reptime 1000}} { + _test_run $reptime { # FreeScan : relative date {clock scan "5 years 18 months 385 days" -base 0 -gmt 1} # FreeScan : relative date with relative weekday @@ -74,17 +137,11 @@ proc test-scan {{reptime 1000}} { {clock scan "19:18:30 MST" -base 148863600 -gmt 1 clock scan "19:18:30 EST" -base 148863600 } - }] { - puts "% [regsub -all {\n[ \t]*} $_(c) {; }]" - if {[regexp {\s*\#} $_(c)]} continue - puts [clock format [if 1 $_(c)] -locale en] - puts [timerate $_(c) $reptime] - puts "" - } + } {puts [clock format $_(r) -locale en]} } proc test-other {{reptime 1000}} { - foreach _(c) [_test_get_commands { + _test_run $reptime { # Bad zone {catch {clock scan "1 day" -timezone BAD_ZONE -locale en}} **STOP** @@ -92,18 +149,13 @@ proc test-other {{reptime 1000}} { {set i 0; time { clock scan "[incr i] - 25.11.2015" -format "$i - %d.%m.%Y" -base 0 -gmt 1 } 50} # Scan : test reusability of GC objects (format is dynamic, so tcl-obj removed with last reference) {set i 50; time { clock scan "[incr i -1] - 25.11.2015" -format "$i - %d.%m.%Y" -base 0 -gmt 1 } 50} - }] { - puts "% [regsub -all {\n[ \t]*} $_(c) {; }]" - if {[regexp {\s*\#} $_(c)]} continue - puts [if 1 $_(c)] - puts [timerate $_(c) $reptime] - puts "" } } proc test {{reptime 1000}} { puts "" test-scan $reptime + #test-freescan $reptime test-other $reptime puts \n**OK** |