From e500678daed9e5f7973df601da8491f28ff303a4 Mon Sep 17 00:00:00 2001 From: Justin Meza Date: Sun, 26 Oct 2014 20:16:26 -0700 Subject: [PATCH] scope storage and access performance optimizations --- interpreter.c | 161 ++++++++++++++++++++++++++++++++------------------ unicode.c | 29 +++++++++ unicode.h | 1 + 3 files changed, 132 insertions(+), 59 deletions(-) diff --git a/interpreter.c b/interpreter.c index 0c7f1f2..241b63a 100644 --- a/interpreter.c +++ b/interpreter.c @@ -476,6 +476,7 @@ ValueObject *createScopeValue(ScopeObject *src, void *mem1 = NULL; void *mem2 = NULL; char *name = NULL; + unsigned int pos = 0; /* Traverse the target to the terminal child and parent */ status = resolveTerminalSlot(src, dest, target, &parent, &child); @@ -488,26 +489,52 @@ ValueObject *createScopeValue(ScopeObject *src, name = resolveIdentifierName(target, src); if (!name) goto createScopeValueAbort; - /* Add value to local scope */ - mem1 = realloc(dest->names, sizeof(IdentifierNode *) * newnumvals); - if (!mem1) { - perror("realloc"); - goto createScopeValueAbort; - } - mem2 = realloc(dest->values, sizeof(ValueObject *) * newnumvals); - if (!mem2) { - perror("realloc"); - goto createScopeValueAbort; + /* realloc if power of two */ + if (newnumvals && !(newnumvals & (newnumvals - 1))) { + int allocnumvals = (newnumvals << 1); + /* Add value to local scope */ + mem1 = realloc(dest->names, sizeof(IdentifierNode *) * allocnumvals); + if (!mem1) { + perror("realloc"); + goto createScopeValueAbort; + } + mem2 = realloc(dest->values, sizeof(ValueObject *) * allocnumvals); + if (!mem2) { + perror("realloc"); + goto createScopeValueAbort; + } + } else { + mem1 = dest->names; + mem2 = dest->values; } dest->names = mem1; dest->values = mem2; - dest->names[dest->numvals] = name; - dest->values[dest->numvals] = createNilValueObject(); - if (!dest->values[dest->numvals]) goto createScopeValueAbort; + + /* Insert in lexical order */ + { + int n; + + if (dest->numvals > 0) { + /* Find insertion position */ + pos = binarySearchIndex((const char **)dest->names, 0, dest->numvals - 1, (const char *)name); + + /* Shift values down */ + for (n = dest->numvals; n > pos; n--) { + dest->names[n] = dest->names[n - 1]; + dest->values[n] = dest->values[n - 1]; + } + } + + /* Insert the value */ + dest->names[pos] = name; + dest->values[pos] = createNilValueObject(); + if (!dest->values[pos]) goto createScopeValueAbort; + } + dest->numvals = newnumvals; - return dest->values[dest->numvals - 1]; + return dest->values[pos]; createScopeValueAbort: /* In case something goes wrong... */ @@ -555,22 +582,24 @@ ValueObject *updateScopeValue(ScopeObject *src, /* Traverse upwards through scopes */ do { - unsigned int n; - /* Check for existing value in current scope */ - for (n = 0; n < parent->numvals; n++) { - if (!strcmp(parent->names[n], name)) { - free(name); - /* Wipe out the old value */ - deleteValueObject(parent->values[n]); - /* Assign the new value */ - if (value) { - parent->values[n] = value; - } - else { - parent->values[n] = createNilValueObject(); - } - return parent->values[n]; + if (parent->numvals == 0) continue; + + unsigned int n = binarySearchIndex((const char **)parent->names, 0, parent->numvals - 1, (const char *)name); + + if (n >= parent->numvals) continue; + + if (!strcmp(parent->names[n], name)) { + free(name); + /* Delete the old value */ + deleteValueObject(parent->values[n]); + /* Assign the new value */ + if (value) { + parent->values[n] = value; } + else { + parent->values[n] = createNilValueObject(); + } + return parent->values[n]; } } while ((parent = parent->parent)); @@ -822,12 +851,24 @@ ValueObject *getScopeValueLocal(ScopeObject *src, if (!name) goto getScopeValueLocalAbort; /* Check for value in current scope */ + if (dest->numvals > 0) { + n = binarySearchIndex((const char **)dest->names, 0, dest->numvals - 1, (const char *)name); + + if (n < dest->numvals) { + if (!strcmp(dest->names[n], name)) { + free(name); + return dest->values[n]; + } + } + } + /* for (n = 0; n < dest->numvals; n++) { if (!strcmp(dest->names[n], name)) { free(name); return dest->values[n]; } } + */ getScopeValueLocalAbort: /* In case something goes wrong... */ @@ -954,37 +995,39 @@ void deleteScopeValue(ScopeObject *src, /* Traverse upwards through scopes */ do { - unsigned int n; - /* Check for existing value in current scope */ - for (n = 0; n < current->numvals; n++) { - if (!strcmp(current->names[n], name)) { - unsigned int i; - unsigned int newnumvals = dest->numvals - 1; - free(name); - /* Wipe out the name and value */ - free(current->names[n]); - deleteValueObject(current->values[n]); - /* Reorder the tables */ - for (i = n; i < current->numvals - 1; i++) { - current->names[i] = current->names[i + 1]; - current->values[i] = current->values[i + 1]; - } - /* Resize the tables */ - mem1 = realloc(dest->names, sizeof(IdentifierNode *) * newnumvals); - if (!mem1) { - perror("realloc"); - goto deleteScopeValueAbort; - } - mem2 = realloc(dest->values, sizeof(ValueObject *) * newnumvals); - if (!mem2) { - perror("realloc"); - goto deleteScopeValueAbort; - } - dest->names = mem1; - dest->values = mem2; - dest->numvals = newnumvals; - return; + if (current->numvals == 0) continue; + + unsigned int n = binarySearchIndex((const char **)current->names, 0, current->numvals - 1, (const char *)name); + + if (n >= current->numvals) continue; + + if (!strcmp(current->names[n], name)) { + unsigned int i; + unsigned int newnumvals = dest->numvals - 1; + free(name); + /* Wipe out the name and value */ + free(current->names[n]); + deleteValueObject(current->values[n]); + /* Reorder the tables */ + for (i = n; i < current->numvals - 1; i++) { + current->names[i] = current->names[i + 1]; + current->values[i] = current->values[i + 1]; } + /* Resize the tables */ + mem1 = realloc(dest->names, sizeof(IdentifierNode *) * newnumvals); + if (!mem1) { + perror("realloc"); + goto deleteScopeValueAbort; + } + mem2 = realloc(dest->values, sizeof(ValueObject *) * newnumvals); + if (!mem2) { + perror("realloc"); + goto deleteScopeValueAbort; + } + dest->names = mem1; + dest->values = mem2; + dest->numvals = newnumvals; + return; } } while ((current = current->parent)); diff --git a/unicode.c b/unicode.c index a7d2abf..4765591 100644 --- a/unicode.c +++ b/unicode.c @@ -43533,6 +43533,35 @@ int binarySearch(const char **strings, return -1; } +/** + * Performs a binary search on an array of strings. + * + * \param [in] strings The array of string to search. + * \param [in] start The index to start searching at. + * \param [in] end The index to end searching at. + * \param [in] find The string to search for. + * + * \return The index where the string would appear. + */ +unsigned int binarySearchIndex(const char **strings, + int start, + int end, + const char *find) +{ + int midpoint; + int cmp; + if (end < start) return start; + midpoint = ((end - start) / 2) + start; + cmp = strcmp(strings[midpoint], find); + if (cmp == 0) + return midpoint; + else if (cmp > 0) + return binarySearchIndex(strings, start, midpoint - 1, find); + else if (cmp < 0) + return binarySearchIndex(strings, midpoint + 1, end, find); + return -1; +} + /** * Converts a Unicode normative name to a Unicode code point. * diff --git a/unicode.h b/unicode.h index c4ddf46..635a29d 100644 --- a/unicode.h +++ b/unicode.h @@ -16,6 +16,7 @@ #include int binarySearch(const char **, int, int, const char *); +unsigned int binarySearchIndex(const char **, int, int, const char *); long convertNormativeNameToCodePoint(const char *); size_t convertCodePointToUTF8(unsigned long, char *);