/* DataDraw Copyright(C) 1992-2006 Bill Cox This program can be distributed under the terms of the GNU Library GPL. See the file COPYING.LIB. */ #include "dv.h" static char *dvPrefix; /*-------------------------------------------------------------------------------------------------- Write a function to resize a hash table. --------------------------------------------------------------------------------------------------*/ static void writeHashTableResizeFunction( dvRelationship relationship) { dvClass parentClass = dvRelationshipGetParentClass(relationship); dvClass childClass = dvRelationshipGetChildClass(relationship); char *propName = utSprintf("%s%sTable", dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); utSym propSym = utSymCreate(propName); dvProperty tablesProp = dvClassFindProperty(parentClass, propSym); utAssert(tablesProp != dvPropertyNull); dvWrtemp(dvFile, "static void add%1%2%3ToHashTable(%4%1 %1, %5%3 _%3);\n" "/*----------------------------------------------------------------------------------------\n" " Increase the size of the hash table.\n" "----------------------------------------------------------------------------------------*/\n" "static void resize%1%2%3HashTable(\n" " %4%1 %1)\n" "{\n" " %5%3 _%3;\n" " %5%3 *%3s;\n" " uint32 num%3s = %0%1GetNum%2%3Table(%1) << 1;\n" "\n" " if(num%3s == 0) {\n" " num%3s = 2;\n" " %0%1Alloc%2%3Tables(%1, 2);\n" " } else {\n" " %0%1Resize%2%3Tables(%1, num%3s);\n" " }\n" " %3s = %0%1Get%2%3Tables(%1);\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); if(dvClassUndo(parentClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %5, %0%1Get%2%3Tables(%1) - %0%1s.%4, %0%1GetNum%2%3Table(%1), true);\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvPropertyGetName(tablesProp), dvPropertyGetID(tablesProp)); } dvWrtemp(dvFile, " /* Zero out the table */\n" " while(num%0s-- != 0) {\n" " *%0s++ = %1%0Null;\n" " }\n", dvClassGetName(childClass), dvClassGetPrefix(childClass)); if(dvClassRedo(parentClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %5, %0%1Get%2%3Tables(%1) - %0%1s.%4, %0%1GetNum%2%3Table(%1), false);\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvPropertyGetName(tablesProp), dvPropertyGetID(tablesProp)); } dvWrtemp(dvFile, " %0%1SetNum%2%3(%1, 0);\n" " %0Foreach%1%2%3(%1, _%3) {\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); if(dvRelationshipHashedByName(relationship)) { dvWrtemp(dvFile, " if(%0%3Get%2Sym(_%3) != utSymNull) {\n" " add%1%2%3ToHashTable(%1, _%3);\n" " }\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); } else { dvWrtemp(dvFile, " add%1%2%3ToHashTable(%1, _%3);\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); } dvWrtemp(dvFile, " } %0End%1%2%3;\n" "}\n\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); } /*-------------------------------------------------------------------------------------------------- Write a hash function for just this key. --------------------------------------------------------------------------------------------------*/ static void writeKeyHash( dvKey key, bool useParamName) { dvProperty property = dvKeyGetProperty(key); dvClass childClass = dvPropertyGetClass(property); dvClass pointerClass; dvPropertyType type = dvPropertyGetType(property);; char *accessMacro; if(useParamName) { accessMacro = dvPropertyGetName(property); } else { if(type == PROP_BOOL || type == PROP_BIT) { accessMacro = utSprintf("%s%sGet%s(_%s)", dvPrefix, dvClassGetName(childClass), dvPropertyGetName(property), dvClassGetName(childClass)); } else { accessMacro = utSprintf("%s%sGet%s(_%s)", dvPrefix, dvClassGetName(childClass), dvPropertyGetName(property), dvClassGetName(childClass)); } } switch(type) { case PROP_UINT: case PROP_INT: case PROP_CHAR: case PROP_ENUM: case PROP_BOOL: case PROP_BIT: dvWrtemp(dvFile, "(uint32)%0", accessMacro); break; case PROP_FLOAT: dvWrtemp(dvFile, "utHashFloat(%0)", accessMacro); break; case PROP_DOUBLE: dvWrtemp(dvFile, "utHashDouble(%0)", accessMacro); break; case PROP_SYM: dvWrtemp(dvFile, "utSymGetHashValue(%0)", accessMacro); break; case PROP_TYPEDEF: dvWrtemp(dvFile, "utHashData(&%0, sizeof(%1))", accessMacro, dvPropertyGetTypeName(property)); break; case PROP_POINTER: pointerClass = dvPropertyGetClassProp(property); dvWrtemp(dvFile, "%1%22Index(%0)", accessMacro, dvClassGetPrefix(pointerClass), dvClassGetName(pointerClass)); break; default: utExit("Unexpected key type"); } } /*-------------------------------------------------------------------------------------------------- Write a hash function for this key, and all the next keys on the relationship. --------------------------------------------------------------------------------------------------*/ static void writeHashFunction( dvKey key, bool useParamName) { dvKey nextKey = dvKeyGetNextPropertyKey(key); if(nextKey == dvKeyNull) { writeKeyHash(key, useParamName); return; } dvWrtemp(dvFile, "utCombineHashes("); writeKeyHash(key, useParamName); dvWrtemp(dvFile, ", "); writeHashFunction(nextKey, useParamName); dvWrtemp(dvFile, ")"); } /*-------------------------------------------------------------------------------------------------- Write a function to add an element to a hash table. --------------------------------------------------------------------------------------------------*/ static void writeHashTableAddFunction( dvRelationship relationship) { dvClass parentClass = dvRelationshipGetParentClass(relationship); dvClass childClass = dvRelationshipGetChildClass(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Add the %2%3 to the %1. If the table is near full, build a new one twice\n" " as big, delete the old one, and return the new one.\n" "----------------------------------------------------------------------------------------*/\n" "static void add%1%2%3ToHashTable(\n" " %4%1 %1,\n" " %5%3 _%3)\n" "{\n" " %5%3 next%3;\n" " uint32 index;\n" "\n" " if(%0%1GetNum%2%3(%1) >= %0%1GetNum%2%3Table(%1)) {\n" " resize%1%2%3HashTable(%1);\n" /* This adds _%3 to the hash table */ " return;\n" " }\n" " index = (%0%1GetNum%2%3Table(%1) - 1) & ", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); writeHashFunction(dvRelationshipGetFirstKey(relationship), false); dvWrtemp(dvFile, ";\n" " next%3 = %0%1Geti%2%3Table(%1, index);\n" " %0%3SetNextTable%1%2%3(_%3, next%3);\n" " %0%1Seti%2%3Table(%1, index, _%3);\n" " %0%1SetNum%2%3(%1, %0%1GetNum%2%3(%1) + 1);\n" "}\n\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); } /*-------------------------------------------------------------------------------------------------- Write a function to remove an element from a hash table. --------------------------------------------------------------------------------------------------*/ static void writeHashTableRemoveFunction( dvRelationship relationship) { dvClass parentClass = dvRelationshipGetParentClass(relationship); dvClass childClass = dvRelationshipGetChildClass(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Remove the %2%3 from the hash table.\n" "----------------------------------------------------------------------------------------*/\n" "static void remove%1%2%3FromHashTable(\n" " %4%1 %1,\n" " %5%3 _%3)\n" "{\n" " uint32 index = (%0%1GetNum%2%3Table(%1) - 1) & ", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); writeHashFunction(dvRelationshipGetFirstKey(relationship), false); dvWrtemp(dvFile, ";\n" " %5%3 prev%3, next%3;\n" " \n" " next%3 = %0%1Geti%2%3Table(%1, index);\n" " if(next%3 == _%3) {\n" " %0%1Seti%2%3Table(%1, index, %0%3GetNextTable%1%2%3(next%3));\n" " } else {\n" " do {\n" " prev%3 = next%3;\n" " next%3 = %0%3GetNextTable%1%2%3(next%3);\n" " } while(next%3 != _%3);\n" " %0%3SetNextTable%1%2%3(prev%3, %0%3GetNextTable%1%2%3(_%3));\n" " }\n" " %0%1SetNum%2%3(%1, %0%1GetNum%2%3(%1) - 1);\n" " %0%3SetNextTable%1%2%3(_%3, %5%3Null);\n" "}\n\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); } /*-------------------------------------------------------------------------------------------------- Write the hash key parameters to the find function. --------------------------------------------------------------------------------------------------*/ static void writeHashKeyParameters( dvRelationship relationship) { dvProperty property; dvKey key; dvForeachRelationshipKey(relationship, key) { property = dvKeyGetProperty(key); dvWrtemp(dvFile, ",\n %0 %1", dvPropertyGetTypeName(property), dvPropertyGetName(property)); } dvEndRelationshipKey; } /*-------------------------------------------------------------------------------------------------- Write a hash key match conditional expression. --------------------------------------------------------------------------------------------------*/ static void writeHashKeyMatch( dvRelationship relationship) { dvClass childClass = dvRelationshipGetChildClass(relationship); dvProperty property; dvPropertyType type; dvKey key; bool isFirst = true; char *getString; dvForeachRelationshipKey(relationship, key) { if(!isFirst) { dvWrtemp(dvFile, " && "); } isFirst = false; property = dvKeyGetProperty(key); type = dvPropertyGetType(property); getString = type == PROP_BIT || type == PROP_BOOL? "" : "Get"; dvWrtemp(dvFile, "%0%1%3%2(_%1) == %2", dvPrefix, dvClassGetName(childClass), dvPropertyGetName(property), getString); } dvEndRelationshipKey; } /*-------------------------------------------------------------------------------------------------- Write a query by key lookup function for a hash-table relationship. --------------------------------------------------------------------------------------------------*/ static void writeFindFunction( dvRelationship relationship) { dvClass parentClass = dvRelationshipGetParentClass(relationship); dvClass childClass = dvRelationshipGetChildClass(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Find the %2%3 from the %1 and its hash key.\n" "----------------------------------------------------------------------------------------*/\n" "%5%3 %0%1Find%2%3(\n" " %4%1 %1", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); writeHashKeyParameters(relationship); dvWrtemp(dvFile, ")\n" "{\n" " uint32 mask = %0%1GetNum%2%3Table(%1) - 1;\n" " %5%3 _%3;\n" "\n" " if(mask + 1 != 0) {\n" " _%3 = %0%1Geti%2%3Table(%1, ", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); writeHashFunction(dvRelationshipGetFirstKey(relationship), true); dvWrtemp(dvFile, " & mask);\n" " while(_%3 != %5%3Null) {\n" " if(", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); writeHashKeyMatch(relationship); dvWrtemp(dvFile, ") {\n" " return _%3;\n" " }\n" " _%3 = %0%3GetNextTable%1%2%3(_%3);\n" " }\n" " }\n" " return %5%3Null;\n" "}\n\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass)); } /*-------------------------------------------------------------------------------------------------- Write a function to rename the object. --------------------------------------------------------------------------------------------------*/ static void writeRenameFunction( dvRelationship relationship) { dvClass parentClass = dvRelationshipGetParentClass(relationship); dvClass childClass = dvRelationshipGetChildClass(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Find the %2%3 from the %1 and its name.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Rename%2%3(\n" " %4%1 %1,\n" " %5%3 _%3,\n" " utSym sym)\n" "{\n" " if(%0%3Get%2Sym(_%3) != utSymNull) {\n" " remove%1%2%3FromHashTable(%1, _%3);\n" " }\n" " %0%3Set%2Sym(_%3, sym);\n" " if(sym != utSymNull) {\n" " add%1%2%3ToHashTable(%1, _%3);\n" " }\n" "}\n\n", dvPrefix, dvClassGetName(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(parentClass), dvClassGetPrefix(childClass), dvRelationshipGetParentLabel(relationship)); } /*-------------------------------------------------------------------------------------------------- Write an add relationship routine for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassInsertFunction( dvClass theClass, dvRelationship relationship) { char *parentName = dvClassGetName(theClass); dvClass childClass = dvRelationshipGetChildClass(relationship); char *childName = dvClassGetName(childClass); dvRelationshipType type = dvRelationshipGetType(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Add the %2%3 to the head of the list on the %1.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Insert%2%3(\n" " %4%1 %1,\n" " %5%3 _%3)\n" "{\n" "#if defined(DD_DEBUG)\n" " if(%1 == %4%1Null) {\n" " utExit(\"Non-existent %1\");\n" " }\n" " if(_%3 == %5%3Null) {\n" " utExit(\"Non-existent %3\");\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " if(%0%2Get%4%1(_%2) != %3%1Null) {\n" " utExit(\"Attempting to add %2 to %1 twice\");\n" " }\n", dvPrefix, parentName, childName, dvClassGetPrefix(theClass), dvRelationshipGetParentLabel(relationship)); } dvWrtemp(dvFile, "#endif\n"); if(type == REL_DOUBLY_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, " %0%3SetNext%1%2%3(_%3, %0%1GetFirst%2%3(%1));\n" " if(%0%1GetFirst%2%3(%1) != %5%3Null) {\n" " %0%3SetPrev%1%2%3(%0%1GetFirst%2%3(%1), _%3);\n" " }\n" " %0%1SetFirst%2%3(%1, _%3);\n" " %0%3SetPrev%1%2%3(_%3, %5%3Null);\n" " if(%0%1GetLast%2%3(%1) == %5%3Null) {\n" " %0%1SetLast%2%3(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } else { dvWrtemp(dvFile, " %0%3SetNext%1%2%3(_%3, %0%1GetFirst%2%3(%1));\n" " %0%1SetFirst%2%3(%1, _%3);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(type == REL_TAIL_LINKED) { dvWrtemp(dvFile, " if(%0%1GetLast%2%3(%1) == %5%3Null) {\n" " %0%1SetLast%2%3(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } } if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " %0%3Set%2%1(_%3, %1);\n", dvPrefix, parentName, dvRelationshipGetParentLabel(relationship), childName); } if(type == REL_HASHED) { if(dvRelationshipHashedByName(relationship)) { dvWrtemp(dvFile, " if(%0%3Get%2Sym(_%3) != utSymNull) {\n" " add%1%2%3ToHashTable(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } else { dvWrtemp(dvFile, " add%1%2%3ToHashTable(%1, _%3);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write an append relationship routine for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassAppendFunction( dvClass theClass, dvRelationship relationship) { char *parentName = dvClassGetName(theClass); dvClass childClass = dvRelationshipGetChildClass(relationship); char *childName = dvClassGetName(childClass); dvRelationshipType type = dvRelationshipGetType(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Add the %2%3 to the end of the list on the %1.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Append%2%3(\n" " %4%1 %1,\n" " %5%3 _%3)\n" "{\n" "#if defined(DD_DEBUG)\n" " if(%1 == %4%1Null) {\n" " utExit(\"Non-existent %1\");\n" " }\n" " if(_%3 == %5%3Null) {\n" " utExit(\"Non-existent %3\");\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " if(%0%2Get%4%1(_%2) != %3%1Null) {\n" " utExit(\"Attempting to add %2 to %1 twice\");\n" " }\n", dvPrefix, parentName, childName, dvClassGetPrefix(theClass), dvRelationshipGetParentLabel(relationship)); } dvWrtemp(dvFile, "#endif\n"); if(type == REL_DOUBLY_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, " %0%3SetPrev%1%2%3(_%3, %0%1GetLast%2%3(%1));\n" " if(%0%1GetLast%2%3(%1) != %5%3Null) {\n" " %0%3SetNext%1%2%3(%0%1GetLast%2%3(%1), _%3);\n" " }\n" " %0%1SetLast%2%3(%1, _%3);\n" " %0%3SetNext%1%2%3(_%3, %5%3Null);\n" " if(%0%1GetFirst%2%3(%1) == %5%3Null) {\n" " %0%1SetFirst%2%3(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } else { dvWrtemp(dvFile, " if(%0%1GetLast%2%3(%1) != %5%3Null) {\n" " %0%3SetNext%1%2%3(%0%1GetLast%2%3(%1), _%3);\n" " } else {\n" " %0%1SetFirst%2%3(%1, _%3);\n" " }\n" " %0%1SetLast%2%3(%1, _%3);\n" " %0%3SetNext%1%2%3(_%3, %5%3Null);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " %0%3Set%2%1(_%3, %1);\n", dvPrefix, parentName, dvRelationshipGetParentLabel(relationship), childName); } if(type == REL_HASHED) { if(dvRelationshipHashedByName(relationship)) { dvWrtemp(dvFile, " if(%0%3Get%2Sym(_%3) != utSymNull) {\n" " add%1%2%3ToHashTable(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } else { dvWrtemp(dvFile, " add%1%2%3ToHashTable(%1, _%3);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write an insert after relationship routine for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassInsertAfter( dvClass theClass, dvRelationship relationship) { char *parentName = dvClassGetName(theClass); dvClass childClass = dvRelationshipGetChildClass(relationship); char *childName = dvClassGetName(childClass); dvRelationshipType type = dvRelationshipGetType(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Insert the %2%3 to the %1 after the previous %2%3.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1InsertAfter%2%3(\n" " %4%1 %1,\n" " %5%3 prev%3,\n" " %5%3 _%3)\n" "{\n" " %5%3 next%3 = %0%3GetNext%1%2%3(prev%3);\n" "\n" "#if defined(DD_DEBUG)\n" " if(%1 == %4%1Null) {\n" " utExit(\"Non-existent %1\");\n" " }\n" " if(_%3 == %5%3Null) {\n" " utExit(\"Non-existent %3\");\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " if(%0%2Get%4%1(_%2) != %3%1Null) {\n" " utExit(\"Attempting to add %2 to %1 twice\");\n" " }\n", dvPrefix, parentName, childName, dvClassGetPrefix(theClass), dvRelationshipGetParentLabel(relationship)); } dvWrtemp(dvFile, "#endif\n"); dvWrtemp(dvFile, " %0%3SetNext%1%2%3(_%3, next%3);\n" " %0%3SetNext%1%2%3(prev%3, _%3);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(type == REL_DOUBLY_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, " %0%3SetPrev%1%2%3(_%3, prev%3);\n" " if(next%3 != %5%3Null) {\n" " %0%3SetPrev%1%2%3(next%3, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } if(type == REL_TAIL_LINKED || type == REL_DOUBLY_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, " if(%0%1GetLast%2%3(%1) == prev%3) {\n" " %0%1SetLast%2%3(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " %0%3Set%2%1(_%3, %1);\n", dvPrefix, parentName, dvRelationshipGetParentLabel(relationship), childName); } if(type == REL_HASHED) { if(dvRelationshipHashedByName(relationship)) { dvWrtemp(dvFile, " if(%0%3Get%2Sym(_%3) != utSymNull) {\n" " add%1%2%3ToHashTable(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } else { dvWrtemp(dvFile, " add%1%2%3ToHashTable(%1, _%3);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write a delete relationship routine for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassRemoveFunction( dvClass theClass, dvRelationship relationship) { char *parentName = dvClassGetName(theClass); dvClass childClass = dvRelationshipGetChildClass(relationship); dvRelationshipType type = dvRelationshipGetType(relationship); char *childName = dvClassGetName(childClass); char *childLabel = dvRelationshipGetChildLabel(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Remove the %2%3 from the %1.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Remove%2%3(\n" " %4%1 %1,\n" " %5%3 _%3)\n" "{\n" " %5%3 p%3, n%3;\n" "\n", dvPrefix, parentName, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); dvWrtemp(dvFile, "#if defined(DD_DEBUG)\n" " if(_%3 == %5%3Null) {\n" " utExit(\"Non-existent %3\");\n" " }\n", dvPrefix, parentName, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " if(%0%3Get%1%2(_%3) != %4%2Null && %0%3Get%1%2(_%3) != %2) {\n" " utExit(\"Delete %3 from non-owning %2\");\n" " }\n", dvPrefix, dvRelationshipGetParentLabel(relationship), parentName, childName, dvClassGetPrefix(theClass)); } if(type == REL_DOUBLY_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, "#endif\n" " n%3 = %0%3GetNext%1%2%3(_%3);\n" " p%3 = %0%3GetPrev%1%2%3(_%3);\n" " if(p%3 != %5%3Null) {\n" " %0%3SetNext%1%2%3(p%3, n%3);\n" " } else if(%0%1GetFirst%2%3(%1) == _%3) {\n" " %0%1SetFirst%2%3(%1, n%3);\n" " }\n" " if(n%3 != %5%3Null) {\n" " %0%3SetPrev%1%2%3(n%3, p%3);\n" " } else if(%0%1GetLast%2%3(%1) == _%3) {\n" " %0%1SetLast%2%3(%1, p%3);\n" " }\n" " %0%3SetNext%1%2%3(_%3, %5%3Null);\n" " %0%3SetPrev%1%2%3(_%3, %5%3Null);\n", dvPrefix, parentName, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } else { dvWrtemp(dvFile, "#endif\n" " p%3 = %5%3Null;\n" " for(n%3 = %0%1GetFirst%2%3(%1); n%3 != %5%3Null && n%3 != _%3;\n" " n%3 = %0%3GetNext%1%2%3(n%3)) {\n" " p%3 = n%3;\n" " }\n" " if(p%3 != %5%3Null) {\n" " %0%3SetNext%1%2%3(p%3, %0%3GetNext%1%2%3(_%3));\n" " } else {\n" " %0%1SetFirst%2%3(%1, %0%3GetNext%1%2%3(_%3));\n" " }\n" " %0%3SetNext%1%2%3(_%3, %5%3Null);\n", dvPrefix, parentName, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(type == REL_TAIL_LINKED) { dvWrtemp(dvFile, " if(%0%1GetLast%2%3(%1) == _%3) {\n" " %0%1SetLast%2%3(%1, p%3);\n" " }\n", dvPrefix, parentName, childLabel, childName); } } if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " %0%3Set%1%2(_%3, %4%2Null);\n", dvPrefix, dvRelationshipGetParentLabel(relationship), parentName, childName, dvClassGetPrefix(theClass)); } if(type == REL_HASHED) { if(dvRelationshipHashedByName(relationship)) { dvWrtemp(dvFile, " if(%0%3Get%2Sym(_%3) != utSymNull) {\n" " remove%1%2%3FromHashTable(%1, _%3);\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } else { dvWrtemp(dvFile, " remove%1%2%3FromHashTable(%1, _%3);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); } } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write an array insert relationship routine for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassArrayInsertFunction( dvClass theClass, dvRelationship relationship) { char *parentName = dvClassGetName(theClass); dvClass childClass = dvRelationshipGetChildClass(relationship); char *childName = dvClassGetName(childClass); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Add the indexed %2%3 to the %1.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Insert%2%3(\n" " %4%1 %1,\n" " uint32 x,\n" " %5%3 _%3)\n" "{\n" "#if defined(DD_DEBUG)\n" " if(%1 == %4%1Null) {\n" " utExit(\"Non existent %1\");\n" " }\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " if(%0%2Get%4%1(_%2) != %3%1Null) {\n" " utExit(\"Attempting to add %2 to %1 twice\");\n" " }\n", dvPrefix, parentName, childName, dvClassGetPrefix(theClass), dvRelationshipGetParentLabel(relationship)); } dvWrtemp(dvFile, "#endif\n" " %0%1Seti%2%3(%1, x, _%3);\n" " %0%1SetUsed%2%3(%1, utMax(%0%1GetUsed%2%3(%1), x + 1));\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " %0%3Set%1%4Index(_%3, x);\n" " %0%3Set%2%1(_%3, %1);\n", dvPrefix, parentName, dvRelationshipGetParentLabel(relationship), childName, dvRelationshipGetChildLabel(relationship)); } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write an array append relationship routine for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassArrayAppendFunction( dvClass theClass, dvRelationship relationship) { char *parentName = dvClassGetName(theClass); dvClass childClass = dvRelationshipGetChildClass(relationship); char *childName = dvClassGetName(childClass); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Add the %2%3 to the end of the %1%2%3% array.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Append%2%3(\n" " %4%1 %1,\n" " %5%3 _%3)\n" "{\n" " uint32 used%2%3 = %0%1GetUsed%2%3(%1);\n" "\n" "#if defined(DD_DEBUG)\n" " if(%1 == %4%1Null) {\n" " utExit(\"Non existent %1\");\n" " }\n" "#endif\n" " if(used%2%3 >= %0%1GetNum%2%3(%1)) {\n" " %0%1Resize%2%3s(%1, used%2%3 + (used%2%3 << 1) + 1);\n" " }\n" " %0%1Seti%2%3(%1, used%2%3, _%3);\n" " %0%1SetUsed%2%3(%1, used%2%3 + 1);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " %0%3Set%1%4Index(_%3, used%2%3);\n" " %0%3Set%2%1(_%3, %1);\n", dvPrefix, parentName, dvRelationshipGetParentLabel(relationship), childName, dvRelationshipGetChildLabel(relationship)); } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write a delete relationship routine for array relationship. --------------------------------------------------------------------------------------------------*/ static void writeClassRemoveArray( dvClass theClass, dvRelationship relationship) { char *parentName = dvClassGetName(theClass); dvClass childClass = dvRelationshipGetChildClass(relationship); char *childName = dvClassGetName(childClass); char *childLabel = dvRelationshipGetChildLabel(relationship); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Remove the %2%3 from the %1.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Remove%2%3(\n" " %4%1 %1,\n" " %5%3 _%3)\n" "{\n", dvPrefix, parentName, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); dvWrtemp(dvFile, "#if defined(DD_DEBUG)\n" " if(_%3 == %5%3Null) {\n" " utExit(\"Non-existent %3\");\n" " }\n", dvPrefix, parentName, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " if(%0%3Get%1%2(_%3) != %4%2Null && %0%3Get%1%2(_%3) != %2) {\n" " utExit(\"Delete %3 from non-owning %2\");\n" " }\n", dvPrefix, dvRelationshipGetParentLabel(relationship), parentName, childName, dvClassGetPrefix(theClass)); } dvWrtemp(dvFile, "#endif\n" " %0%1Seti%2%3(%1, %0%3Get%1%2Index(_%3), %5%3Null);\n" " %0%3Set%1%2Index(_%3, UINT32_MAX);\n", dvPrefix, parentName, dvRelationshipGetChildLabel(relationship), childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, " %0%1Set%2%3(_%1, %4%3Null);\n", dvPrefix, childName, dvRelationshipGetParentLabel(relationship), parentName, dvClassGetPrefix(theClass)); } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write code to initialize property array values. --------------------------------------------------------------------------------------------------*/ static void writePropertyInits( dvProperty prop, char *firstIndex, char *numValues, char *indent) { dvClass theClass = dvPropertyGetClass(prop); dvUnion theUnion = dvPropertyGetUnion(prop); char *initValue = dvPropertyFindInitializer(prop); char *name = dvClassGetName(theClass); char *propName = dvPropertyGetName(prop); if(dvPropertyGetType(prop) == PROP_SYM || dvPropertyGetType(prop) == PROP_POINTER || strcmp(initValue, "0")) { dvWrtemp(dvFile, "%7 {\n" "%7 %2 x%1;\n" "%7 for(x%1 = (%2)(%3); x%1 < %3 + %4; x%1++) {\n" "%7 %0%1s.%6 = %5;\n" "%7 }\n" "%7 }\n", dvPrefix, name, dvClassGetReferenceTypeName(theClass), firstIndex, numValues, initValue, theUnion == dvUnionNull? utSprintf("%s[x%s]", propName, name) : utSprintf("%s[x%s].%s", dvUnionGetFieldName(theUnion), name, propName), indent); } else { dvWrtemp(dvFile, "%7 memset(%0%1s.%2 + %5, 0, ((%6%4)*sizeof(%3));\n", dvPrefix, name, theUnion == dvUnionNull? propName : dvUnionGetFieldName(theUnion), theUnion == dvUnionNull? dvPropertyGetTypeName(prop) : dvUnionGetTypeName(theUnion), dvPropertyGetType(prop) == PROP_BIT? " + 7) >> 3" : ")", firstIndex, numValues, indent); } } /*-------------------------------------------------------------------------------------------------- Write the allocation for the property fields of theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassPropFieldAllocs( dvClass theClass) { dvUnion theUnion; dvProperty prop; char *name = dvClassGetName(theClass); dvForeachClassProperty(theClass, prop) { if(dvPropertyGetUnion(prop) == dvUnionNull && !dvPropertySparse(prop)) { if(!dvPropertyArray(prop)) { dvWrtemp(dvFile, " %0%1s.%2 = utNewA(%4, (%3Allocated%1()%5);\n", dvPrefix, name, dvPropertyGetName(prop), dvClassGetPrefix(theClass), dvPropertyGetTypeName(prop), dvPropertyGetType(prop) == PROP_BIT? " + 7) >> 3" : ")"); if(dvClassGetBaseClass(theClass) != dvClassNull) { writePropertyInits(prop, "0", utSprintf("%sAllocated%s()", dvClassGetPrefix(theClass), name), ""); } } else { dvWrtemp(dvFile, " %0SetUsed%1%2(0);\n" " %0SetAllocated%1%2(2);\n" " %0SetFree%1%2(0);\n" " %0%1s.%2 = utNewA(%4, %0Allocated%1%2());\n", dvPrefix, name, dvPropertyGetName(prop), dvClassGetPrefix(theClass), dvPropertyGetTypeName(prop)); } } } dvEndClassProperty; dvForeachClassUnion(theClass, theUnion) { dvWrtemp(dvFile, " %0%1s.%3 = utNewA(%4, %2Allocated%1());\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass), dvUnionGetFieldName(theUnion), dvUnionGetTypeName(theUnion)); if(dvClassGetBaseClass(theClass) != dvClassNull) { writePropertyInits(dvUnionGetFirstProperty(theUnion), "0", utSprintf("%sAllocated%s()", dvClassGetPrefix(theClass), name), ""); } } dvEndClassUnion; } /*-------------------------------------------------------------------------------------------------- Write the reallocation for the property fields of theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassPropFieldReallocs( dvClass theClass) { dvUnion theUnion; dvProperty prop; char *name = dvClassGetName(theClass); dvForeachClassProperty(theClass, prop) { if(!dvPropertyArray(prop) && dvPropertyGetUnion(prop) == dvUnionNull && !dvPropertySparse(prop)) { if(dvClassUndo(theClass)) { dvWrtemp(dvFile, " utRecordResize(%0ModuleID, %3, (%2Allocated%1()%4, true);\n", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvPropertyGetFieldNumber(prop)), dvPropertyGetType(prop) == PROP_BIT? " + 7) >> 3" : ")"); } dvWrtemp(dvFile, " utResizeArray(%0%1s.%2, (newSize%4);\n", dvPrefix, name, dvPropertyGetName(prop), dvClassGetPrefix(theClass), dvPropertyGetType(prop) == PROP_BIT? " + 7) >> 3" : ")"); if(dvClassRedo(theClass)) { dvWrtemp(dvFile, " utRecordResize(%0ModuleID, %3, (newSize%4, false);\n", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvPropertyGetFieldNumber(prop)), dvPropertyGetType(prop) == PROP_BIT? " + 7) >> 3" : ")"); } } } dvEndClassProperty; dvForeachClassUnion(theClass, theUnion) { if(dvClassUndo(theClass)) { dvWrtemp(dvFile, " utRecordResize(%0ModuleID, %3, %2Allocated%1(), true);\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass), utSprintf("%u", dvUnionGetFieldNumber(theUnion))); } dvWrtemp(dvFile, " utResizeArray(%0%1s.%2, newSize);\n", dvPrefix, dvClassGetName(theClass), dvUnionGetFieldName(theUnion), dvClassGetPrefix(theClass)); if(dvClassRedo(theClass)) { dvWrtemp(dvFile, " utRecordResize(%0ModuleID, %3, newSize, false);\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass), utSprintf("%u", dvPropertyGetFieldNumber(prop))); } } dvEndClassUnion; } /*-------------------------------------------------------------------------------------------------- Write the free statements for the property fields of theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassPropFieldFrees( dvClass theClass) { dvUnion theUnion; dvProperty prop; char *name = dvClassGetName(theClass); dvForeachClassProperty(theClass, prop) { if(dvPropertyGetUnion(prop) == dvUnionNull && !dvPropertySparse(prop)) { dvWrtemp(dvFile, " utFree(%0%1s.%2);\n", dvPrefix, name, dvPropertyGetName(prop)); } } dvEndClassProperty; dvForeachClassUnion(theClass, theUnion) { dvWrtemp(dvFile, " utFree(%0%1s.%2);\n", dvPrefix, dvClassGetName(theClass), dvUnionGetFieldName(theUnion)); } dvEndClassUnion; } /*-------------------------------------------------------------------------------------------------- Write out the allocation stuff for a class. --------------------------------------------------------------------------------------------------*/ static void writeClassAllocs( dvClass theClass) { char *name = dvClassGetName(theClass); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Allocate the field arrays of %1.\n" "----------------------------------------------------------------------------------------*/\n" "static void alloc%1s(void)\n" "{\n", dvPrefix, name); if(dvClassGetBaseClass(theClass) == dvClassNull) { dvWrtemp(dvFile, " %0SetAllocated%1(2);\n" " %0SetUsed%1(0);\n", dvPrefix, name); if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { dvWrtemp(dvFile, " %0SetFirstFree%1(%0%1Null);\n", dvPrefix, name); } } writeClassPropFieldAllocs(theClass); if(dvClassGetBaseClass(theClass) != dvClassNull) { dvWrtemp(dvFile, " %0SetAllocated%1(%2Allocated%1());\n" " %0%1ConstructorCallback = %2%1GetConstructorCallback();\n" " %2%1SetConstructorCallback(init%1);\n", dvPrefix, name, dvClassGetPrefix(theClass)); if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { dvWrtemp(dvFile, " %0%1DestructorCallback = %2%1GetDestructorCallback();\n" " %2%1SetDestructorCallback(destroy%1);\n", dvPrefix, name, dvClassGetPrefix(theClass)); } } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write out the reallocation stuff for a class. --------------------------------------------------------------------------------------------------*/ static void writeClassReallocs( dvClass theClass) { dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Realloc the arrays of properties for class %0.\n" "----------------------------------------------------------------------------------------*/\n" "static void realloc%0s(\n" " %1 newSize)\n" "{\n", dvClassGetName(theClass), dvClassGetReferenceTypeName(theClass)); writeClassPropFieldReallocs(theClass); dvWrtemp(dvFile, " %0SetAllocated%1(newSize);\n" "}\n\n", dvPrefix, dvClassGetName(theClass)); } /*-------------------------------------------------------------------------------------------------- Write the database stop routine. --------------------------------------------------------------------------------------------------*/ static void writeStop( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Free memory used by the %0 database.\n" "----------------------------------------------------------------------------------------*/\n" "void %0DatabaseStop(void)\n{\n", dvPrefix); dvForeachModuleClass(module, theClass) { writeClassPropFieldFrees(theClass); if(dvClassGetBaseClass(theClass) != dvClassNull) { dvWrtemp(dvFile, " %2%1SetConstructorCallback(%0%1ConstructorCallback);\n" " %0%1ConstructorCallback = NULL;\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass)); if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { dvWrtemp(dvFile, " if(%2%1GetDestructorCallback() != destroy%1) {\n" " utExit(\"%0DatabaseClose called out of order\");\n" " }\n" " %2%1SetDestructorCallback(%0%1DestructorCallback);\n" " %0%1DestructorCallback = NULL;\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass)); } } } dvEndModuleClass; dvWrtemp(dvFile, " utUnregisterModule(%0ModuleID);\n" "}\n\n", dvPrefix); } /*-------------------------------------------------------------------------------------------------- Write code to register this module's fields so that changes can be mirrored to disk. --------------------------------------------------------------------------------------------------*/ static void writeRegisterFields( dvModule module) { dvClass theClass; dvUnion theUnion; dvCase theCase; dvEnum theEnum; dvEntry entry; dvProperty property; dvWrtemp(dvFile, " %0ModuleID = utRegisterModule(\"%0\", %0Hash(), %1, sizeof(struct %0RootType_),\n" " &%0RootData, %0DatabaseStart, %0DatabaseStop);\n", dvPrefix, utSprintf("%u, %u, %u", dvModuleGetNumClasses(module), dvModuleGetNumFields(module), dvModuleGetNumEnums(module))); dvForeachModuleEnum(module, theEnum) { dvWrtemp(dvFile, " utRegisterEnum(\"%0\", %1);\n", dvEnumGetName(theEnum), utSprintf("%u", dvEnumGetNumEntries(theEnum))); dvForeachEnumEntry(theEnum, entry) { dvWrtemp(dvFile, " utRegisterEntry(\"%0\", %1);\n", dvEntryGetName(entry), utSprintf("%u", dvEntryGetValue(entry))); } dvEndEnumEntry; } dvEndModuleEnum; dvForeachModuleClass(module, theClass) { dvWrtemp(dvFile, " utRegisterClass(\"%1\", %3, &%2RootData.used%1, &%2RootData.allocated%1,\n", dvModuleGetPrefix(module), dvClassGetName(theClass), dvClassGetPrefix(theClass), utSprintf("%u", dvClassGetNumFields(theClass))); if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { dvWrtemp(dvFile, " &%1RootData.firstFree%0, ", dvClassGetName(theClass), dvClassGetPrefix(theClass)); } else { dvWrtemp(dvFile, " NULL, "); } dvWrtemp(dvFile, "%0, %1, ", utSprintf("%u", dvPropertyGetFieldNumber(dvClassGetFreeListProperty(theClass))), utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); if(dvClassGetBaseClass(theClass) == dvClassNull) { dvWrtemp(dvFile, "alloc%0, ", dvClassGetName(theClass)); if(dvClassGetMemoryStyle(theClass) != MEM_CREATE_ONLY) { dvWrtemp(dvFile, "destroy%0);\n", dvClassGetName(theClass)); } else { dvWrtemp(dvFile, "NULL);\n"); } } else { dvWrtemp(dvFile, "NULL, NULL);\n"); } dvForeachClassProperty(theClass, property) { if(dvPropertyGetUnion(property) == dvUnionNull && !dvPropertySparse(property)) { dvWrtemp(dvFile, " utRegisterField(\"%2\", &%0%1s.%2, sizeof(%3), %4,", dvModuleGetPrefix(module), dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetTypeName(property), dvPropertyGetFieldTypeName(property)); if(dvPropertyGetType(property) == PROP_POINTER) { dvWrtemp(dvFile, " \"%0\");\n", dvClassGetName(dvPropertyGetClassProp(property))); } else if(dvPropertyGetType(property) == PROP_ENUM) { dvWrtemp(dvFile, " \"%0\");\n", dvEnumGetName(dvPropertyGetEnumProp(property))); } else { dvWrtemp(dvFile, " NULL);\n"); } if(dvPropertyArray(property)) { dvWrtemp(dvFile, " utRegisterArray(&%0RootData.used%1%2, &%0RootData.allocated%1%2,\n" " get%1%2s, alloc%1%2s);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), utSprintf("%u", dvPropertyGetFieldNumber(property))); } if(dvPropertyHidden(property)) { dvWrtemp(dvFile, " utSetFieldHidden();\n"); } } } dvEndClassProperty; dvForeachClassUnion(theClass, theUnion) { property = dvUnionGetTypeProperty(theUnion); dvWrtemp(dvFile, " utRegisterField(\"%2\", &%0%1s.%2, sizeof(%3), UT_UNION, \"%4\");\n" " utRegisterUnion(\"%4\", %5);\n", dvModuleGetPrefix(module), dvClassGetName(theClass), dvUnionGetFieldName(theUnion), dvUnionGetTypeName(theUnion), dvPropertyGetName(property), utSprintf("%u", dvUnionGetNumCases(theUnion))); dvForeachUnionProperty(theUnion, property) { dvForeachPropertyCase(property, theCase) { entry = dvCaseGetEntry(theCase); dvWrtemp(dvFile, " utRegisterUnionCase(%0, %1, sizeof(%2));\n", utSprintf("%u", dvEntryGetValue(entry)), dvPropertyGetFieldTypeName(property), dvPropertyGetTypeName(property)); } dvEndPropertyCase; } dvEndUnionProperty; } dvEndClassUnion; } dvEndModuleClass; } /*-------------------------------------------------------------------------------------------------- Write the database initialization routine. --------------------------------------------------------------------------------------------------*/ static void writeStart( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Allocate memory used by the %0 database.\n" "----------------------------------------------------------------------------------------*/\n" "void %0DatabaseStart(void)\n{\n" " if(!utInitialized()) {\n" " utStart();\n" " }\n" " %0RootData.hash = %1;\n", dvPrefix, utSprintf("0x%x", dvComputeDatabaseHash())); writeRegisterFields(module); dvForeachModuleClass(module, theClass) { dvWrtemp(dvFile, " alloc%0s();\n", dvClassGetName(theClass)); } dvEndModuleClass; if(dvModuleHasSparseData(module)) { dvWrtemp(dvFile, " (void)%0DatadrawRootAlloc();\n", dvPrefix); } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write the function to allocate more objects of the class. --------------------------------------------------------------------------------------------------*/ static void writeClassAllocateMore( dvClass theClass) { dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Allocate more %1s.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1AllocMore(void)\n" "{\n" " realloc%1s((%3)(%2Allocated%1() + (%2Allocated%1() >> 1)));\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass), dvClassGetReferenceTypeName(theClass)); } /*-------------------------------------------------------------------------------------------------- Write the init function for local fields of an object. --------------------------------------------------------------------------------------------------*/ static void writeExtendedClassInitFunc( dvClass theClass) { dvWrtemp(dvFile, "static void realloc%1s(%3 newSize);\n" "/*----------------------------------------------------------------------------------------\n" " Initialize a new %1. This is a constructor callback from the base class.\n" "----------------------------------------------------------------------------------------*/\n" "static void init%1(\n" " %2%1 %1)\n" "{\n" " if(%0Allocated%1() != %2Allocated%1()) {\n" " realloc%1s(%2Allocated%1());\n" " }\n" " %0%1Init(%1);\n" " if(%0%1ConstructorCallback != NULL) {\n" " %0%1ConstructorCallback(%1);\n" " }\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass), dvClassGetReferenceTypeName(theClass)); } /*-------------------------------------------------------------------------------------------------- Write simple constructor/destructor wrapper functions for the database manager's use. --------------------------------------------------------------------------------------------------*/ static void writeConstructorDestructorWrappers( dvClass theClass) { dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Default constructor wrapper for the database manager.\n" "----------------------------------------------------------------------------------------*/\n" "static uint64 alloc%1(void)\n" "{\n" " %0%1 %1 = %0%1Alloc();\n" "\n" " return %0%12Index(%1);\n" "}\n\n", dvPrefix, dvClassGetName(theClass)); if(dvClassGetMemoryStyle(theClass) != MEM_CREATE_ONLY) { dvWrtemp(dvFile, "/*-----------------------------------------------------" "-----------------------------------\n" " Destructor wrapper for the database manager.\n" "-------------------------------------------------------" "---------------------------------*/\n" "static void destroy%1(\n" " uint64 objectIndex)\n" "{\n" " %0%1Destroy(%0Index2%1((%2)objectIndex));\n" "}\n\n" , dvPrefix, dvClassGetName(theClass), dvClassGetReferenceTypeName(theClass)); } } /*-------------------------------------------------------------------------------------------------- Write a function to compact a property array. --------------------------------------------------------------------------------------------------*/ static void writeArrayCompact( dvProperty property) { dvClass theClass = dvPropertyGetClass(property); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Compact the %1.%2 heap to free memory.\n" "----------------------------------------------------------------------------------------*/\n" "void %0Compact%1%2s(void)\n" "{\n" " uint32 elementSize = sizeof(%4);\n" " uint32 usedHeaderSize = (sizeof(%3%1) + elementSize - 1)/elementSize;\n" " uint32 freeHeaderSize = (sizeof(%3%1) + sizeof(uint32) + elementSize - 1)/elementSize;\n" " %4 *toPtr = %0%1s.%2;\n" " %4 *fromPtr = toPtr;\n" " %3%1 %1;\n" " uint32 size;\n" "\n" " while(fromPtr < %0%1s.%2 + %0Used%1%2()) {\n" " %1 = *(%3%1 *)(void *)fromPtr;\n" " if(%1 != %3%1Null) {\n" " /* Need to move it to toPtr */\n" " size = utMax(%0%1GetNum%2(%1) + usedHeaderSize, freeHeaderSize);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); if(dvClassUndo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, toPtr - %0%1s.%2, size, true);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " memmove((void *)toPtr, (void *)fromPtr, size*elementSize);\n"); if(dvClassRedo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, toPtr - %0%1s.%2, size, false);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " %0%1Set%2Index(%1, toPtr - %0%1s.%2 + usedHeaderSize);\n" " toPtr += size;\n" " } else {\n" " /* Just skip it */\n" " size = *(uint32 *)(void *)(((%3%1 *)(void *)fromPtr) + 1);\n" " }\n" " fromPtr += size;\n" " }\n" " %0SetUsed%1%2(toPtr - %0%1s.%2);\n" " %0SetFree%1%2(0);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass)); } /*-------------------------------------------------------------------------------------------------- Write a function to compact and/or allocate more space on the property heap. --------------------------------------------------------------------------------------------------*/ static void writeArrayAllocMore( dvProperty property) { dvClass theClass = dvPropertyGetClass(property); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Allocate more memory for the %1.%2 heap.\n" "----------------------------------------------------------------------------------------*/\n" "static void allocMore%1%2s(\n" " uint32 spaceNeeded)\n" "{\n" " uint32 freeSpace = %0Allocated%1%2() - %0Used%1%2();\n" "\n" " if((%0Free%1%2() << 2) > %0Used%1%2()) {\n" " %0Compact%1%2s();\n" " freeSpace = %0Allocated%1%2() - %0Used%1%2();\n" " }\n" " if(freeSpace < spaceNeeded) {\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); if(dvClassUndo(theClass)) { dvWrtemp(dvFile, " utRecordResize(%0ModuleID, %3, %0Allocated%1%2(), true);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), utSprintf("%u", dvPropertyGetFieldNumber(property))); } dvWrtemp(dvFile, " %0SetAllocated%1%2(%0Allocated%1%2() + spaceNeeded - freeSpace +\n" " (%0Allocated%1%2() >> 1));\n" " utResizeArray(%0%1s.%2, %0Allocated%1%2());\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property)); if(dvClassRedo(theClass)) { dvWrtemp(dvFile, " utRecordResize(%0ModuleID, %3, %0Allocated%1%2(), false);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), utSprintf("%u", dvPropertyGetFieldNumber(property))); } dvWrtemp(dvFile, " }\n" "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write a function to allocate the requested space for the array. The request is always placed at the end of the heap, but if the ammount of free memory withing the heap is > 25%, then we compact the heap first. --------------------------------------------------------------------------------------------------*/ static void writeArrayAlloc( dvProperty property) { dvClass theClass = dvPropertyGetClass(property); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Allocate memory for a new %1.%2 array.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Alloc%2s(\n" " %3%1 %1,\n" " uint32 num%2s)\n" "{\n" " uint32 freeSpace = %0Allocated%1%2() - %0Used%1%2();\n" " uint32 elementSize = sizeof(%4);\n" " uint32 usedHeaderSize = (sizeof(%3%1) + elementSize - 1)/elementSize;\n" " uint32 freeHeaderSize = (sizeof(%3%1) + sizeof(uint32) + elementSize - 1)/elementSize;\n" " uint32 spaceNeeded = utMax(num%2s + usedHeaderSize, freeHeaderSize);\n" "\n" "#if defined(DD_DEBUG)\n" " utAssert(%0%1GetNum%2(%1) == 0);\n" "#endif\n" " if(num%2s == 0) {\n" " return;\n" " }\n" " if(freeSpace < spaceNeeded) {\n" " allocMore%1%2s(spaceNeeded);\n" " }\n" " %0%1Set%2Index(%1, %0Used%1%2() + usedHeaderSize);\n" " %0%1SetNum%2(%1, num%2s);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); if(dvClassUndo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, %0Used%1%2(), num%2s + usedHeaderSize, true);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " *(%3%1 *)(void *)(%0%1s.%2 + %0Used%1%2()) = %1;\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass)); writePropertyInits(property, dvSwrtemp("%0%1Get%2Index(%1)", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property)), utSprintf("num%ss", dvPropertyGetName(property)), ""); if(dvClassRedo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, %0Used%1%2(), num%2s + usedHeaderSize, false);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " %0SetUsed%1%2(%0Used%1%2() + spaceNeeded);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property)); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Wrapper around %0%1Get%2s for the database manager.\n" "----------------------------------------------------------------------------------------*/\n" "static void *get%1%2s(\n" " uint64 objectNumber,\n" " uint32 *numValues)\n" "{\n" " %3%1 %1 = %3Index2%1((%4)objectNumber);\n" "\n" " *numValues = %0%1GetNum%2(%1);\n" " return %0%1Get%2s(%1);\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Wrapper around %0%1Alloc%2s for the database manager.\n" "----------------------------------------------------------------------------------------*/\n" "static void *alloc%1%2s(\n" " uint64 objectNumber,\n" " uint32 numValues)\n" "{\n" " %3%1 %1 = %3Index2%1((%4)objectNumber);\n" "\n" " %0%1Set%2Index(%1, 0);\n" " %0%1SetNum%2(%1, 0);\n" " if(numValues == 0) {\n" " return NULL;\n" " }\n" " %0%1Alloc%2s(%1, numValues);\n" " return %0%1Get%2s(%1);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass), dvClassGetReferenceTypeName(theClass)); } /*-------------------------------------------------------------------------------------------------- Write a function to free a property array. --------------------------------------------------------------------------------------------------*/ static void writeArrayFree( dvProperty property) { dvClass theClass = dvPropertyGetClass(property); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Free memory used by the %1.%2 array.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Free%2s(\n" " %3%1 %1)\n" "{\n" " uint32 elementSize = sizeof(%4);\n" " uint32 usedHeaderSize = (sizeof(%3%1) + elementSize - 1)/elementSize;\n" " uint32 freeHeaderSize = (sizeof(%3%1) + sizeof(uint32) + elementSize - 1)/elementSize;\n" " uint32 size = utMax(%0%1GetNum%2(%1) + usedHeaderSize, freeHeaderSize);\n" " %4 *dataPtr = %0%1Get%2s(%1) - usedHeaderSize;\n" "\n" " if(%0%1GetNum%2(%1) == 0) {\n" " return;\n" " }\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); if(dvClassUndo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, dataPtr - %0%1s.%2, freeHeaderSize, true);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " *(%1%0 *)(void *)(dataPtr) = %1%0Null;\n" " *(uint32 *)(void *)(((%1%0 *)(void *)dataPtr) + 1) = size;\n", dvClassGetName(theClass), dvClassGetPrefix(theClass)); if(dvClassRedo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, dataPtr - %0%1s.%2, freeHeaderSize, false);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " %0%1SetNum%2(%1, 0);\n" " %0SetFree%1%2(%0Free%1%2() + size);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property)); } /*-------------------------------------------------------------------------------------------------- Write a function to reallocate a property array. --------------------------------------------------------------------------------------------------*/ static void writeArrayResize( dvProperty property) { dvClass theClass = dvPropertyGetClass(property); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Resize the %1.%2 array.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Resize%2s(\n" " %3%1 %1,\n" " uint32 num%2s)\n" "{\n" " uint32 freeSpace;\n" " uint32 elementSize = sizeof(%4);\n" " uint32 usedHeaderSize = (sizeof(%3%1) + elementSize - 1)/elementSize;\n" " uint32 freeHeaderSize = (sizeof(%3%1) + sizeof(uint32) + elementSize - 1)/elementSize;\n" " uint32 newSize = utMax(num%2s + usedHeaderSize, freeHeaderSize);\n" " uint32 oldSize = utMax(%0%1GetNum%2(%1) + usedHeaderSize, freeHeaderSize);\n" " %4 *dataPtr;\n" "\n" " if(num%2s == 0) {\n" " if(%0%1GetNum%2(%1) != 0) {\n" " %0%1Free%2s(%1);\n" " }\n" " return;\n" " }\n" " if(%0%1GetNum%2(%1) == 0) {\n" " %0%1Alloc%2s(%1, num%2s);\n" " return;\n" " }\n" " freeSpace = %0Allocated%1%2() - %0Used%1%2();\n" " if(freeSpace < newSize) {\n" " allocMore%1%2s(newSize);\n" " }\n" " dataPtr = %0%1Get%2s(%1) - usedHeaderSize;\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); if(dvClassUndo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, %0Used%1%2(), newSize, true);\n" " utRecordArray(%0ModuleID, %3, dataPtr - %0%1s.%2, freeHeaderSize, true);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " memcpy((void *)(%0%1s.%2 + %0Used%1%2()), dataPtr,\n" " elementSize*utMin(oldSize, newSize));\n" " if(newSize > oldSize) {\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property)); writePropertyInits(property, utSprintf("%sUsed%s%s() + oldSize", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property)), "newSize - oldSize", " "); dvWrtemp(dvFile, " }\n" " *(%1%0 *)(void *)dataPtr = %1%0Null;\n" " *(uint32 *)(void *)(((%1%0 *)(void *)dataPtr) + 1) = oldSize;\n", dvClassGetName(theClass), dvClassGetPrefix(theClass)); if(dvClassRedo(theClass)) { dvWrtemp(dvFile, " utRecordArray(%0ModuleID, %3, %0Used%1%2(), newSize, false);\n" " utRecordArray(%0ModuleID, %3, dataPtr - %0%1s.%2, freeHeaderSize, false);\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvPropertyGetID(property)); } dvWrtemp(dvFile, " %0SetFree%1%2(%0Free%1%2() + oldSize);\n" " %0%1Set%2Index(%1, %0Used%1%2() + usedHeaderSize);\n" " %0%1SetNum%2(%1, num%2s);\n" " %0SetUsed%1%2(%0Used%1%2() + newSize);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property)); } /*-------------------------------------------------------------------------------------------------- Write functions that manipulate property arrays on this class. --------------------------------------------------------------------------------------------------*/ static void writeClassPropertyArrayFunctions( dvClass theClass) { dvProperty property; dvForeachClassProperty(theClass, property) { if(dvPropertyArray(property)) { writeArrayCompact(property); writeArrayAllocMore(property); writeArrayAlloc(property); writeArrayFree(property); writeArrayResize(property); } } dvEndClassProperty; } /*-------------------------------------------------------------------------------------------------- This relationship needs to have children processed during destruction. --------------------------------------------------------------------------------------------------*/ bool needsChildrenProcessed( dvRelationship relationship) { if(!dvRelationshipAccessChild(relationship)) { return false; /* Can't get there from here */ } if(dvClassGetMemoryStyle(dvRelationshipGetChildClass(relationship)) == MEM_CREATE_ONLY) { return false; /* Can't destroy a create-only object */ } if(dvRelationshipCascade(relationship)) { return true; /* User decrees it! */ } if(dvRelationshipAccessParent(relationship)) { return true; /* Children have owner pointers to be nulled out */ } return false; } /*-------------------------------------------------------------------------------------------------- Write Binary Heap functions for array relationship. --------------------------------------------------------------------------------------------------*/ static void writeRelationshipBinaryHeapFunctions( dvRelationship relationship) { dvClass parent = dvRelationshipGetParentClass(relationship); dvClass child = dvRelationshipGetChildClass(relationship); dvWrtemp(dvFile, "static void %0%1Swap%2%3(\n" " %4%1 %1,\n" " uint32 x,\n" " uint32 y)\n" "{\n" " %5%3 newY = %0%1Geti%2%3(%1, x);\n" " %5%3 newX = %0%1Geti%2%3(%1, y);\n" "\n" " %0%1Remove%2%3(%1, newY);\n" " %0%1Remove%2%3(%1, newX);\n" " %0%1Insert%2%3(%1, x, newX);\n" " %0%1Insert%2%3(%1, y, newY);\n" "}\n" "\n" "static void %0%1HeapDown%2%3(\n" " %4%1 %1,\n" " uint32 arg_x)\n" "{\n" " uint32 x = arg_x;\n" " uint32 leftIndex;\n" " uint32 rightIndex;\n" " %5%3 cur = %0%1Geti%2%3(%1, x);\n" " %5%3 left = %5%3Null;\n" " %5%3 right = %5%3Null;\n" " %5%3 best;\n" " \n" " utDo {\n" " best = cur;\n" " leftIndex = (x << 1) + 1;\n" " rightIndex = leftIndex + 1;\n" " if(leftIndex < %0%1GetUsed%2%3(%1)) {\n" " left = %0%1Geti%2%3(%1, leftIndex);\n" " if(%0%1Compare%2%3(best, left) > 0) {\n" " best = left;\n" " }\n" " if(rightIndex < %0%1GetUsed%2%3(%1)) {\n" " right = %0%1Geti%2%3(%1, rightIndex);\n" " if(%0%1Compare%2%3(best, right) > 0) {\n" " best = right;\n" " }\n" " }\n" " }\n" " } utWhile(best != cur) {\n" " if(best == left) {\n" " %0%1Swap%2%3(%1, x, leftIndex);\n" " x = leftIndex;\n" " } else {\n" " %0%1Swap%2%3(%1, x, rightIndex);\n" " x = rightIndex;\n" " }\n" " } utRepeat;\n" "}\n" "\n" "static void %0%1HeapUp%2%3(\n" " %4%1 %1,\n" " uint32 arg_x)\n" "{\n" " \n" " uint32 x = arg_x;\n" " %5%3 cur = %0%1Geti%2%3(%1, x);\n" " uint32 parentIndex;\n" " \n" " utDo {\n" " parentIndex = (x-1) >> 1;\n" " } utWhile(x > 0 && %0%1Compare%2%3(%0%1Geti%2%3(%1, parentIndex), cur) > 0) {\n" " %0%1Swap%2%3(%1, parentIndex, x);\n" " x = parentIndex;\n" " } utRepeat\n" " %0%1HeapDown%2%3(%1, x);\n" "}\n" "\n" "void %0%1Push%2%3(\n" " %4%1 %1,\n" " %5%3 %3)\n" "{\n" " uint32 index = %0%1GetUsed%2%3(%1);\n" "\n" " %0%1Append%2%3(%1, %3);\n" " %0%1HeapUp%2%3(%1, index);\n" "}\n" "\n" "%5%3 %0%1Peek%2%3(\n" " %4%1 %1)\n" "{\n" " if(%0%1GetUsed%2%3(%1) == 0) {\n" " return %5%3Null;\n" " }\n" " return %0%1Geti%2%3(%1, 0);\n" "}\n" "\n" "%5%3\n %0%1Pop%2%3(\n" " %4%1 %1)\n" "{\n" " %5%3 cur;\n" " %5%3 retval = %0%1Peek%2%3(%1);\n" " uint32 newNum = %0%1GetUsed%2%3(%1) - 1;\n" "\n" " if(retval == %5%3Null) {\n" " return retval;\n" " }\n" " if(newNum == 0) {\n" " %0%1Remove%2%3(%1, retval);\n" " %0%1SetUsed%2%3(%1, 0);\n" " return retval;\n" " }\n" " %0%1Remove%2%3(%1, retval);\n" " cur = %0%1Geti%2%3(%1, newNum);\n" " %0%1Remove%2%3(%1, cur);\n" " %0%1Insert%2%3(%1, 0, cur);\n" " %0%1SetUsed%2%3(%1, newNum);\n" " \n" " %0%1HeapDown%2%3(%1, 0);\n" " return retval;\n" "}\n" "\n" "void %0%1Improve%2%3(\n" " %5%3 %3)\n" "{\n" " %4%1 %1 = %0%3Get%6%1(%3);\n" " uint32 _index = %0%3Get%6%1Index(%3);\n" "\n" " %0%1HeapUp%2%3(%1, _index);\n" "}\n" "\n", dvPrefix, dvClassGetName(parent), dvRelationshipGetChildLabel(relationship), dvClassGetName(child), dvClassGetPrefix(parent), dvClassGetPrefix(child), dvRelationshipGetParentLabel(relationship)); } /*-------------------------------------------------------------------------------------------------- Declaration of local variables for destructor. --------------------------------------------------------------------------------------------------*/ static bool declareClassChildren( dvClass theClass) { dvRelationship relationship; dvClass childClass; dvRelationshipType type; bool declaredSomething = false; dvForeachClassChildRelationship(theClass, relationship) { childClass = dvRelationshipGetChildClass(relationship); type = dvRelationshipGetType(relationship); if(needsChildrenProcessed(relationship)) { if(type == REL_LINKED_LIST || type == REL_DOUBLY_LINKED || type == REL_TAIL_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, " %0%2 %1%2_, next%1%2_;\n", dvClassGetPrefix(childClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); } else if(type == REL_ARRAY || type == REL_HEAP) { dvWrtemp(dvFile, " %0%2 %1%2_;\n" " uint32 x%1%2;\n", dvClassGetPrefix(childClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); } else if(type == REL_POINTER) { dvWrtemp(dvFile, " %0%2 %1%2_;\n", dvClassGetPrefix(childClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); } declaredSomething = true; } } dvEndClassChildRelationship; return declaredSomething; } /*-------------------------------------------------------------------------------------------------- Declaration of local variables for rip. Return true if we declare anything. --------------------------------------------------------------------------------------------------*/ static bool declareClassParents( dvClass theClass) { dvRelationship relationship; dvClass parentClass; bool declaredSomething = false; dvForeachClassParentRelationship(theClass, relationship) { if(dvRelationshipAccessParent(relationship) && dvRelationshipAccessChild(relationship) && !dvRelationshipSharedParent(relationship)) { parentClass = dvRelationshipGetParentClass(relationship); dvWrtemp(dvFile, " %0%1 owning%2%1 = %3%4Get%2%1(%4);\n", dvClassGetPrefix(parentClass), dvClassGetName(parentClass), dvRelationshipGetParentLabel(relationship), dvPrefix, dvClassGetName(theClass)); declaredSomething = true; } } dvEndClassParentRelationship; return declaredSomething; } /*-------------------------------------------------------------------------------------------------- Destroy the cascade delete children AND null out weak child parents. --------------------------------------------------------------------------------------------------*/ static void processClassChildren( dvClass theClass) { dvRelationship relationship; dvClass childClass; bool indented, needsValidTest; dvRelationshipType type; dvForeachClassChildRelationship(theClass, relationship) { childClass = dvRelationshipGetChildClass(relationship); if(needsChildrenProcessed(relationship)) { type = dvRelationshipGetType(relationship); indented = false; needsValidTest = true; if(type == REL_LINKED_LIST || type == REL_DOUBLY_LINKED || type == REL_TAIL_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, " for(%1%2_ = %4%3GetFirst%1%2(%3); %1%2_ != %0%2Null;\n" " %1%2_ = next%1%2_) {\n" " next%1%2_ = %4%2GetNext%3%1%2(%1%2_);\n", dvClassGetPrefix(childClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetName(theClass), dvPrefix); indented = true; needsValidTest = false; /* test already in for loop */ } else if(type == REL_ARRAY || type == REL_HEAP) { dvWrtemp(dvFile, " for(x%1%2 = 0; x%1%2 < %4%3GetNum%1%2(%3); x%1%2++) {\n" " %1%2_ = %4%3Geti%1%2(%3, x%1%2);\n", dvClassGetPrefix(childClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetName(theClass), dvPrefix); indented = true; } else if(type == REL_POINTER) { dvWrtemp(dvFile, " %1%2_ = %4%3Get%1%2(%3);\n", dvClassGetPrefix(childClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetName(theClass), dvPrefix); } if(dvRelationshipCascade(relationship)) { dvWrtemp(dvFile, needsValidTest? "%3 if(%1%2_ != %0%2Null) {\n" "%3 %0%2Destroy(%1%2_);\n" "%3 }\n" : "%3 %0%2Destroy(%1%2_);\n", dvClassGetPrefix(childClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), indented ? " " : ""); } else if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, needsValidTest? "%7 if(%5%2_ != %6%2Null) {\n" "%7 %0%2Set%1%3(%5%2_, %4%3Null);\n" "%7 }\n" : "%7 %0%2Set%1%3(%5%2_, %4%3Null);\n", dvPrefix, dvRelationshipGetParentLabel(relationship), dvClassGetName(childClass), dvClassGetName(theClass), dvClassGetPrefix(theClass), dvRelationshipGetChildLabel(relationship), dvClassGetPrefix(childClass), indented ? " " : ""); } if(indented) { dvWrtemp(dvFile, " }\n"); } } } dvEndClassChildRelationship; } /*-------------------------------------------------------------------------------------------------- Unlink the object from its parents. --------------------------------------------------------------------------------------------------*/ static void processClassParents( dvClass theClass) { dvRelationship relationship; dvClass parentClass; dvForeachClassParentRelationship(theClass, relationship) { parentClass = dvRelationshipGetParentClass(relationship); if(dvRelationshipAccessParent(relationship) && dvRelationshipAccessChild(relationship)) { if(dvRelationshipGetType(relationship) != REL_POINTER) { dvWrtemp(dvFile, " if(owning%5%2 != %0%2Null) {\n" " %4%2Remove%1%3(owning%5%2, %3);\n", dvClassGetPrefix(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(parentClass), dvClassGetName(theClass), dvPrefix, dvRelationshipGetParentLabel(relationship)); } else { dvWrtemp(dvFile, " if(owning%6%2 != %0%2Null) {\n" " %4%2Set%1%3(owning%6%2, %5%3Null);\n", dvClassGetPrefix(parentClass), dvRelationshipGetChildLabel(relationship), dvClassGetName(parentClass), dvClassGetName(theClass), dvPrefix, dvClassGetPrefix(theClass), dvRelationshipGetParentLabel(relationship)); } if(dvRelationshipMandatory(relationship)) { dvWrtemp(dvFile, "#if defined(DD_DEBUG)\n" " } else {\n" " utExit(\"%2 without owning %1\");\n" "#endif\n", dvClassGetPrefix(parentClass), dvClassGetName(parentClass), dvClassGetName(theClass)); } fprintf(dvFile, " }\n"); } } dvEndClassParentRelationship; } /*-------------------------------------------------------------------------------------------------- Determine if the union has any cascade-delete properties. --------------------------------------------------------------------------------------------------*/ static bool unionHasCascadeProperty( dvUnion theUnion) { dvProperty property; dvForeachUnionProperty(theUnion, property) { if(dvPropertyCascade(property)) { return true; } } dvEndUnionProperty; return false; } /*-------------------------------------------------------------------------------------------------- Write code to cascade delete through pointer properties. --------------------------------------------------------------------------------------------------*/ static void processClassCascadeProperties( dvClass theClass) { dvClass childClass; dvUnion theUnion; dvProperty property, typeProperty; dvCase theCase; dvForeachClassProperty(theClass, property) { if(dvPropertyCascade(property) && dvPropertyGetUnion(property) == dvUnionNull) { childClass = dvPropertyGetClassProp(property); dvWrtemp(dvFile, "%3 if(%0%1Get%2(%1) != %3%4Null) {\n" "%3 %3%4Destroy(%0%1Get%2(%1));\n" "%3 }\n", dvClassGetPrefix(theClass), dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(childClass), dvClassGetName(childClass)); } } dvEndClassProperty; dvForeachClassUnion(theClass, theUnion) { if(unionHasCascadeProperty(theUnion)) { typeProperty = dvUnionGetTypeProperty(theUnion); dvWrtemp(dvFile, " switch(%0%1Get%2(%1)) {\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(typeProperty)); dvForeachUnionProperty(theUnion, property) { if(dvPropertyCascade(property)) { dvForeachPropertyCase(property, theCase) { dvWrtemp(dvFile, " case %0:", dvEntryGetName(dvCaseGetEntry(theCase))); } dvEndPropertyCase; childClass = dvPropertyGetClassProp(property); dvWrtemp(dvFile, "\n" " %3%4Destroy(%0%1Get%2(%1));\n" " break;\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(childClass), dvClassGetName(childClass)); } } dvEndUnionProperty; dvWrtemp(dvFile, " default:\n" " break;\n" " }\n"); } } dvEndClassUnion; } /*-------------------------------------------------------------------------------------------------- Write the destructor for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassDestructor( dvClass theClass) { bool isExtension = dvClassGetBaseClass(theClass) != dvClassNull; bool declaredSomething; if(dvClassGetMemoryStyle(theClass) == MEM_CREATE_ONLY) { return; } dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Destroy %0 including everything in it. Remove from parents.\n" "----------------------------------------------------------------------------------------*/\n" , dvClassGetName(theClass)); if(isExtension) { dvWrtemp(dvFile, "static void destroy%1(\n" " %2%1 %1)\n" "{\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass)); } else { dvWrtemp(dvFile, "void %0%1Destroy(\n" " %2%1 %1)\n" "{\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass)); } declaredSomething = declareClassChildren(theClass); declaredSomething |= declareClassParents(theClass); if(declaredSomething) { dvWrtemp(dvFile, "\n"); } dvWrtemp(dvFile, " if(%0%1DestructorCallback != NULL) {\n" " %0%1DestructorCallback(%1);\n" " }\n", dvPrefix, dvClassGetName(theClass)); processClassChildren(theClass); processClassParents(theClass); processClassCascadeProperties(theClass); if(!isExtension) { dvWrtemp(dvFile, " %0%1Free(%1);\n", dvPrefix, dvClassGetName(theClass)); } fprintf(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write out constructor/destructor variable declarations. --------------------------------------------------------------------------------------------------*/ static void writeClassConstructorDestructorVariables( dvClass theClass) { char *name = dvClassGetName(theClass); dvWrtemp(dvFile, "void(*%0%1ConstructorCallback)(%2%1);\n", dvPrefix, name, dvClassGetPrefix(theClass)); if(dvClassGetMemoryStyle(theClass) != MEM_CREATE_ONLY) { dvWrtemp(dvFile, "void(*%0%1DestructorCallback)(%2%1);\n", dvPrefix, name, dvClassGetPrefix(theClass)); } } /*-------------------------------------------------------------------------------------------------- Write out all the constructor/destructor variable declarations. --------------------------------------------------------------------------------------------------*/ static void writeConstructorDestructorVariables( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Constructor/Destructor hooks.\n" "----------------------------------------------------------------------------------------*/\n" ); dvForeachModuleClass(module, theClass) { writeClassConstructorDestructorVariables(theClass); } dvEndModuleClass; fputs("\n", dvFile); } /*-------------------------------------------------------------------------------------------------- Write the file top portion. Note that we write a slightly different include statment if we detect we are generating DatadrawUtil. This breaks a loop that otherwise would have it including itself! --------------------------------------------------------------------------------------------------*/ static void writeFileTop( dvModule module) { dvClass theClass; char *includeFile = utSprintf("%sdatabase.h", dvPrefix); if(!strcmp(dvModuleGetName(module), "DatadrawUtil")) { includeFile = "ddutil.h"; /* This hack breaks a recursive include loop */ } dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Database %0\n" "----------------------------------------------------------------------------------------*/\n" "\n" "#include \"%1\"\n" "\n" "union %0TempType_ %0Temp_;\n" "struct %0RootType_ %0RootData;\n", dvPrefix, includeFile); dvWrtemp(dvFile, "uint8 %0ModuleID;\n", dvPrefix); dvForeachModuleClass(module, theClass) { dvWrtemp(dvFile, "struct %0%1Fields %0%1s;\n", dvPrefix, dvClassGetName(theClass)); } dvEndModuleClass; fputs("\n", dvFile); writeConstructorDestructorVariables(module); } /*-------------------------------------------------------------------------------------------------- Write a function show all the fields of an object. --------------------------------------------------------------------------------------------------*/ static void writeClassShowFunction( dvClass theClass) { dvWrtemp(dvFile, "#if defined(DD_DEBUG)\n" "/*----------------------------------------------------------------------------------------\n" " Write out all the fields of an object.\n" "----------------------------------------------------------------------------------------*/\n" "void %0Show%1(\n" " %2%1 %1)\n" "{\n" " utDatabaseShowObject(\"%0\", \"%1\", %2%12Index(%1));\n" "}\n" "#endif\n\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass)); } /*-------------------------------------------------------------------------------------------------- Write access functions for the property so that we can call them from the debugger. --------------------------------------------------------------------------------------------------*/ static void writePropertyDebug( dvProperty property) { dvClass theClass = dvPropertyGetClass(property); dvUnion theUnion; char *name = dvClassGetName(theClass); char *propName = dvPropertyGetName(property); if(dvPropertyArray(property)) { dvWrtemp(dvFile, "#undef %0%1Geti%2\n" "%4 %0%1Geti%2(\n" " %3%1 _%1,\n" " uint32 x)\n" "{\n" " return (%0%1s.%2)[%0%1Get%2Index(_%1) + x];\n" "}\n\n" "#undef %0%1Get%2s\n" "%4 *%0%1Get%2s(\n" " %3%1 %1)\n" "{\n" " return %0%1s.%2 + %0%1Get%2Index(%1);\n" "}\n\n" "#undef %0%1Seti%2\n" "void %0%1Seti%2(\n" " %3%1 %1,\n" " uint32 x,\n" " %4 value)\n" "{\n" " %0%1s.%2[%0%1Get%2Index(%1) + x] = value;\n" "}\n\n", dvPrefix, name, propName, dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); dvWrtemp(dvFile, "#undef %0%1Get%2\n" "%4 *%0%1Get%2(\n" " %3%1 %1)\n" "{\n" " return %0%1s.%2 + %0%1Get%2Index(%1);\n" "}\n\n", dvPrefix, name, propName, dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); } else if(!dvPropertySparse(property)) { theUnion = dvPropertyGetUnion(property); if(dvPropertyGetType(property) == PROP_BIT) { dvWrtemp(dvFile, "#undef %0%1%2\n" "bool %0%1%2(\n" " %3%1 _%1)\n" "{\n" " return (%0%1s.%2[%3%12Index(_%1) >> 3] >> (%3%12Index(_%1) & 7)) & 1;\n" "}\n\n" "#undef %0%1Set%2\n" "void %0%1Set%2(\n" " %3%1 _%1,\n" " bool value)\n" "{\n" " uint32 x%1 = %3%12Index(_%1);\n\n" " %0%1s.%2[x%1 >> 3] = (%0%1s.%2[x%1 >> 3] & ~(1 << (x%1 & 7))) |\n" " ((value != 0) << (x%1 & 7));\n" "}\n\n", dvPrefix, name, propName, dvClassGetPrefix(theClass)); } else { if(theUnion == dvUnionNull) { dvWrtemp(dvFile, "#undef %0%1%3%2\n" "%5 %0%1%3%2(\n" " %4%1 _%1)\n" "{\n" " return %0%1s.%2[%4%12Index(_%1)];\n" "}\n\n" "#undef %0%1Set%2\n" "void %0%1Set%2(\n" " %4%1 _%1,\n" " %5 value)\n" "{\n" " %0%1s.%2[%4%12Index(_%1)] = value;\n" "}\n\n", dvPrefix, name, propName, dvPropertyGetType(property) == PROP_BOOL? "" : "Get", dvClassGetPrefix(theClass), dvPropertyGetTypeName(property)); } else { dvWrtemp(dvFile, "#undef %0%1%3%2\n" "%5 %0%1%3%2(\n" " %4%1 _%1)\n" "{\n" " return %0%1s.%6[%4%12Index(_%1)].%2;\n" "}\n\n" "#undef %0%1Set%2\n" "void %0%1Set%2(\n" " %4%1 _%1,\n" " %5 value)\n" "{\n" " %0%1s.%6[%4%12Index(_%1)].%2 = value;\n" "}\n\n", dvPrefix, name, propName, dvPropertyGetType(property) == PROP_BOOL? "" : "Get", dvClassGetPrefix(theClass), dvPropertyGetTypeName(property), dvUnionGetFieldName(theUnion)); } } } } /*-------------------------------------------------------------------------------------------------- Just write a debug function to print the object's name. --------------------------------------------------------------------------------------------------*/ static void writeChildNameDebugFunction( dvRelationship relationship) { dvClass childClass = dvRelationshipGetChildClass(relationship); dvWrtemp(dvFile, "#undef %0%2Get%1Name\n" "char *%0%2Get%1Name(\n" " %3%2 %2)\n" "{\n" " return utSymGetName(%0%2Get%1Sym(%2));\n" "}\n\n", dvPrefix, dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(childClass)); } /*-------------------------------------------------------------------------------------------------- Write debug functions for the class to access properties of its objects in a debugger. --------------------------------------------------------------------------------------------------*/ static void writeClassDebug( dvClass theClass) { dvProperty property; dvRelationship relationship; dvForeachClassProperty(theClass, property) { writePropertyDebug(property); } dvEndClassProperty; dvForeachClassChildRelationship(theClass, relationship) { if(dvRelationshipGetType(relationship) == REL_HASHED && dvRelationshipAccessChild(relationship) && dvRelationshipHashedByName(relationship)) { writeChildNameDebugFunction(relationship); } } dvEndClassChildRelationship; } /*-------------------------------------------------------------------------------------------------- Write debug functions for the module to access properties of objects in a debugger. --------------------------------------------------------------------------------------------------*/ static void writeDebug( dvModule module) { dvClass theClass; fputs("#if defined(DD_DEBUG)\n", dvFile); dvForeachModuleClass(module, theClass) { writeClassDebug(theClass); } dvEndModuleClass; fputs("#endif\n", dvFile); } /*-------------------------------------------------------------------------------------------------- See if this property is a part of the class or because of an owning/child --------------------------------------------------------------------------------------------------*/ static bool propIsClassProp( dvProperty prop) { if(dvPropertyArray(prop)) { return false; } if(dvPropertyHidden(prop)) { return false; } if(dvPropertyGetRelationship(prop) != dvRelationshipNull) { return false; } return true; } /*-------------------------------------------------------------------------------------------------- Write the class's property access macros. --------------------------------------------------------------------------------------------------*/ static void writeClassCopyPropFuncs( dvClass theClass) { dvUnion theUnion; dvProperty prop; dvPropertyType propType; char *name = dvClassGetName(theClass); char *propName; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Copy the properties of %1.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1CopyProps(\n" " %2%1 old%1,\n" " %2%1 new%1)\n" "{\n", dvPrefix, name, dvClassGetPrefix(theClass)); dvForeachClassProperty(theClass, prop) { name = dvClassGetName(theClass); propName = dvPropertyGetName(prop); if(propIsClassProp(prop)) { theUnion = dvPropertyGetUnion(prop); propType = dvPropertyGetType(prop); if(theUnion == dvUnionNull && propType != PROP_POINTER) { dvWrtemp(dvFile, " %0%1Set%2(new%1, %0%1%3%2(old%1));\n", dvPrefix, name, propName, ((propType == PROP_BOOL) || (propType == PROP_BIT))? "" : "Get"); } } } dvEndClassProperty; if(dvClassGenerateAttributes(theClass)) { dvWrtemp(dvFile, " %0%1CopyAttributes(old%1, new%1);\n", dvPrefix, name, propName, ((propType == PROP_BOOL) || (propType == PROP_BIT))? "" : "Get"); } dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- class has bit fields --------------------------------------------------------------------------------------------------*/ static bool classHasBitfields( dvClass theClass) { dvProperty prop; dvForeachClassProperty(theClass, prop) { if(dvPropertyGetType(prop) == PROP_BIT) { return true; } } dvEndClassProperty; return false; } /*-------------------------------------------------------------------------------------------------- Write the class bit field Get/Set Bitfields function. --------------------------------------------------------------------------------------------------*/ static void writeClassBitfieldFuncs( dvClass theClass) { dvProperty prop; dvUnion theUnion; char *name, *propName, *prefix; if(!classHasBitfields(theClass)) { return; } name = dvClassGetName(theClass); if(dvClassGetBaseClass(theClass) != dvClassNull) { prefix = dvClassGetPrefix(theClass); } else { prefix = dvPrefix; } dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Return the integer equivalent for the bit fields in %1.\n" "----------------------------------------------------------------------------------------*/\n" "uint32 %0%1GetBitfield(\n" " %2%1 _%1)\n" "{\n" " uint32 bitfield = 0;\n" " uint8 xLevel = 0;\n\n", dvPrefix, name, prefix); dvForeachClassProperty(theClass, prop) { if(propIsClassProp(prop) && dvPropertyGetType(prop) == PROP_BIT) { name = dvClassGetName(theClass); propName = dvPropertyGetName(prop); theUnion = dvPropertyGetUnion(prop); if(theUnion == dvUnionNull) { dvWrtemp(dvFile, " bitfield |= %0%1%2(_%1) << xLevel++;\n", dvPrefix, name, propName); } } } dvEndClassProperty; dvWrtemp(dvFile, " return bitfield;\n}\n\n"); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Set bit fields in %1 using bitfield.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1SetBitfield(\n" " %2%1 _%1,\n" " uint32 bitfield)\n" "{\n", dvPrefix, name, prefix); dvForeachClassProperty(theClass, prop) { if(propIsClassProp(prop) && dvPropertyGetType(prop) == PROP_BIT) { name = dvClassGetName(theClass); propName = dvPropertyGetName(prop); theUnion = dvPropertyGetUnion(prop); if(theUnion == dvUnionNull) { dvWrtemp(dvFile, " %0%1Set%2(_%1, bitfield & 1);\n", dvPrefix, name, propName); dvWrtemp(dvFile, " bitfield >>= 1;\n"); } } } dvEndClassProperty; dvWrtemp(dvFile, "}\n\n"); } /*-------------------------------------------------------------------------------------------------- Write the copy attrlist and attribute function. --------------------------------------------------------------------------------------------------*/ static void writeCopyAttrlistFunction(void) { char *upperPrefix = utStringToUpperCase(dvPrefix); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Make a copy of the attrlist.\n" "----------------------------------------------------------------------------------------*/\n" "%0Attribute %0CopyAttribute(\n" " %0Attribute oldAttribute)\n" "{\n" " %0Attribute newAttribute = %0AttributeAlloc();\n" " %0AttributeType type = %0AttributeGetType(oldAttribute);\n" "\n" " %0AttributeSetType(newAttribute, type);\n" " switch(type) {\n" " case %1_INT64:\n" " %0AttributeSetInt64Val(newAttribute, %0AttributeGetInt64Val(oldAttribute));\n" " break;\n" " case %1_DOUBLE:\n" " %0AttributeSetDoubleVal(newAttribute, %0AttributeGetDoubleVal(oldAttribute));\n" " break;\n" " case %1_BOOL:\n" " %0AttributeSetBoolVal(newAttribute, %0AttributeBoolVal(oldAttribute));\n" " break;\n" " case %1_SYM:\n" " %0AttributeSetSymVal(newAttribute, %0AttributeGetSymVal(oldAttribute));\n" " break;\n" " case %1_STRING: case %1_BLOB:\n" " if(%0AttributeGetNumData(oldAttribute) != 0) {\n" " %0AttributeSetData(newAttribute, %0AttributeGetData(oldAttribute),\n" " %0AttributeGetNumData(oldAttribute));\n" " }\n" " break;\n" " default:\n" " utExit(\"Unknown attribute type\");\n" " }\n" " return newAttribute;\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Make a copy of the attrlist.\n" "----------------------------------------------------------------------------------------*/\n" "%0Attrlist %0CopyAttrlist(\n" " %0Attrlist oldAttrlist)\n" "{\n" " %0Attrlist newAttrlist = %0AttrlistAlloc();\n" " %0Attribute oldAttribute, newAttribute;\n" "\n" " %0ForeachAttrlistAttribute(oldAttrlist, oldAttribute) {\n" " newAttribute = %0CopyAttribute(oldAttribute);\n" " %0AttrlistAppendAttribute(newAttrlist, newAttribute);\n" " } %0EndAttrlistAttribute;\n" " return newAttrlist;\n" "}\n\n", dvPrefix, upperPrefix); } /*-------------------------------------------------------------------------------------------------- Write get/set wrappers for the attribute type. --------------------------------------------------------------------------------------------------*/ static void writeAttributeAccess( dvClass theClass, char *type, char *typeName, char *nullVal, char *propType, char *accessString) { char *entryName = utStringToUpperCase(utSprintf("%s_%s", dvPrefix, propType)); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Get the %1's %2 attribute value.\n" "----------------------------------------------------------------------------------------*/\n" "%3 %0%1Get%2Attribute(\n" " %7%1 _%1,\n" " utSym sym)\n" "{\n" " %0Attribute attribute = %0%1FindAttribute(_%1, (sym));\n" "\n" " if(attribute == %0AttributeNull || %0AttributeGetType(attribute) != %5) {\n" " return %4;\n" " }\n" " return %0Attribute%6%2Val(attribute);\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Set the %1's %2 attribute value.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Set%2Attribute(\n" " %7%1 _%1,\n" " utSym sym,\n" " %3 value)\n" "{\n" " %0Attribute attribute = %0%1AttributeCreate(_%1, sym, %5);\n" "\n" " %0AttributeSet%2Val(attribute, value);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), typeName, type, nullVal, entryName, accessString, dvClassGetPrefix(theClass)); } /*-------------------------------------------------------------------------------------------------- Write get/set wrappers for string attributes. --------------------------------------------------------------------------------------------------*/ static void writeAttributeStringAccess( dvClass theClass) { char *upperPrefix = utStringToUpperCase(dvPrefix); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Get the %1's string attribute value.\n" "----------------------------------------------------------------------------------------*/\n" "char *%0%1GetStringAttribute(\n" " %3%1 _%1,\n" " utSym sym)\n" "{\n" " %0Attribute attribute = %0%1FindAttribute(_%1, (sym));\n" "\n" " if(attribute == %0AttributeNull || %0AttributeGetType(attribute) != %2_STRING) {\n" " return NULL;\n" " }\n" " return (char *)%0AttributeGetData(attribute);\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Set the %1's string attribute value.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1SetStringAttribute(\n" " %3%1 _%1,\n" " utSym sym,\n" " char *string)\n" "{\n" " %0Attribute attribute = %0%1AttributeCreate(_%1, sym, %2_STRING);\n" "\n" " %0AttributeSetData(attribute, (uint8 *)string, strlen(string) + 1);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), upperPrefix, dvClassGetPrefix(theClass)); } /*-------------------------------------------------------------------------------------------------- Write get/set wrappers for blob attributes. --------------------------------------------------------------------------------------------------*/ static void writeAttributeBlobAccess( dvClass theClass) { char *upperPrefix = utStringToUpperCase(dvPrefix); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Get the %1's blob attribute value.\n" "----------------------------------------------------------------------------------------*/\n" "uint8 *%0%1GetBlobAttribute(\n" " %3%1 _%1,\n" " utSym sym,\n" " uint32 *length)\n" "{\n" " %0Attribute attribute = %0%1FindAttribute(_%1, (sym));\n" "\n" " if(attribute == %0AttributeNull || %0AttributeGetType(attribute) != %2_STRING) {\n" " return NULL;\n" " }\n" " *length = %0AttributeGetNumData(attribute);\n" " return %0AttributeGetData(attribute);\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Set the %1's blob attribute value.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1SetBlobAttribute(\n" " %3%1 _%1,\n" " utSym sym,\n" " uint8 *data," " uint32 length)\n" "{\n" " %0Attribute attribute = %0%1AttributeCreate(_%1, sym, %2_BLOB);\n" "\n" " %0AttributeSetData(attribute, data, length);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), upperPrefix, dvClassGetPrefix(theClass)); } /*-------------------------------------------------------------------------------------------------- Write functions for manipulating class attributes. --------------------------------------------------------------------------------------------------*/ static void writeClassAttributeFunctions( dvClass theClass) { dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Create the attribute on the %1.\n" "----------------------------------------------------------------------------------------*/\n" "%0Attribute %0%1AttributeCreate(\n" " %2%1 _%1,\n" " utSym sym,\n" " %0AttributeType type)\n" "{\n" " %0Attrlist attrlist = %0%1GetAttrlist(_%1);\n" " %0Attribute attribute;\n" "\n" " if(attrlist == %0AttrlistNull) {\n" " attrlist = %0AttrlistAlloc();\n" " %0%1SetAttrlist(_%1, attrlist);\n" " }\n" " attribute = %0AttrlistFindAttribute(attrlist, sym);\n" " if(attribute != %0AttributeNull) {\n" " return attribute;\n" " }\n" " attribute = %0AttributeAlloc();\n" " %0AttributeSetSym(attribute, sym);\n" " %0AttributeSetType(attribute, type);\n" " %0AttrlistAppendAttribute(attrlist, attribute);\n" " return attribute;\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Delete the attribute from the %1.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1DeleteAttribute(\n" " %2%1 _%1,\n" " utSym sym)\n" "{\n" " %0Attribute attribute = %0%1FindAttribute(_%1, sym);\n" "\n" " if(attribute == %0AttributeNull) {\n" " return;\n" " }\n" " %0AttributeDestroy(attribute);\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Copy attributes from one %1 to another.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1CopyAttributes(\n" " %2%1 old%1,\n" " %2%1 new%1)\n" "{\n" " %0Attrlist oldAttrlist = %0%1GetAttrlist(old%1);\n" " %0Attrlist newAttrlist;\n" "\n" " if(oldAttrlist == %0AttrlistNull) {\n" " return;\n" " }\n" " newAttrlist = %0CopyAttrlist(oldAttrlist);\n" " %0%1SetAttrlist(new%1, newAttrlist);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass)); writeAttributeAccess(theClass, "int64", "Int64", "0", "INT64", "Get"); writeAttributeAccess(theClass, "double", "Double", "0.0", "DOUBLE", "Get"); writeAttributeAccess(theClass, "bool", "Bool", "false", "BOOL", ""); writeAttributeAccess(theClass, "utSym", "Sym", "utSymNull", "SYM", "Get"); writeAttributeStringAccess(theClass); writeAttributeBlobAccess(theClass); } /*-------------------------------------------------------------------------------------------------- Write a function to set sparse variable values. --------------------------------------------------------------------------------------------------*/ static void writeSparseFieldAccessFunction( dvProperty property) { dvClass theClass = dvPropertyGetClass(property); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Get the %1.%2 field.\n" "----------------------------------------------------------------------------------------*/\n" "%4 %0%1%7%2(\n" " %3%1 %1)\n" "{\n" " %0%5 object = %0DatadrawRootFind%5(%0FirstDatadrawRoot(), %1);\n" "\n" " if(object == %0%5Null) {\n" " return %6;\n" " }\n" " return %0%5%7%2(object);\n" "}\n" "\n" "/*----------------------------------------------------------------------------------------\n" " Set the %1.%2 field.\n" "----------------------------------------------------------------------------------------*/\n" "void %0%1Set%2(\n" " %3%1 %1,\n" " %4 value)\n" "{\n" " %0DatadrawRoot theRoot = %0FirstDatadrawRoot();\n" " %0%5 object = %0DatadrawRootFind%5(theRoot, %1);\n" "\n" " if(object == %0%5Null) {\n" " object = %0%5Alloc();\n" " %0%5Set%1Key(object, %1);\n" " %0DatadrawRootInsert%5(theRoot, object);\n" " }\n" " %0%5Set%2(object, value);\n" "}\n\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(property), dvClassGetPrefix(theClass), dvPropertyGetTypeName(property), dvSparsegroupGetName(dvPropertyGetSparsegroup(property)), dvPropertyFindInitializer(property), dvPropertyGetType(property) == PROP_BOOL? "" : "Get"); } /*-------------------------------------------------------------------------------------------------- Write functions to set sparse variable values. --------------------------------------------------------------------------------------------------*/ static void writeSparseFieldAccessFunctions( dvClass theClass) { dvProperty property; dvForeachClassProperty(theClass, property) { if(dvPropertySparse(property)) { writeSparseFieldAccessFunction(property); } } dvEndClassProperty; } /*-------------------------------------------------------------------------------------------------- Write the database support file. --------------------------------------------------------------------------------------------------*/ void dvWriteCFile( dvModule module, char *sourceFile) { dvClass theClass; dvRelationship relationship; dvRelationshipType type; char *fileName = sourceFile; bool firstAttribute = true; if(utDirectoryExists(sourceFile)) { fileName = utSprintf("%s%c%sdatabase.c", sourceFile, UTDIRSEP, dvModuleGetPrefix(module)); } dvFile = fopen(fileName, "wt"); if(dvFile == NULL) { utError("Could not open file %s", fileName); } utLogMessage("Generating C file %s", fileName); dvPrefix = dvModuleGetPrefix(module); writeFileTop(module); dvForeachModuleClass(module, theClass) { writeClassDestructor(theClass); if(dvClassGetBaseClass(theClass) != dvClassNull) { writeExtendedClassInitFunc(theClass); } else { writeConstructorDestructorWrappers(theClass); } writeClassAllocs(theClass); writeClassReallocs(theClass); if(dvClassGetBaseClass(theClass) == dvClassNull) { writeClassAllocateMore(theClass); } writeClassPropertyArrayFunctions(theClass); writeClassCopyPropFuncs(theClass); writeClassBitfieldFuncs(theClass); if(dvClassGenerateAttributes(theClass)) { if(firstAttribute) { writeCopyAttrlistFunction(); firstAttribute = false; } writeClassAttributeFunctions(theClass); } writeSparseFieldAccessFunctions(theClass); dvForeachClassChildRelationship(theClass, relationship) { if(dvRelationshipAccessChild(relationship)) { type = dvRelationshipGetType(relationship); if(type == REL_LINKED_LIST || type == REL_DOUBLY_LINKED || type == REL_TAIL_LINKED || type == REL_HASHED) { if(type == REL_HASHED) { writeHashTableResizeFunction(relationship); writeHashTableAddFunction(relationship); writeHashTableRemoveFunction(relationship); writeFindFunction(relationship); if(dvRelationshipHashedByName(relationship)) { writeRenameFunction(relationship); } } writeClassInsertFunction(theClass, relationship); if(type != REL_LINKED_LIST) { writeClassAppendFunction(theClass, relationship); } writeClassInsertAfter(theClass, relationship); writeClassRemoveFunction(theClass, relationship); } else if(type == REL_ARRAY) { writeClassArrayInsertFunction(theClass, relationship); writeClassArrayAppendFunction(theClass, relationship); if(dvRelationshipAccessParent(relationship)) { writeClassRemoveArray(theClass, relationship); } } else if(type == REL_HEAP) { writeClassArrayInsertFunction(theClass, relationship); writeClassArrayAppendFunction(theClass, relationship); writeClassRemoveArray(theClass, relationship); writeRelationshipBinaryHeapFunctions(relationship); } } } dvEndClassChildRelationship; writeClassShowFunction(theClass); } dvEndModuleClass; writeStop(module); writeStart(module); writeDebug(module); fclose(dvFile); }