summaryrefslogtreecommitdiff
path: root/Src/params.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/params.c')
-rw-r--r--Src/params.c92
1 files changed, 89 insertions, 3 deletions
diff --git a/Src/params.c b/Src/params.c
index 8a0ed5143..d960c22cf 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -3456,18 +3456,104 @@ tiedarrunsetfn(Param pm, UNUSED(int exp))
/**/
static void
-arrayuniq(char **x, int freeok)
+simple_arrayuniq(char **x, int freeok)
{
char **t, **p = x;
+ char *hole = "";
+ /* Find duplicates and replace them with holes */
while (*++p)
for (t = x; t < p; t++)
- if (!strcmp(*p, *t)) {
+ if (*t != hole && !strcmp(*p, *t)) {
if (freeok)
zsfree(*p);
- for (t = p--; (*t = t[1]) != NULL; t++);
+ *p = hole;
break;
}
+ /* Swap non-holes into holes in optimal jumps */
+ for (p = t = x; *t != NULL; t++) {
+ if (*t == hole) {
+ while (*p == hole)
+ ++p;
+ if ((*t = *p) != NULL)
+ *p++ = hole;
+ } else if (p == t)
+ p++;
+ }
+ /* Erase all the remaining holes, just in case */
+ while (++t < p)
+ *t = NULL;
+}
+
+/**/
+static void
+arrayuniq_freenode(HashNode hn)
+{
+ (void)hn;
+}
+
+/**/
+static HashTable
+newuniqtable(zlong size)
+{
+ HashTable ht = newhashtable((int)size, "arrayuniq", NULL);
+ /* ??? error checking */
+
+ ht->hash = hasher;
+ ht->emptytable = emptyhashtable;
+ ht->filltable = NULL;
+ ht->cmpnodes = strcmp;
+ ht->addnode = addhashnode;
+ ht->getnode = gethashnode2;
+ ht->getnode2 = gethashnode2;
+ ht->removenode = removehashnode;
+ ht->disablenode = disablehashnode;
+ ht->enablenode = enablehashnode;
+ ht->freenode = arrayuniq_freenode;
+ ht->printnode = NULL;
+
+ return ht;
+}
+
+/**/
+static void
+arrayuniq(char **x, int freeok)
+{
+ char **it, **write_it;
+ zlong array_size = arrlen(x);
+ HashTable ht;
+
+ if (array_size == 0)
+ return;
+ if (array_size < 10 || !(ht = newuniqtable(array_size + 1))) {
+ /* fallback to simpler routine */
+ simple_arrayuniq(x, freeok);
+ return;
+ }
+
+ for (it = x, write_it = x; *it;) {
+ if (! gethashnode(ht, *it)) {
+ HashNode new_node = zhalloc(sizeof(struct hashnode));
+ if (!new_node) {
+ /* Oops, out of heap memory, no way to recover */
+ zerr("out of memory in arrayuniq");
+ break;
+ }
+ (void) addhashnode2(ht, *it, new_node);
+ *write_it = *it;
+ if (it != write_it)
+ *it = NULL;
+ ++write_it;
+ }
+ else {
+ if (freeok)
+ zsfree(*it);
+ *it = NULL;
+ }
+ ++it;
+ }
+
+ deletehashtable(ht);
}
/**/