summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-01-10 22:07:37 (GMT)
committersebres <sebres@users.sourceforge.net>2017-01-10 22:07:37 (GMT)
commitefcfa2b368fa979b75f62e91ae673b260f2ba0c9 (patch)
treea653abcdf8c8acb4fa58a6394ee760741b36ec52 /generic
parentc093e76184fc3101487abf86878fcc8e85a77cd9 (diff)
downloadtcl-efcfa2b368fa979b75f62e91ae673b260f2ba0c9.zip
tcl-efcfa2b368fa979b75f62e91ae673b260f2ba0c9.tar.gz
tcl-efcfa2b368fa979b75f62e91ae673b260f2ba0c9.tar.bz2
[temp-commit]: tclClockFmt.c - 1st try
using "timerate" instead "time" by performance measurement tests (more precise and fixed time, so no switch of factor expected)
Diffstat (limited to 'generic')
-rw-r--r--generic/tclClock.c17
-rw-r--r--generic/tclClockFmt.c417
-rw-r--r--generic/tclDate.c12
-rw-r--r--generic/tclDate.h44
-rw-r--r--generic/tclGetDate.y1
5 files changed, 482 insertions, 9 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c
index e39e032..c869cf4 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -8,6 +8,7 @@
* Copyright 1991-1995 Karl Lehenbauer and Mark Diekhans.
* Copyright (c) 1995 Sun Microsystems, Inc.
* Copyright (c) 2004 by Kevin B. Kenny. All rights reserved.
+ * Copyright (c) 2015 by Sergey G. Brester aka sebres. All rights reserved.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -2600,9 +2601,9 @@ ClockScanObjCmd(
}
*/
- if (1) {
+ if (0) {
/* TODO: Tcled Scan proc - */
- int ret;
+ int ret;
Tcl_Obj *callargs[10];
memcpy(callargs, objv, objc * sizeof(*objv));
callargs[0] = Tcl_NewStringObj("::tcl::clock::__org_scan", -1);
@@ -2611,6 +2612,18 @@ ClockScanObjCmd(
Tcl_DecrRefCount(callargs[0]);
return ret;
}
+
+ if (1) {
+
+ ClockFmtScnStorage * fss;
+
+ if ((fss = Tcl_GetClockFrmScnFromObj(interp, opts.formatObj)) == NULL) {
+ return TCL_ERROR;
+ };
+
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)fss));
+
+ }
return TCL_OK;
}
diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c
new file mode 100644
index 0000000..fa89dde
--- /dev/null
+++ b/generic/tclClockFmt.c
@@ -0,0 +1,417 @@
+/*
+ * tclClockFmt.c --
+ *
+ * Contains the date format (and scan) routines. This code is back-ported
+ * from the time and date facilities of tclSE engine, by Serg G. Brester.
+ *
+ * Copyright (c) 2015 by Sergey G. Brester aka sebres. All rights reserved.
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#include "tclInt.h"
+#include "tclDate.h"
+
+/*
+ * Miscellaneous forward declarations and functions used within this file
+ */
+
+static void
+ClockFmtObj_DupInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
+static void
+ClockFmtObj_FreeInternalRep(Tcl_Obj *objPtr);
+static int
+ClockFmtObj_SetFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
+static void
+ClockFmtObj_UpdateString(Tcl_Obj *objPtr);
+
+
+TCL_DECLARE_MUTEX(ClockFmtMutex); /* Serializes access to common format list. */
+
+static void ClockFmtScnStorageDelete(ClockFmtScnStorage *fss);
+
+/*
+ * Clock scan and format facilities.
+ */
+
+#define TOK_CHAIN_BLOCK_SIZE 8
+
+/*
+ *----------------------------------------------------------------------
+ */
+
+#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
+
+static struct {
+ ClockFmtScnStorage *stackPtr;
+ ClockFmtScnStorage *stackBound;
+ unsigned int count;
+} ClockFmtScnStorage_GC = {NULL, NULL, 0};
+
+inline void
+ClockFmtScnStorageGC_In(ClockFmtScnStorage *entry)
+{
+ /* add new entry */
+ TclSpliceIn(entry, ClockFmtScnStorage_GC.stackPtr);
+ if (ClockFmtScnStorage_GC.stackBound == NULL) {
+ ClockFmtScnStorage_GC.stackBound = entry;
+ }
+ ClockFmtScnStorage_GC.count++;
+
+ /* if GC ist full */
+ if (ClockFmtScnStorage_GC.count > CLOCK_FMT_SCN_STORAGE_GC_SIZE) {
+
+ /* GC stack is LIFO: delete first inserted entry */
+ ClockFmtScnStorage *delEnt = ClockFmtScnStorage_GC.stackBound;
+ ClockFmtScnStorage_GC.stackBound = delEnt->prevPtr;
+ TclSpliceOut(delEnt, ClockFmtScnStorage_GC.stackPtr);
+ ClockFmtScnStorage_GC.count--;
+ delEnt->prevPtr = delEnt->nextPtr = NULL;
+ /* remove it now */
+ ClockFmtScnStorageDelete(delEnt);
+ }
+}
+inline void
+ClockFmtScnStorage_GC_Out(ClockFmtScnStorage *entry)
+{
+ TclSpliceOut(entry, ClockFmtScnStorage_GC.stackPtr);
+ ClockFmtScnStorage_GC.count--;
+ if (ClockFmtScnStorage_GC.stackBound == entry) {
+ ClockFmtScnStorage_GC.stackBound = entry->prevPtr;
+ }
+ entry->prevPtr = entry->nextPtr = NULL;
+}
+
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_HashTable FmtScnHashTable;
+static int initFmtScnHashTable = 0;
+
+inline Tcl_HashEntry *
+HashEntry4FmtScn(ClockFmtScnStorage *fss) {
+ return (Tcl_HashEntry*)(fss + 1);
+};
+inline ClockFmtScnStorage *
+FmtScn4HashEntry(Tcl_HashEntry *hKeyPtr) {
+ return (ClockFmtScnStorage*)(((char*)hKeyPtr) - sizeof(ClockFmtScnStorage));
+};
+
+/*
+ * Format storage hash (list of formats shared across all threads).
+ */
+
+static Tcl_HashEntry *
+ClockFmtScnStorageAllocProc(
+ Tcl_HashTable *tablePtr, /* Hash table. */
+ void *keyPtr) /* Key to store in the hash table entry. */
+{
+ ClockFmtScnStorage *fss;
+
+ const char *string = (const char *) keyPtr;
+ Tcl_HashEntry *hPtr;
+ unsigned int size,
+ allocsize = sizeof(ClockFmtScnStorage) + sizeof(Tcl_HashEntry);
+
+ allocsize += (size = strlen(string) + 1);
+ if (size > sizeof(hPtr->key)) {
+ allocsize -= sizeof(hPtr->key);
+ }
+
+ fss = ckalloc(allocsize);
+
+ /* initialize */
+ memset(fss, 0, sizeof(*fss));
+
+ hPtr = HashEntry4FmtScn(fss);
+ memcpy(&hPtr->key.string, string, size);
+ hPtr->clientData = 0; /* currently unused */
+
+ return hPtr;
+}
+
+static void
+ClockFmtScnStorageFreeProc(
+ Tcl_HashEntry *hPtr)
+{
+ ClockFmtScnStorage *fss = FmtScn4HashEntry(hPtr);
+ ClockScanToken *tok;
+
+ tok = fss->firstScnTok;
+ while (tok != NULL) {
+ if (tok->nextTok == tok + 1) {
+ tok++;
+ /*****************************/
+ } else {
+ tok = tok->nextTok;
+ }
+ }
+
+ ckfree(fss);
+}
+
+static void
+ClockFmtScnStorageDelete(ClockFmtScnStorage *fss) {
+ Tcl_HashEntry *hPtr = HashEntry4FmtScn(fss);
+ /*
+ * This will delete a hash entry and call "ckfree" for storage self, if
+ * some additionally handling required, freeEntryProc can be used instead
+ */
+ Tcl_DeleteHashEntry(hPtr);
+}
+
+
+/*
+ * Derivation of tclStringHashKeyType with another allocEntryProc
+ */
+
+static Tcl_HashKeyType ClockFmtScnStorageHashKeyType;
+
+
+/*
+ *----------------------------------------------------------------------
+ */
+
+static ClockFmtScnStorage *
+FindOrCreateFmtScnStorage(
+ Tcl_Interp *interp,
+ const char *strFmt)
+{
+ ClockFmtScnStorage *fss = NULL;
+ int new;
+ Tcl_HashEntry *hPtr;
+
+ Tcl_MutexLock(&ClockFmtMutex);
+
+ /* if not yet initialized */
+ if (!initFmtScnHashTable) {
+ /* initialize type */
+ memcpy(&ClockFmtScnStorageHashKeyType, &tclStringHashKeyType, sizeof(tclStringHashKeyType));
+ ClockFmtScnStorageHashKeyType.allocEntryProc = ClockFmtScnStorageAllocProc;
+ ClockFmtScnStorageHashKeyType.freeEntryProc = ClockFmtScnStorageFreeProc;
+ initFmtScnHashTable = 1;
+
+ /* initialize hash table */
+ Tcl_InitCustomHashTable(&FmtScnHashTable, TCL_CUSTOM_TYPE_KEYS,
+ &ClockFmtScnStorageHashKeyType);
+ }
+
+ /* get or create entry (and alocate storage) */
+ hPtr = Tcl_CreateHashEntry(&FmtScnHashTable, strFmt, &new);
+ if (hPtr != NULL) {
+
+ fss = FmtScn4HashEntry(hPtr);
+
+ #if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
+ /* unlink if it is currently in GC */
+ if (new == 0 && fss->objRefCount == 0) {
+ ClockFmtScnStorage_GC_Out(fss);
+ }
+ #endif
+
+ /* new reference, so increment in lock right now */
+ fss->objRefCount++;
+ }
+
+ Tcl_MutexUnlock(&ClockFmtMutex);
+
+ if (fss == NULL && interp != NULL) {
+ Tcl_AppendResult(interp, "retrieve clock format failed \"",
+ strFmt ? strFmt : "", "\"", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "EINVAL", NULL);
+ }
+
+ return fss;
+}
+
+
+/*
+ * Type definition.
+ */
+
+Tcl_ObjType ClockFmtObjType = {
+ "clock-format", /* name */
+ ClockFmtObj_FreeInternalRep, /* freeIntRepProc */
+ ClockFmtObj_DupInternalRep, /* dupIntRepProc */
+ ClockFmtObj_UpdateString, /* updateStringProc */
+ ClockFmtObj_SetFromAny /* setFromAnyProc */
+};
+
+#define SetObjClockFmtScn(objPtr, fss) \
+ objPtr->internalRep.twoPtrValue.ptr1 = fss
+#define ObjClockFmtScn(objPtr) \
+ (ClockFmtScnStorage *)objPtr->internalRep.twoPtrValue.ptr1;
+
+#define SetObjLitStorage(objPtr, lit) \
+ objPtr->internalRep.twoPtrValue.ptr2 = lit
+#define ObjLitStorage(objPtr) \
+ (ClockLitStorage *)objPtr->internalRep.twoPtrValue.ptr2;
+
+#define ClockFmtObj_SetObjIntRep(objPtr, fss, lit) \
+ objPtr->internalRep.twoPtrValue.ptr1 = fss, \
+ objPtr->internalRep.twoPtrValue.ptr2 = lit, \
+ objPtr->typePtr = &ClockFmtObjType;
+
+/*
+ *----------------------------------------------------------------------
+ */
+static void
+ClockFmtObj_DupInternalRep(srcPtr, copyPtr)
+ Tcl_Obj *srcPtr;
+ Tcl_Obj *copyPtr;
+{
+ ClockFmtScnStorage *fss = ObjClockFmtScn(srcPtr);
+ // ClockLitStorage *lit = ObjLitStorage(srcPtr);
+
+ if (fss != NULL) {
+ Tcl_MutexLock(&ClockFmtMutex);
+ fss->objRefCount++;
+ Tcl_MutexUnlock(&ClockFmtMutex);
+ }
+
+ ClockFmtObj_SetObjIntRep(copyPtr, fss, NULL);
+
+ /* if no format representation, dup string representation */
+ if (fss == NULL) {
+ copyPtr->bytes = ckalloc(srcPtr->length + 1);
+ memcpy(copyPtr->bytes, srcPtr->bytes, srcPtr->length + 1);
+ copyPtr->length = srcPtr->length;
+ }
+}
+/*
+ *----------------------------------------------------------------------
+ */
+static void
+ClockFmtObj_FreeInternalRep(objPtr)
+ Tcl_Obj *objPtr;
+{
+ ClockFmtScnStorage *fss = ObjClockFmtScn(objPtr);
+ // ClockLitStorage *lit = ObjLitStorage(objPtr);
+ if (fss != NULL) {
+ Tcl_MutexLock(&ClockFmtMutex);
+ /* decrement object reference count of format/scan storage */
+ if (--fss->objRefCount <= 0) {
+ #if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
+ /* don't remove it right now (may be reusable), just add to GC */
+ ClockFmtScnStorageGC_In(fss);
+ #else
+ /* remove storage (format representation) */
+ ClockFmtScnStorageDelete(fss);
+ #endif
+ }
+ Tcl_MutexUnlock(&ClockFmtMutex);
+ }
+ SetObjClockFmtScn(objPtr, NULL);
+ SetObjLitStorage(objPtr, NULL);
+ objPtr->typePtr = NULL;
+};
+/*
+ *----------------------------------------------------------------------
+ */
+static int
+ClockFmtObj_SetFromAny(interp, objPtr)
+ Tcl_Interp *interp;
+ Tcl_Obj *objPtr;
+{
+ ClockFmtScnStorage *fss;
+ const char *strFmt = TclGetString(objPtr);
+
+ if (!strFmt || (fss = FindOrCreateFmtScnStorage(interp, strFmt)) == NULL) {
+ return TCL_ERROR;
+ }
+
+ if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc)
+ objPtr->typePtr->freeIntRepProc(objPtr);
+ ClockFmtObj_SetObjIntRep(objPtr, fss, NULL);
+ return TCL_OK;
+};
+/*
+ *----------------------------------------------------------------------
+ */
+static void
+ClockFmtObj_UpdateString(objPtr)
+ Tcl_Obj *objPtr;
+{
+ char *name = "UNKNOWN";
+ int len;
+ ClockFmtScnStorage *fss = ObjClockFmtScn(objPtr);
+
+ if (fss != NULL) {
+ Tcl_HashEntry *hPtr = HashEntry4FmtScn(fss);
+ name = hPtr->key.string;
+ }
+ len = strlen(name);
+ objPtr->length = len,
+ objPtr->bytes = ckalloc((size_t)++len);
+ if (objPtr->bytes)
+ memcpy(objPtr->bytes, name, len);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetClockFrmScnFromObj --
+ *
+ * Returns a clock format/scan representation of (*objPtr), if possible.
+ * If something goes wrong, NULL is returned, and if interp is non-NULL,
+ * an error message is written there.
+ *
+ * Results:
+ * Valid representation of type ClockFmtScnStorage.
+ *
+ * Side effects:
+ * Caches the ClockFmtScnStorage reference as the internal rep of (*objPtr)
+ * and in global hash table, shared across all threads.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ClockFmtScnStorage *
+Tcl_GetClockFrmScnFromObj(
+ Tcl_Interp *interp,
+ Tcl_Obj *objPtr)
+{
+ ClockFmtScnStorage *fss;
+
+ if (objPtr->typePtr != &ClockFmtObjType) {
+ if (ClockFmtObj_SetFromAny(interp, objPtr) != TCL_OK) {
+ return NULL;
+ }
+ }
+
+ fss = ObjClockFmtScn(objPtr);
+
+ if (fss == NULL) {
+ const char *strFmt = TclGetString(objPtr);
+ fss = FindOrCreateFmtScnStorage(interp, strFmt);
+ }
+
+ return fss;
+}
+
+
+static void
+Tcl_GetClockFrmScnFinalize()
+{
+#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
+ /* clear GC */
+ ClockFmtScnStorage_GC.stackPtr = NULL;
+ ClockFmtScnStorage_GC.stackBound = NULL;
+ ClockFmtScnStorage_GC.count = 0;
+#endif
+ if (initFmtScnHashTable) {
+ Tcl_DeleteHashTable(&FmtScnHashTable);
+ }
+ Tcl_MutexFinalize(&ClockFmtMutex);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */
diff --git a/generic/tclDate.c b/generic/tclDate.c
index a31e0fc..389b245 100644
--- a/generic/tclDate.c
+++ b/generic/tclDate.c
@@ -570,12 +570,12 @@ static const yytype_int8 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 176, 176, 177, 180, 183, 186, 189, 192, 195,
- 198, 202, 207, 210, 216, 222, 230, 236, 247, 251,
- 255, 261, 265, 269, 273, 277, 283, 287, 292, 297,
- 302, 307, 311, 316, 320, 325, 332, 336, 342, 351,
- 360, 370, 384, 389, 392, 395, 398, 401, 404, 409,
- 412, 417, 421, 425, 431, 449, 452
+ 0, 177, 177, 178, 181, 184, 187, 190, 193, 196,
+ 199, 203, 208, 211, 217, 223, 231, 237, 248, 252,
+ 256, 262, 266, 270, 274, 278, 284, 288, 293, 298,
+ 303, 308, 312, 317, 321, 326, 333, 337, 343, 352,
+ 361, 371, 385, 390, 393, 396, 399, 402, 405, 410,
+ 413, 418, 422, 426, 432, 450, 453
};
#endif
diff --git a/generic/tclDate.h b/generic/tclDate.h
index 6ba9620..c3c362a 100644
--- a/generic/tclDate.h
+++ b/generic/tclDate.h
@@ -66,13 +66,55 @@ typedef enum _MERIDIAN {
} MERIDIAN;
/*
+ * Clock scan and format facilities.
+ */
+
+#define CLOCK_FMT_SCN_STORAGE_GC_SIZE 32
+
+
+typedef struct ClockFormatToken ClockFormatToken;
+typedef struct ClockScanToken ClockScanToken;
+typedef struct ClockFmtScnStorage ClockFmtScnStorage;
+
+typedef struct ClockFormatToken {
+ ClockFormatToken *nextTok;
+} ClockFormatToken;
+
+typedef struct ClockScanToken {
+ ClockScanToken *nextTok;
+} ClockScanToken;
+
+typedef struct ClockFmtScnStorage {
+ int objRefCount; /* Reference count shared across threads */
+ ClockScanToken *firstScnTok;
+ ClockFormatToken *firstFmtTok;
+#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
+ ClockFmtScnStorage *nextPtr;
+ ClockFmtScnStorage *prevPtr;
+#endif
+/* +Tcl_HashEntry hashEntry /* ClockFmtScnStorage is a derivate of Tcl_HashEntry,
+ * stored by offset +sizeof(self) */
+} ClockFmtScnStorage;
+
+typedef struct ClockLitStorage {
+ int dummy;
+} ClockLitStorage;
+
+/*
* Prototypes of module functions.
*/
MODULE_SCOPE time_t ToSeconds(time_t Hours, time_t Minutes,
time_t Seconds, MERIDIAN Meridian);
-MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info);
+MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info);
+
+/* tclClockFmt.c module declarations */
+
+MODULE_SCOPE ClockFmtScnStorage *
+ Tcl_GetClockFrmScnFromObj(Tcl_Interp *interp,
+ Tcl_Obj *objPtr);
+
/*
* Other externals.
diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y
index ac781ad..d500d6b 100644
--- a/generic/tclGetDate.y
+++ b/generic/tclGetDate.y
@@ -9,6 +9,7 @@
*
* Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 2015 Sergey G. Brester aka sebres.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.