inline char *
Memcpy(char *dst, char *src, size_t length)
{
if (dst == NULL) {
dst = (char *) ckalloc(length);
}
memcpy(dst, src, length);
return dst;
}
inline void stateInitialiseHash(Tcl_HashTable *);
inline Tcl_Obj *stateBless(Tcl_Obj *, Tcl_HashTable *);
inline Tcl_Obj *stateGet(Tcl_Interp *, Tcl_Obj *);
inline void stateInvalidate(Tcl_HashTable *);
/* Blessed (semi-auto cleaned) simulator state references */
static int stateSet(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void statePrint(Tcl_Obj *objPtr);
static void stateDup(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr);
static void stateFree(Tcl_Obj *objPtr);
static struct Tcl_ObjType stateType = {
"Cleaned Reference",
stateFree, stateDup, statePrint, stateSet
};
static int
stateSet(
Tcl_Interp *interp,
Tcl_Obj *objPtr)
{
if (interp) {
Tcl_AppendResult(interp, "cannot (re)build object of type \"",
stateType.name, "\"", NULL);
}
return TCL_ERROR;
}
static void
statePrint(
Tcl_Obj *objPtr)
{
Tcl_Obj *contents = objPtr->internalRep.twoPtrValue.ptr1;
char *bytes = Tcl_GetStringFromObj(contents, &objPtr->length);
objPtr->bytes = Memcpy(NULL, bytes, objPtr->length+1);
}
static void
stateDup(
Tcl_Obj *srcPtr,
Tcl_Obj *dupPtr)
{
Tcl_Obj *contents = srcPtr->internalRep.twoPtrValue.ptr1;
Tcl_HashTable *hash = srcPtr->internalRep.twoPtrValue.ptr2;
Tcl_HashEntry *hent;
int isNew;
dupPtr->internalRep.twoPtrValue.ptr1 = contents;
dupPtr->internalRep.twoPtrValue.ptr2 = hash;
dupPtr->typePtr = &stateType;
Tcl_IncrRefCount(contents);
hent = Tcl_CreateHashEntry(hash, (char *)dupPtr, &isNew);
if (hent) {
Tcl_SetHashValue(hent, dupPtr);
}
}
static void
stateFree(
Tcl_Obj *objPtr)
{
Tcl_Obj *contents = objPtr->internalRep.twoPtrValue.ptr1;
Tcl_HashTable *hash = objPtr->internalRep.twoPtrValue.ptr2;
Tcl_HashEntry *hent;
Tcl_DecrRefCount(contents);
hent = Tcl_FindHashEntry(hash, (char *)objPtr);
if (hent) {
Tcl_DeleteHashEntry(hent);
}
}
/* Invalidate all state-reference objects referred to in the given
* hash table, nuking the hash at the same time. */
inline void
stateInvalidate(
Tcl_HashTable *hash)
{
Tcl_HashSearch hsearch;
Tcl_HashEntry *hent;
hent = Tcl_FirstHashEntry(hash, &hsearch);
for (; hent ; hent=Tcl_NextHashEntry(&hsearch)) {
Tcl_Obj *objPtr = Tcl_GetHashValue(hent);
Tcl_Obj *contents = objPtr->internalRep.twoPtrValue.ptr1;
if (!objPtr->bytes) {
/* Make sure that there is still something there for users to see */
statePrint(objPtr);
}
/* Delete the contents - this is the crucial bit */
Tcl_DecrRefCount(contents);
/* Mark the object as untyped */
objPtr->typePtr = NULL;
}
Tcl_DeleteHashTable(hash);
}
/* Given a state object (AKA a complex list thingy) make it into a
* blessed state-reference which ensures that it will be invalidated
* at the correct time. */
inline Tcl_Obj *
stateBless(
Tcl_Obj *stateObject,
Tcl_HashTable *hash)
{
Tcl_Obj *newObj = Tcl_NewObj();
Tcl_HashEntry *hent;
int isNew;
/* Get rid of anything present by default in new objects */
if (newObj->bytes) {
Tcl_InvalidateStringRep(newObj);
}
/* Make the internal representation */
newObj->typePtr = &stateType;
newObj->internalRep.twoPtrValue.ptr1 = stateObject;
Tcl_IncrRefCount(stateObject);
newObj->internalRep.twoPtrValue.ptr2 = hash;
/* Store a reference to the object in the hash */
hent = Tcl_CreateHashEntry(hash, (char *)newObj, &isNew);
if (hent) {
Tcl_SetHashValue(hent, newObj);
}
return newObj;
}
/* Set up the state-reference hash table */
inline void
stateInitialiseHash(
Tcl_HashTable *hash)
{
Tcl_InitHashTable(hash, TCL_ONE_WORD_KEYS);
}
/* Get a state reference, but only if it is blessed. Error otherwise */
inline Tcl_Obj *
stateGet(
Tcl_Interp *interp,
Tcl_Obj *objPtr)
{
if (objPtr->typePtr != &stateType &&
Tcl_ConvertToType(interp, objPtr, &stateType) != TCL_OK) {
return NULL;
}
return objPtr->internalRep.twoPtrValue.ptr1;
}Still to come; the explanation for all this!DKF
tcl_obj

