]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Rename hash.h and hash.c to virhash.h and virhash.c
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 25 Jan 2012 16:13:59 +0000 (16:13 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 26 Jan 2012 14:11:13 +0000 (14:11 +0000)
In preparation for the patch to include Murmurhash3, which
introduces a virhashcode.h and virhashcode.c files, rename
the existing hash.h and hash.c to virhash.h and virhash.c
respectively.

21 files changed:
po/POTFILES.in
src/Makefile.am
src/conf/domain_conf.h
src/conf/nwfilter_conf.h
src/conf/nwfilter_params.h
src/cpu/cpu_generic.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_text.h
src/uml/uml_conf.h
src/util/cgroup.c
src/util/hash.c [deleted file]
src/util/hash.h [deleted file]
src/util/virhash.c [new file with mode: 0644]
src/util/virhash.h [new file with mode: 0644]
src/xen/xen_driver.h
src/xen/xm_internal.c
tests/Makefile.am
tests/hashdata.h [deleted file]
tests/hashtest.c [deleted file]
tests/virhashdata.h [new file with mode: 0644]
tests/virhashtest.c [new file with mode: 0644]

index 0126320ec4666e4a9ac727672db57a3e2e1c61fe..674d6df578808b6867c1f478e020cfd692807638 100644 (file)
@@ -110,7 +110,6 @@ src/util/command.c
 src/util/conf.c
 src/util/dnsmasq.c
 src/util/event_poll.c
-src/util/hash.c
 src/util/hooks.c
 src/util/hostusb.c
 src/util/iohelper.c
@@ -126,6 +125,7 @@ src/util/sysinfo.c
 src/util/util.c
 src/util/viraudit.c
 src/util/virfile.c
+src/util/virhash.c
 src/util/virnetdev.c
 src/util/virnetdevbridge.c
 src/util/virnetdevmacvlan.c
index 4629700a0daba002e5cc61cd428cb26f3367044b..eacc741e0eef1ebe69b3025e81147277c97330f1 100644 (file)
@@ -60,7 +60,6 @@ UTIL_SOURCES =                                                        \
                util/cgroup.c util/cgroup.h                     \
                util/event.c util/event.h                       \
                util/event_poll.c util/event_poll.h             \
-               util/hash.c util/hash.h                         \
                util/hooks.c util/hooks.h                       \
                util/iptables.c util/iptables.h                 \
                util/ebtables.c util/ebtables.h                 \
@@ -90,6 +89,7 @@ UTIL_SOURCES =                                                        \
                util/virtypedparam.c util/virtypedparam.h       \
                util/xml.c util/xml.h                           \
                util/virterror.c util/virterror_internal.h      \
+               util/virhash.c util/virhash.h                   \
                util/virkeycode.c util/virkeycode.h             \
                util/virkeymaps.h                               \
                util/virnetdev.h util/virnetdev.c               \
index 3b522a9a28113ddf7b366ef28a6ba4b4abcab4da..7a8f12dd81a2038e1fe1db39fd79e7fa86f9c229 100644 (file)
@@ -34,7 +34,7 @@
 # include "cpu_conf.h"
 # include "util.h"
 # include "threads.h"
-# include "hash.h"
+# include "virhash.h"
 # include "virsocketaddr.h"
 # include "nwfilter_params.h"
 # include "nwfilter_conf.h"
index 4331ab1831da85a00bb5f5c13f8ac13de6e7d8e5..3cb4b82f379ec688d0d53f225562c22ba5c79638 100644 (file)
@@ -32,7 +32,7 @@
 # include "internal.h"
 
 # include "util.h"
-# include "hash.h"
+# include "virhash.h"
 # include "xml.h"
 # include "buf.h"
 # include "virsocketaddr.h"
index fa8f770f232e5ef8e555a8b473f3bbf1177f16df..eab46ec573b76bce03c61489bd67de01807273da 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef NWFILTER_PARAMS_H
 # define NWFILTER_PARAMS_H
 
-# include "hash.h"
+# include "virhash.h"
 # include "buf.h"
 
 enum virNWFilterVarValueType {
index a98b10900a19d849d8bfaa0ac52beb130df08f45..2a31b49243ffd334110e93038c080fa2b2c3ed9c 100644 (file)
@@ -25,7 +25,7 @@
 #include <config.h>
 
 #include "memory.h"
-#include "hash.h"
+#include "virhash.h"
 #include "cpu.h"
 #include "cpu_generic.h"
 
index 15acf8b7740862c0482be63931eef2d427a8758d..88ce303dd90d9441df41e69f0e641ec43f7628fd 100644 (file)
@@ -29,7 +29,7 @@
 
 # include "domain_conf.h"
 # include "qemu_conf.h"
-# include "hash.h"
+# include "virhash.h"
 
 typedef struct _qemuMonitor qemuMonitor;
 typedef qemuMonitor *qemuMonitorPtr;
index dee29809da817e3699f7d199568093feb7489c1c..47a946d292351fbb63784a755362febed56fc6af 100644 (file)
@@ -28,7 +28,6 @@
 # include "internal.h"
 
 # include "qemu_monitor.h"
-# include "hash.h"
 
 int qemuMonitorTextIOProcess(qemuMonitorPtr mon,
                              const char *data,
index 383ae6600dbd271e333126c2afebe8618f0eb4f7..f942116ecafa06d2f2fb4f812f00a1bad2bd2a5e 100644 (file)
@@ -32,7 +32,7 @@
 # include "virterror_internal.h"
 # include "threads.h"
 # include "command.h"
-# include "hash.h"
+# include "virhash.h"
 
 # define umlDebug(fmt, ...) do {} while(0)
 
index 32f59c8230dcb0b76436a70ef249801704f8e99f..e1a90b2a9a6dd66b6280958716fb433acaadbbf8 100644 (file)
@@ -32,7 +32,7 @@
 #include "cgroup.h"
 #include "logging.h"
 #include "virfile.h"
-#include "hash.h"
+#include "virhash.h"
 
 #define CGROUP_MAX_VAL 512
 
diff --git a/src/util/hash.c b/src/util/hash.c
deleted file mode 100644 (file)
index 20d3a12..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
- * hash.c: chained hash tables for domain and domain/connection deallocations
- *
- * Reference: Your favorite introductory book on algorithms
- *
- * Copyright (C) 2011 Red Hat, Inc.
- * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
- * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
- *
- * Author: breese@users.sourceforge.net
- *         Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "virterror_internal.h"
-#include "hash.h"
-#include "memory.h"
-#include "logging.h"
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-#define MAX_HASH_LEN 8
-
-/* #define DEBUG_GROW */
-
-#define virHashIterationError(ret)                                      \
-    do {                                                                \
-        VIR_ERROR(_("Hash operation not allowed during iteration"));   \
-        return ret;                                                     \
-    } while (0)
-
-/*
- * A single entry in the hash table
- */
-typedef struct _virHashEntry virHashEntry;
-typedef virHashEntry *virHashEntryPtr;
-struct _virHashEntry {
-    struct _virHashEntry *next;
-    void *name;
-    void *payload;
-};
-
-/*
- * The entire hash table
- */
-struct _virHashTable {
-    virHashEntryPtr *table;
-    size_t size;
-    size_t nbElems;
-    /* True iff we are iterating over hash entries. */
-    bool iterating;
-    /* Pointer to the current entry during iteration. */
-    virHashEntryPtr current;
-    virHashDataFree dataFree;
-    virHashKeyCode keyCode;
-    virHashKeyEqual keyEqual;
-    virHashKeyCopy keyCopy;
-    virHashKeyFree keyFree;
-};
-
-static uint32_t virHashStrCode(const void *name)
-{
-    const char *str = name;
-    uint32_t value = 0L;
-    char ch;
-
-    if (str != NULL) {
-        value += 30 * (*str);
-        while ((ch = *str++) != 0) {
-            value =
-                value ^ ((value << 5) + (value >> 3) + (uint32_t) ch);
-        }
-    }
-    return value;
-}
-
-static bool virHashStrEqual(const void *namea, const void *nameb)
-{
-    return STREQ(namea, nameb);
-}
-
-static void *virHashStrCopy(const void *name)
-{
-    return strdup(name);
-}
-
-static void virHashStrFree(void *name)
-{
-    VIR_FREE(name);
-}
-
-
-static size_t
-virHashComputeKey(virHashTablePtr table, const void *name)
-{
-    uint32_t value = table->keyCode(name);
-    return (value % table->size);
-}
-
-/**
- * virHashCreateFull:
- * @size: the size of the hash table
- * @dataFree: callback to free data
- * @keyCode: callback to compute hash code
- * @keyEqual: callback to compare hash keys
- * @keyCopy: callback to copy hash keys
- * @keyFree: callback to free keys
- *
- * Create a new virHashTablePtr.
- *
- * Returns the newly created object, or NULL if an error occurred.
- */
-virHashTablePtr virHashCreateFull(ssize_t size,
-                                  virHashDataFree dataFree,
-                                  virHashKeyCode keyCode,
-                                  virHashKeyEqual keyEqual,
-                                  virHashKeyCopy keyCopy,
-                                  virHashKeyFree keyFree)
-{
-    virHashTablePtr table = NULL;
-
-    if (size <= 0)
-        size = 256;
-
-    if (VIR_ALLOC(table) < 0) {
-        virReportOOMError();
-        return NULL;
-    }
-
-    table->size = size;
-    table->nbElems = 0;
-    table->dataFree = dataFree;
-    table->keyCode = keyCode;
-    table->keyEqual = keyEqual;
-    table->keyCopy = keyCopy;
-    table->keyFree = keyFree;
-
-    if (VIR_ALLOC_N(table->table, size) < 0) {
-        virReportOOMError();
-        VIR_FREE(table);
-        return NULL;
-    }
-
-    return table;
-}
-
-
-/**
- * virHashCreate:
- * @size: the size of the hash table
- * @dataFree: callback to free data
- *
- * Create a new virHashTablePtr.
- *
- * Returns the newly created object, or NULL if an error occurred.
- */
-virHashTablePtr virHashCreate(ssize_t size, virHashDataFree dataFree)
-{
-    return virHashCreateFull(size,
-                             dataFree,
-                             virHashStrCode,
-                             virHashStrEqual,
-                             virHashStrCopy,
-                             virHashStrFree);
-}
-
-/**
- * virHashGrow:
- * @table: the hash table
- * @size: the new size of the hash table
- *
- * resize the hash table
- *
- * Returns 0 in case of success, -1 in case of failure
- */
-static int
-virHashGrow(virHashTablePtr table, size_t size)
-{
-    size_t oldsize, i;
-    virHashEntryPtr *oldtable;
-
-#ifdef DEBUG_GROW
-    size_t nbElem = 0;
-#endif
-
-    if (table == NULL)
-        return (-1);
-    if (size < 8)
-        return (-1);
-    if (size > 8 * 2048)
-        return (-1);
-
-    oldsize = table->size;
-    oldtable = table->table;
-    if (oldtable == NULL)
-        return (-1);
-
-    if (VIR_ALLOC_N(table->table, size) < 0) {
-        virReportOOMError();
-        table->table = oldtable;
-        return (-1);
-    }
-    table->size = size;
-
-    for (i = 0; i < oldsize; i++) {
-        virHashEntryPtr iter = oldtable[i];
-        while (iter) {
-            virHashEntryPtr next = iter->next;
-            size_t key = virHashComputeKey(table, iter->name);
-
-            iter->next = table->table[key];
-            table->table[key] = iter;
-
-#ifdef DEBUG_GROW
-            nbElem++;
-#endif
-            iter = next;
-        }
-    }
-
-    VIR_FREE(oldtable);
-
-#ifdef DEBUG_GROW
-    VIR_DEBUG("virHashGrow : from %d to %d, %ld elems\n", oldsize,
-              size, nbElem);
-#endif
-
-    return (0);
-}
-
-/**
- * virHashFree:
- * @table: the hash table
- *
- * Free the hash @table and its contents. The userdata is
- * deallocated with function provided at creation time.
- */
-void
-virHashFree(virHashTablePtr table)
-{
-    size_t i;
-
-    if (table == NULL)
-        return;
-
-    for (i = 0; i < table->size; i++) {
-        virHashEntryPtr iter = table->table[i];
-        while (iter) {
-            virHashEntryPtr next = iter->next;
-
-            if (table->dataFree)
-                table->dataFree(iter->payload, iter->name);
-            if (table->keyFree)
-                table->keyFree(iter->name);
-            VIR_FREE(iter);
-            iter = next;
-        }
-    }
-
-    VIR_FREE(table->table);
-    VIR_FREE(table);
-}
-
-static int
-virHashAddOrUpdateEntry(virHashTablePtr table, const void *name,
-                        void *userdata,
-                        bool is_update)
-{
-    size_t key, len = 0;
-    virHashEntryPtr entry;
-    char *new_name;
-
-    if ((table == NULL) || (name == NULL))
-        return (-1);
-
-    if (table->iterating)
-        virHashIterationError(-1);
-
-    key = virHashComputeKey(table, name);
-
-    /* Check for duplicate entry */
-    for (entry = table->table[key]; entry; entry = entry->next) {
-        if (table->keyEqual(entry->name, name)) {
-            if (is_update) {
-                if (table->dataFree)
-                    table->dataFree(entry->payload, entry->name);
-                entry->payload = userdata;
-                return 0;
-            } else {
-                return -1;
-            }
-        }
-        len++;
-    }
-
-    if (VIR_ALLOC(entry) < 0 || !(new_name = table->keyCopy(name))) {
-        virReportOOMError();
-        VIR_FREE(entry);
-        return -1;
-    }
-
-    entry->name = new_name;
-    entry->payload = userdata;
-    entry->next = table->table[key];
-    table->table[key] = entry;
-
-    table->nbElems++;
-
-    if (len > MAX_HASH_LEN)
-        virHashGrow(table, MAX_HASH_LEN * table->size);
-
-    return 0;
-}
-
-/**
- * virHashAddEntry:
- * @table: the hash table
- * @name: the name of the userdata
- * @userdata: a pointer to the userdata
- *
- * Add the @userdata to the hash @table. This can later be retrieved
- * by using @name. Duplicate entries generate errors.
- *
- * Returns 0 the addition succeeded and -1 in case of error.
- */
-int
-virHashAddEntry(virHashTablePtr table, const void *name, void *userdata)
-{
-    return virHashAddOrUpdateEntry(table, name, userdata, false);
-}
-
-/**
- * virHashUpdateEntry:
- * @table: the hash table
- * @name: the name of the userdata
- * @userdata: a pointer to the userdata
- *
- * Add the @userdata to the hash @table. This can later be retrieved
- * by using @name. Existing entry for this tuple
- * will be removed and freed with @f if found.
- *
- * Returns 0 the addition succeeded and -1 in case of error.
- */
-int
-virHashUpdateEntry(virHashTablePtr table, const void *name,
-                   void *userdata)
-{
-    return virHashAddOrUpdateEntry(table, name, userdata, true);
-}
-
-/**
- * virHashLookup:
- * @table: the hash table
- * @name: the name of the userdata
- *
- * Find the userdata specified by @name
- *
- * Returns the a pointer to the userdata
- */
-void *
-virHashLookup(virHashTablePtr table, const void *name)
-{
-    size_t key;
-    virHashEntryPtr entry;
-
-    if (!table || !name)
-        return NULL;
-
-    key = virHashComputeKey(table, name);
-    for (entry = table->table[key]; entry; entry = entry->next) {
-        if (table->keyEqual(entry->name, name))
-            return entry->payload;
-    }
-    return NULL;
-}
-
-
-/**
- * virHashSteal:
- * @table: the hash table
- * @name: the name of the userdata
- *
- * Find the userdata specified by @name
- * and remove it from the hash without freeing it.
- *
- * Returns the a pointer to the userdata
- */
-void *virHashSteal(virHashTablePtr table, const void *name)
-{
-    void *data = virHashLookup(table, name);
-    if (data) {
-        virHashDataFree dataFree = table->dataFree;
-        table->dataFree = NULL;
-        virHashRemoveEntry(table, name);
-        table->dataFree = dataFree;
-    }
-    return data;
-}
-
-
-/**
- * virHashSize:
- * @table: the hash table
- *
- * Query the number of elements installed in the hash @table.
- *
- * Returns the number of elements in the hash table or
- * -1 in case of error
- */
-ssize_t
-virHashSize(virHashTablePtr table)
-{
-    if (table == NULL)
-        return (-1);
-    return (table->nbElems);
-}
-
-/**
- * virHashTableSize:
- * @table: the hash table
- *
- * Query the size of the hash @table, i.e., number of buckets in the table.
- *
- * Returns the number of keys in the hash table or
- * -1 in case of error
- */
-ssize_t
-virHashTableSize(virHashTablePtr table)
-{
-    if (table == NULL)
-        return -1;
-    return table->size;
-}
-
-
-/**
- * virHashRemoveEntry:
- * @table: the hash table
- * @name: the name of the userdata
- *
- * Find the userdata specified by the @name and remove
- * it from the hash @table. Existing userdata for this tuple will be removed
- * and freed with @f.
- *
- * Returns 0 if the removal succeeded and -1 in case of error or not found.
- */
-int
-virHashRemoveEntry(virHashTablePtr table, const void *name)
-{
-    virHashEntryPtr entry;
-    virHashEntryPtr *nextptr;
-
-    if (table == NULL || name == NULL)
-        return (-1);
-
-    nextptr = table->table + virHashComputeKey(table, name);
-    for (entry = *nextptr; entry; entry = entry->next) {
-        if (table->keyEqual(entry->name, name)) {
-            if (table->iterating && table->current != entry)
-                virHashIterationError(-1);
-
-            if (table->dataFree)
-                table->dataFree(entry->payload, entry->name);
-            if (table->keyFree)
-                table->keyFree(entry->name);
-            *nextptr = entry->next;
-            VIR_FREE(entry);
-            table->nbElems--;
-            return 0;
-        }
-        nextptr = &entry->next;
-    }
-
-    return -1;
-}
-
-
-/**
- * virHashForEach
- * @table: the hash table to process
- * @iter: callback to process each element
- * @data: opaque data to pass to the iterator
- *
- * Iterates over every element in the hash table, invoking the
- * 'iter' callback. The callback is allowed to remove the current element
- * using virHashRemoveEntry but calling other virHash* functions is prohibited.
- *
- * Returns number of items iterated over upon completion, -1 on failure
- */
-ssize_t
-virHashForEach(virHashTablePtr table, virHashIterator iter, void *data)
-{
-    size_t i, count = 0;
-
-    if (table == NULL || iter == NULL)
-        return (-1);
-
-    if (table->iterating)
-        virHashIterationError(-1);
-
-    table->iterating = true;
-    table->current = NULL;
-    for (i = 0 ; i < table->size ; i++) {
-        virHashEntryPtr entry = table->table[i];
-        while (entry) {
-            virHashEntryPtr next = entry->next;
-
-            table->current = entry;
-            iter(entry->payload, entry->name, data);
-            table->current = NULL;
-
-            count++;
-            entry = next;
-        }
-    }
-    table->iterating = false;
-
-    return (count);
-}
-
-/**
- * virHashRemoveSet
- * @table: the hash table to process
- * @iter: callback to identify elements for removal
- * @data: opaque data to pass to the iterator
- *
- * Iterates over all elements in the hash table, invoking the 'iter'
- * callback. If the callback returns a non-zero value, the element
- * will be removed from the hash table & its payload passed to the
- * data freer callback registered at creation.
- *
- * Returns number of items removed on success, -1 on failure
- */
-ssize_t
-virHashRemoveSet(virHashTablePtr table,
-                 virHashSearcher iter,
-                 const void *data)
-{
-    size_t i, count = 0;
-
-    if (table == NULL || iter == NULL)
-        return (-1);
-
-    if (table->iterating)
-        virHashIterationError(-1);
-
-    table->iterating = true;
-    table->current = NULL;
-    for (i = 0 ; i < table->size ; i++) {
-        virHashEntryPtr *nextptr = table->table + i;
-
-        while (*nextptr) {
-            virHashEntryPtr entry = *nextptr;
-            if (!iter(entry->payload, entry->name, data)) {
-                nextptr = &entry->next;
-            } else {
-                count++;
-                if (table->dataFree)
-                    table->dataFree(entry->payload, entry->name);
-                if (table->keyFree)
-                    table->keyFree(entry->name);
-                *nextptr = entry->next;
-                VIR_FREE(entry);
-                table->nbElems--;
-            }
-        }
-    }
-    table->iterating = false;
-
-    return count;
-}
-
-/**
- * virHashSearch:
- * @table: the hash table to search
- * @iter: an iterator to identify the desired element
- * @data: extra opaque information passed to the iter
- *
- * Iterates over the hash table calling the 'iter' callback
- * for each element. The first element for which the iter
- * returns non-zero will be returned by this function.
- * The elements are processed in a undefined order
- */
-void *virHashSearch(virHashTablePtr table,
-                    virHashSearcher iter,
-                    const void *data)
-{
-    size_t i;
-
-    if (table == NULL || iter == NULL)
-        return (NULL);
-
-    if (table->iterating)
-        virHashIterationError(NULL);
-
-    table->iterating = true;
-    table->current = NULL;
-    for (i = 0 ; i < table->size ; i++) {
-        virHashEntryPtr entry;
-        for (entry = table->table[i]; entry; entry = entry->next) {
-            if (iter(entry->payload, entry->name, data)) {
-                table->iterating = false;
-                return entry->payload;
-            }
-        }
-    }
-    table->iterating = false;
-
-    return NULL;
-}
-
-struct getKeysIter
-{
-    virHashKeyValuePair *sortArray;
-    size_t arrayIdx;
-};
-
-static void virHashGetKeysIterator(void *payload,
-                                   const void *key, void *data)
-{
-    struct getKeysIter *iter = data;
-
-    iter->sortArray[iter->arrayIdx].key = key;
-    iter->sortArray[iter->arrayIdx].value = payload;
-
-    iter->arrayIdx++;
-}
-
-typedef int (*qsort_comp)(const void *, const void *);
-
-virHashKeyValuePairPtr virHashGetItems(virHashTablePtr table,
-                                       virHashKeyComparator compar)
-{
-    ssize_t numElems = virHashSize(table);
-    struct getKeysIter iter = {
-        .arrayIdx = 0,
-        .sortArray = NULL,
-    };
-
-    if (numElems < 0)
-        return NULL;
-
-    if (VIR_ALLOC_N(iter.sortArray, numElems + 1)) {
-        virReportOOMError();
-        return NULL;
-    }
-
-    virHashForEach(table, virHashGetKeysIterator, &iter);
-
-    if (compar)
-        qsort(&iter.sortArray[0], numElems, sizeof(iter.sortArray[0]),
-              (qsort_comp)compar);
-
-    return iter.sortArray;
-}
-
-struct virHashEqualData
-{
-    bool equal;
-    const virHashTablePtr table2;
-    virHashValueComparator compar;
-};
-
-static int virHashEqualSearcher(const void *payload, const void *name,
-                                const void *data)
-{
-    struct virHashEqualData *vhed = (void *)data;
-    const void *value;
-
-    value = virHashLookup(vhed->table2, name);
-    if (!value ||
-        vhed->compar(value, payload) != 0) {
-        /* key is missing in 2nd table or values are different */
-        vhed->equal = false;
-        /* stop 'iteration' */
-        return 1;
-    }
-    return 0;
-}
-
-bool virHashEqual(const virHashTablePtr table1,
-                  const virHashTablePtr table2,
-                  virHashValueComparator compar)
-{
-    struct virHashEqualData data = {
-        .equal = true,
-        .table2 = table2,
-        .compar = compar,
-    };
-
-    if (table1 == table2)
-        return true;
-
-    if (!table1 || !table2 ||
-        virHashSize(table1) != virHashSize(table2))
-        return false;
-
-    virHashSearch(table1, virHashEqualSearcher, &data);
-
-    return data.equal;
-}
diff --git a/src/util/hash.h b/src/util/hash.h
deleted file mode 100644 (file)
index 2420045..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Summary: Chained hash tables and domain/connections handling
- * Description: This module implements the hash table and allocation and
- *              deallocation of domains and connections
- *
- * Copy: Copyright (C) 2005, 2011 Red Hat, Inc.
- *
- * Author: Bjorn Reese <bjorn.reese@systematic.dk>
- *         Daniel Veillard <veillard@redhat.com>
- */
-
-#ifndef __VIR_HASH_H__
-# define __VIR_HASH_H__
-
-/*
- * The hash table.
- */
-typedef struct _virHashTable virHashTable;
-typedef virHashTable *virHashTablePtr;
-
-/*
- * function types:
- */
-
-/**
- * virHashDataFree:
- * @payload:  the data in the hash
- * @name:  the name associated
- *
- * Callback to free data from a hash.
- */
-typedef void (*virHashDataFree) (void *payload, const void *name);
-/**
- * virHashIterator:
- * @payload: the data in the hash
- * @name: the hash key
- * @data: user supplied data blob
- *
- * Callback to process a hash entry during iteration
- */
-typedef void (*virHashIterator) (void *payload, const void *name, void *data);
-/**
- * virHashSearcher:
- * @payload: the data in the hash
- * @name: the hash key
- * @data: user supplied data blob
- *
- * Callback to identify hash entry desired
- * Returns 1 if the hash entry is desired, 0 to move
- * to next entry
- */
-typedef int (*virHashSearcher) (const void *payload, const void *name,
-                                const void *data);
-
-/**
- * virHashKeyCode:
- * @name: the hash key
- *
- * Compute the hash code corresponding to the key @name
- *
- * Returns the hash code
- */
-typedef uint32_t (*virHashKeyCode)(const void *name);
-/**
- * virHashKeyEqual:
- * @namea: the first hash key
- * @nameb: the second hash key
- *
- * Compare two hash keys for equality
- *
- * Returns true if the keys are equal, false otherwise
- */
-typedef bool (*virHashKeyEqual)(const void *namea, const void *nameb);
-/**
- * virHashKeyCopy:
- * @name: the hash key
- *
- * Create a copy of the hash key, duplicating
- * memory allocation where applicable
- *
- * Returns a newly allocated copy of @name
- */
-typedef void *(*virHashKeyCopy)(const void *name);
-/**
- * virHashKeyFree:
- * @name: the hash key
- *
- * Free any memory associated with the hash
- * key @name
- */
-typedef void (*virHashKeyFree)(void *name);
-
-/*
- * Constructor and destructor.
- */
-virHashTablePtr virHashCreate(ssize_t size,
-                              virHashDataFree dataFree);
-virHashTablePtr virHashCreateFull(ssize_t size,
-                                  virHashDataFree dataFree,
-                                  virHashKeyCode keyCode,
-                                  virHashKeyEqual keyEqual,
-                                  virHashKeyCopy keyCopy,
-                                  virHashKeyFree keyFree);
-void virHashFree(virHashTablePtr table);
-ssize_t virHashSize(virHashTablePtr table);
-ssize_t virHashTableSize(virHashTablePtr table);
-
-/*
- * Add a new entry to the hash table.
- */
-int virHashAddEntry(virHashTablePtr table,
-                    const void *name, void *userdata);
-int virHashUpdateEntry(virHashTablePtr table,
-                       const void *name,
-                       void *userdata);
-
-/*
- * Remove an entry from the hash table.
- */
-int virHashRemoveEntry(virHashTablePtr table,
-                       const void *name);
-
-/*
- * Retrieve the userdata.
- */
-void *virHashLookup(virHashTablePtr table, const void *name);
-
-/*
- * Retrieve & remove the userdata.
- */
-void *virHashSteal(virHashTablePtr table, const void *name);
-
-/*
- * Get the hash table's key/value pairs and have them optionally sorted.
- * The returned array contains virHashSize() elements. Additionally,
- * an empty element has been added to the end of the array (with key == NULL)
- * to indicate the end of the array.
- * The key/value pairs are only valid as long as the underlying hash
- * table is not modified, i.e., no keys are removed or inserted, and
- * the hash table is not deleted.
- * The caller must only free the returned array using VIR_FREE().
- * The caller must make copies of all returned keys and values if they are
- * to be used somewhere else.
- */
-typedef struct _virHashKeyValuePair virHashKeyValuePair;
-typedef virHashKeyValuePair *virHashKeyValuePairPtr;
-struct _virHashKeyValuePair {
-    const void *key;
-    const void *value;
-};
-typedef int (*virHashKeyComparator)(const virHashKeyValuePairPtr,
-                                    const virHashKeyValuePairPtr);
-virHashKeyValuePairPtr virHashGetItems(virHashTablePtr table,
-                                       virHashKeyComparator compar);
-
-/*
- * Compare two tables for equality: the lookup of a key's value in
- * both tables must result in an equivalent value.
- * The caller must pass in a comparator function for comparing the values
- * of two keys.
- */
-typedef int (*virHashValueComparator)(const void *value1, const void *value2);
-bool virHashEqual(const virHashTablePtr table1,
-                  const virHashTablePtr table2,
-                  virHashValueComparator compar);
-
-
-/*
- * Iterators
- */
-ssize_t virHashForEach(virHashTablePtr table, virHashIterator iter, void *data);
-ssize_t virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, const void *data);
-void *virHashSearch(virHashTablePtr table, virHashSearcher iter, const void *data);
-
-#endif                          /* ! __VIR_HASH_H__ */
diff --git a/src/util/virhash.c b/src/util/virhash.c
new file mode 100644 (file)
index 0000000..238a6fe
--- /dev/null
@@ -0,0 +1,713 @@
+/*
+ * virhash.c: chained hash tables for domain and domain/connection deallocatiosn
+ *
+ * Reference: Your favorite introductory book on algorithms
+ *
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: Bjorn Reese <bjorn.reese@systematic.dk>
+ *         Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "virterror_internal.h"
+#include "virhash.h"
+#include "memory.h"
+#include "logging.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define MAX_HASH_LEN 8
+
+/* #define DEBUG_GROW */
+
+#define virHashIterationError(ret)                                      \
+    do {                                                                \
+        VIR_ERROR(_("Hash operation not allowed during iteration"));   \
+        return ret;                                                     \
+    } while (0)
+
+/*
+ * A single entry in the hash table
+ */
+typedef struct _virHashEntry virHashEntry;
+typedef virHashEntry *virHashEntryPtr;
+struct _virHashEntry {
+    struct _virHashEntry *next;
+    void *name;
+    void *payload;
+};
+
+/*
+ * The entire hash table
+ */
+struct _virHashTable {
+    virHashEntryPtr *table;
+    size_t size;
+    size_t nbElems;
+    /* True iff we are iterating over hash entries. */
+    bool iterating;
+    /* Pointer to the current entry during iteration. */
+    virHashEntryPtr current;
+    virHashDataFree dataFree;
+    virHashKeyCode keyCode;
+    virHashKeyEqual keyEqual;
+    virHashKeyCopy keyCopy;
+    virHashKeyFree keyFree;
+};
+
+static uint32_t virHashStrCode(const void *name)
+{
+    const char *str = name;
+    uint32_t value = 0L;
+    char ch;
+
+    if (str != NULL) {
+        value += 30 * (*str);
+        while ((ch = *str++) != 0) {
+            value =
+                value ^ ((value << 5) + (value >> 3) + (uint32_t) ch);
+        }
+    }
+    return value;
+}
+
+static bool virHashStrEqual(const void *namea, const void *nameb)
+{
+    return STREQ(namea, nameb);
+}
+
+static void *virHashStrCopy(const void *name)
+{
+    return strdup(name);
+}
+
+static void virHashStrFree(void *name)
+{
+    VIR_FREE(name);
+}
+
+
+static size_t
+virHashComputeKey(virHashTablePtr table, const void *name)
+{
+    uint32_t value = table->keyCode(name);
+    return (value % table->size);
+}
+
+/**
+ * virHashCreateFull:
+ * @size: the size of the hash table
+ * @dataFree: callback to free data
+ * @keyCode: callback to compute hash code
+ * @keyEqual: callback to compare hash keys
+ * @keyCopy: callback to copy hash keys
+ * @keyFree: callback to free keys
+ *
+ * Create a new virHashTablePtr.
+ *
+ * Returns the newly created object, or NULL if an error occurred.
+ */
+virHashTablePtr virHashCreateFull(ssize_t size,
+                                  virHashDataFree dataFree,
+                                  virHashKeyCode keyCode,
+                                  virHashKeyEqual keyEqual,
+                                  virHashKeyCopy keyCopy,
+                                  virHashKeyFree keyFree)
+{
+    virHashTablePtr table = NULL;
+
+    if (size <= 0)
+        size = 256;
+
+    if (VIR_ALLOC(table) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    table->size = size;
+    table->nbElems = 0;
+    table->dataFree = dataFree;
+    table->keyCode = keyCode;
+    table->keyEqual = keyEqual;
+    table->keyCopy = keyCopy;
+    table->keyFree = keyFree;
+
+    if (VIR_ALLOC_N(table->table, size) < 0) {
+        virReportOOMError();
+        VIR_FREE(table);
+        return NULL;
+    }
+
+    return table;
+}
+
+
+/**
+ * virHashCreate:
+ * @size: the size of the hash table
+ * @dataFree: callback to free data
+ *
+ * Create a new virHashTablePtr.
+ *
+ * Returns the newly created object, or NULL if an error occurred.
+ */
+virHashTablePtr virHashCreate(ssize_t size, virHashDataFree dataFree)
+{
+    return virHashCreateFull(size,
+                             dataFree,
+                             virHashStrCode,
+                             virHashStrEqual,
+                             virHashStrCopy,
+                             virHashStrFree);
+}
+
+/**
+ * virHashGrow:
+ * @table: the hash table
+ * @size: the new size of the hash table
+ *
+ * resize the hash table
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+static int
+virHashGrow(virHashTablePtr table, size_t size)
+{
+    size_t oldsize, i;
+    virHashEntryPtr *oldtable;
+
+#ifdef DEBUG_GROW
+    size_t nbElem = 0;
+#endif
+
+    if (table == NULL)
+        return (-1);
+    if (size < 8)
+        return (-1);
+    if (size > 8 * 2048)
+        return (-1);
+
+    oldsize = table->size;
+    oldtable = table->table;
+    if (oldtable == NULL)
+        return (-1);
+
+    if (VIR_ALLOC_N(table->table, size) < 0) {
+        virReportOOMError();
+        table->table = oldtable;
+        return (-1);
+    }
+    table->size = size;
+
+    for (i = 0; i < oldsize; i++) {
+        virHashEntryPtr iter = oldtable[i];
+        while (iter) {
+            virHashEntryPtr next = iter->next;
+            size_t key = virHashComputeKey(table, iter->name);
+
+            iter->next = table->table[key];
+            table->table[key] = iter;
+
+#ifdef DEBUG_GROW
+            nbElem++;
+#endif
+            iter = next;
+        }
+    }
+
+    VIR_FREE(oldtable);
+
+#ifdef DEBUG_GROW
+    VIR_DEBUG("virHashGrow : from %d to %d, %ld elems\n", oldsize,
+              size, nbElem);
+#endif
+
+    return (0);
+}
+
+/**
+ * virHashFree:
+ * @table: the hash table
+ *
+ * Free the hash @table and its contents. The userdata is
+ * deallocated with function provided at creation time.
+ */
+void
+virHashFree(virHashTablePtr table)
+{
+    size_t i;
+
+    if (table == NULL)
+        return;
+
+    for (i = 0; i < table->size; i++) {
+        virHashEntryPtr iter = table->table[i];
+        while (iter) {
+            virHashEntryPtr next = iter->next;
+
+            if (table->dataFree)
+                table->dataFree(iter->payload, iter->name);
+            if (table->keyFree)
+                table->keyFree(iter->name);
+            VIR_FREE(iter);
+            iter = next;
+        }
+    }
+
+    VIR_FREE(table->table);
+    VIR_FREE(table);
+}
+
+static int
+virHashAddOrUpdateEntry(virHashTablePtr table, const void *name,
+                        void *userdata,
+                        bool is_update)
+{
+    size_t key, len = 0;
+    virHashEntryPtr entry;
+    char *new_name;
+
+    if ((table == NULL) || (name == NULL))
+        return (-1);
+
+    if (table->iterating)
+        virHashIterationError(-1);
+
+    key = virHashComputeKey(table, name);
+
+    /* Check for duplicate entry */
+    for (entry = table->table[key]; entry; entry = entry->next) {
+        if (table->keyEqual(entry->name, name)) {
+            if (is_update) {
+                if (table->dataFree)
+                    table->dataFree(entry->payload, entry->name);
+                entry->payload = userdata;
+                return 0;
+            } else {
+                return -1;
+            }
+        }
+        len++;
+    }
+
+    if (VIR_ALLOC(entry) < 0 || !(new_name = table->keyCopy(name))) {
+        virReportOOMError();
+        VIR_FREE(entry);
+        return -1;
+    }
+
+    entry->name = new_name;
+    entry->payload = userdata;
+    entry->next = table->table[key];
+    table->table[key] = entry;
+
+    table->nbElems++;
+
+    if (len > MAX_HASH_LEN)
+        virHashGrow(table, MAX_HASH_LEN * table->size);
+
+    return 0;
+}
+
+/**
+ * virHashAddEntry:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @userdata: a pointer to the userdata
+ *
+ * Add the @userdata to the hash @table. This can later be retrieved
+ * by using @name. Duplicate entries generate errors.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+virHashAddEntry(virHashTablePtr table, const void *name, void *userdata)
+{
+    return virHashAddOrUpdateEntry(table, name, userdata, false);
+}
+
+/**
+ * virHashUpdateEntry:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @userdata: a pointer to the userdata
+ *
+ * Add the @userdata to the hash @table. This can later be retrieved
+ * by using @name. Existing entry for this tuple
+ * will be removed and freed with @f if found.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+virHashUpdateEntry(virHashTablePtr table, const void *name,
+                   void *userdata)
+{
+    return virHashAddOrUpdateEntry(table, name, userdata, true);
+}
+
+/**
+ * virHashLookup:
+ * @table: the hash table
+ * @name: the name of the userdata
+ *
+ * Find the userdata specified by @name
+ *
+ * Returns the a pointer to the userdata
+ */
+void *
+virHashLookup(virHashTablePtr table, const void *name)
+{
+    size_t key;
+    virHashEntryPtr entry;
+
+    if (!table || !name)
+        return NULL;
+
+    key = virHashComputeKey(table, name);
+    for (entry = table->table[key]; entry; entry = entry->next) {
+        if (table->keyEqual(entry->name, name))
+            return entry->payload;
+    }
+    return NULL;
+}
+
+
+/**
+ * virHashSteal:
+ * @table: the hash table
+ * @name: the name of the userdata
+ *
+ * Find the userdata specified by @name
+ * and remove it from the hash without freeing it.
+ *
+ * Returns the a pointer to the userdata
+ */
+void *virHashSteal(virHashTablePtr table, const void *name)
+{
+    void *data = virHashLookup(table, name);
+    if (data) {
+        virHashDataFree dataFree = table->dataFree;
+        table->dataFree = NULL;
+        virHashRemoveEntry(table, name);
+        table->dataFree = dataFree;
+    }
+    return data;
+}
+
+
+/**
+ * virHashSize:
+ * @table: the hash table
+ *
+ * Query the number of elements installed in the hash @table.
+ *
+ * Returns the number of elements in the hash table or
+ * -1 in case of error
+ */
+ssize_t
+virHashSize(virHashTablePtr table)
+{
+    if (table == NULL)
+        return (-1);
+    return (table->nbElems);
+}
+
+/**
+ * virHashTableSize:
+ * @table: the hash table
+ *
+ * Query the size of the hash @table, i.e., number of buckets in the table.
+ *
+ * Returns the number of keys in the hash table or
+ * -1 in case of error
+ */
+ssize_t
+virHashTableSize(virHashTablePtr table)
+{
+    if (table == NULL)
+        return -1;
+    return table->size;
+}
+
+
+/**
+ * virHashRemoveEntry:
+ * @table: the hash table
+ * @name: the name of the userdata
+ *
+ * Find the userdata specified by the @name and remove
+ * it from the hash @table. Existing userdata for this tuple will be removed
+ * and freed with @f.
+ *
+ * Returns 0 if the removal succeeded and -1 in case of error or not found.
+ */
+int
+virHashRemoveEntry(virHashTablePtr table, const void *name)
+{
+    virHashEntryPtr entry;
+    virHashEntryPtr *nextptr;
+
+    if (table == NULL || name == NULL)
+        return (-1);
+
+    nextptr = table->table + virHashComputeKey(table, name);
+    for (entry = *nextptr; entry; entry = entry->next) {
+        if (table->keyEqual(entry->name, name)) {
+            if (table->iterating && table->current != entry)
+                virHashIterationError(-1);
+
+            if (table->dataFree)
+                table->dataFree(entry->payload, entry->name);
+            if (table->keyFree)
+                table->keyFree(entry->name);
+            *nextptr = entry->next;
+            VIR_FREE(entry);
+            table->nbElems--;
+            return 0;
+        }
+        nextptr = &entry->next;
+    }
+
+    return -1;
+}
+
+
+/**
+ * virHashForEach
+ * @table: the hash table to process
+ * @iter: callback to process each element
+ * @data: opaque data to pass to the iterator
+ *
+ * Iterates over every element in the hash table, invoking the
+ * 'iter' callback. The callback is allowed to remove the current element
+ * using virHashRemoveEntry but calling other virHash* functions is prohibited.
+ *
+ * Returns number of items iterated over upon completion, -1 on failure
+ */
+ssize_t
+virHashForEach(virHashTablePtr table, virHashIterator iter, void *data)
+{
+    size_t i, count = 0;
+
+    if (table == NULL || iter == NULL)
+        return (-1);
+
+    if (table->iterating)
+        virHashIterationError(-1);
+
+    table->iterating = true;
+    table->current = NULL;
+    for (i = 0 ; i < table->size ; i++) {
+        virHashEntryPtr entry = table->table[i];
+        while (entry) {
+            virHashEntryPtr next = entry->next;
+
+            table->current = entry;
+            iter(entry->payload, entry->name, data);
+            table->current = NULL;
+
+            count++;
+            entry = next;
+        }
+    }
+    table->iterating = false;
+
+    return (count);
+}
+
+/**
+ * virHashRemoveSet
+ * @table: the hash table to process
+ * @iter: callback to identify elements for removal
+ * @data: opaque data to pass to the iterator
+ *
+ * Iterates over all elements in the hash table, invoking the 'iter'
+ * callback. If the callback returns a non-zero value, the element
+ * will be removed from the hash table & its payload passed to the
+ * data freer callback registered at creation.
+ *
+ * Returns number of items removed on success, -1 on failure
+ */
+ssize_t
+virHashRemoveSet(virHashTablePtr table,
+                 virHashSearcher iter,
+                 const void *data)
+{
+    size_t i, count = 0;
+
+    if (table == NULL || iter == NULL)
+        return (-1);
+
+    if (table->iterating)
+        virHashIterationError(-1);
+
+    table->iterating = true;
+    table->current = NULL;
+    for (i = 0 ; i < table->size ; i++) {
+        virHashEntryPtr *nextptr = table->table + i;
+
+        while (*nextptr) {
+            virHashEntryPtr entry = *nextptr;
+            if (!iter(entry->payload, entry->name, data)) {
+                nextptr = &entry->next;
+            } else {
+                count++;
+                if (table->dataFree)
+                    table->dataFree(entry->payload, entry->name);
+                if (table->keyFree)
+                    table->keyFree(entry->name);
+                *nextptr = entry->next;
+                VIR_FREE(entry);
+                table->nbElems--;
+            }
+        }
+    }
+    table->iterating = false;
+
+    return count;
+}
+
+/**
+ * virHashSearch:
+ * @table: the hash table to search
+ * @iter: an iterator to identify the desired element
+ * @data: extra opaque information passed to the iter
+ *
+ * Iterates over the hash table calling the 'iter' callback
+ * for each element. The first element for which the iter
+ * returns non-zero will be returned by this function.
+ * The elements are processed in a undefined order
+ */
+void *virHashSearch(virHashTablePtr table,
+                    virHashSearcher iter,
+                    const void *data)
+{
+    size_t i;
+
+    if (table == NULL || iter == NULL)
+        return (NULL);
+
+    if (table->iterating)
+        virHashIterationError(NULL);
+
+    table->iterating = true;
+    table->current = NULL;
+    for (i = 0 ; i < table->size ; i++) {
+        virHashEntryPtr entry;
+        for (entry = table->table[i]; entry; entry = entry->next) {
+            if (iter(entry->payload, entry->name, data)) {
+                table->iterating = false;
+                return entry->payload;
+            }
+        }
+    }
+    table->iterating = false;
+
+    return NULL;
+}
+
+struct getKeysIter
+{
+    virHashKeyValuePair *sortArray;
+    size_t arrayIdx;
+};
+
+static void virHashGetKeysIterator(void *payload,
+                                   const void *key, void *data)
+{
+    struct getKeysIter *iter = data;
+
+    iter->sortArray[iter->arrayIdx].key = key;
+    iter->sortArray[iter->arrayIdx].value = payload;
+
+    iter->arrayIdx++;
+}
+
+typedef int (*qsort_comp)(const void *, const void *);
+
+virHashKeyValuePairPtr virHashGetItems(virHashTablePtr table,
+                                       virHashKeyComparator compar)
+{
+    ssize_t numElems = virHashSize(table);
+    struct getKeysIter iter = {
+        .arrayIdx = 0,
+        .sortArray = NULL,
+    };
+
+    if (numElems < 0)
+        return NULL;
+
+    if (VIR_ALLOC_N(iter.sortArray, numElems + 1)) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    virHashForEach(table, virHashGetKeysIterator, &iter);
+
+    if (compar)
+        qsort(&iter.sortArray[0], numElems, sizeof(iter.sortArray[0]),
+              (qsort_comp)compar);
+
+    return iter.sortArray;
+}
+
+struct virHashEqualData
+{
+    bool equal;
+    const virHashTablePtr table2;
+    virHashValueComparator compar;
+};
+
+static int virHashEqualSearcher(const void *payload, const void *name,
+                                const void *data)
+{
+    struct virHashEqualData *vhed = (void *)data;
+    const void *value;
+
+    value = virHashLookup(vhed->table2, name);
+    if (!value ||
+        vhed->compar(value, payload) != 0) {
+        /* key is missing in 2nd table or values are different */
+        vhed->equal = false;
+        /* stop 'iteration' */
+        return 1;
+    }
+    return 0;
+}
+
+bool virHashEqual(const virHashTablePtr table1,
+                  const virHashTablePtr table2,
+                  virHashValueComparator compar)
+{
+    struct virHashEqualData data = {
+        .equal = true,
+        .table2 = table2,
+        .compar = compar,
+    };
+
+    if (table1 == table2)
+        return true;
+
+    if (!table1 || !table2 ||
+        virHashSize(table1) != virHashSize(table2))
+        return false;
+
+    virHashSearch(table1, virHashEqualSearcher, &data);
+
+    return data.equal;
+}
diff --git a/src/util/virhash.h b/src/util/virhash.h
new file mode 100644 (file)
index 0000000..8462cb3
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Summary: Chained hash tables and domain/connections handling
+ * Description: This module implements the hash table and allocation and
+ *              deallocation of domains and connections
+ *
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
+ *
+ * Author: Bjorn Reese <bjorn.reese@systematic.dk>
+ *         Daniel Veillard <veillard@redhat.com>
+ */
+
+#ifndef __VIR_HASH_H__
+# define __VIR_HASH_H__
+
+/*
+ * The hash table.
+ */
+typedef struct _virHashTable virHashTable;
+typedef virHashTable *virHashTablePtr;
+
+/*
+ * function types:
+ */
+
+/**
+ * virHashDataFree:
+ * @payload:  the data in the hash
+ * @name:  the name associated
+ *
+ * Callback to free data from a hash.
+ */
+typedef void (*virHashDataFree) (void *payload, const void *name);
+/**
+ * virHashIterator:
+ * @payload: the data in the hash
+ * @name: the hash key
+ * @data: user supplied data blob
+ *
+ * Callback to process a hash entry during iteration
+ */
+typedef void (*virHashIterator) (void *payload, const void *name, void *data);
+/**
+ * virHashSearcher:
+ * @payload: the data in the hash
+ * @name: the hash key
+ * @data: user supplied data blob
+ *
+ * Callback to identify hash entry desired
+ * Returns 1 if the hash entry is desired, 0 to move
+ * to next entry
+ */
+typedef int (*virHashSearcher) (const void *payload, const void *name,
+                                const void *data);
+
+/**
+ * virHashKeyCode:
+ * @name: the hash key
+ *
+ * Compute the hash code corresponding to the key @name
+ *
+ * Returns the hash code
+ */
+typedef uint32_t (*virHashKeyCode)(const void *name);
+/**
+ * virHashKeyEqual:
+ * @namea: the first hash key
+ * @nameb: the second hash key
+ *
+ * Compare two hash keys for equality
+ *
+ * Returns true if the keys are equal, false otherwise
+ */
+typedef bool (*virHashKeyEqual)(const void *namea, const void *nameb);
+/**
+ * virHashKeyCopy:
+ * @name: the hash key
+ *
+ * Create a copy of the hash key, duplicating
+ * memory allocation where applicable
+ *
+ * Returns a newly allocated copy of @name
+ */
+typedef void *(*virHashKeyCopy)(const void *name);
+/**
+ * virHashKeyFree:
+ * @name: the hash key
+ *
+ * Free any memory associated with the hash
+ * key @name
+ */
+typedef void (*virHashKeyFree)(void *name);
+
+/*
+ * Constructor and destructor.
+ */
+virHashTablePtr virHashCreate(ssize_t size,
+                              virHashDataFree dataFree);
+virHashTablePtr virHashCreateFull(ssize_t size,
+                                  virHashDataFree dataFree,
+                                  virHashKeyCode keyCode,
+                                  virHashKeyEqual keyEqual,
+                                  virHashKeyCopy keyCopy,
+                                  virHashKeyFree keyFree);
+void virHashFree(virHashTablePtr table);
+ssize_t virHashSize(virHashTablePtr table);
+ssize_t virHashTableSize(virHashTablePtr table);
+
+/*
+ * Add a new entry to the hash table.
+ */
+int virHashAddEntry(virHashTablePtr table,
+                    const void *name, void *userdata);
+int virHashUpdateEntry(virHashTablePtr table,
+                       const void *name,
+                       void *userdata);
+
+/*
+ * Remove an entry from the hash table.
+ */
+int virHashRemoveEntry(virHashTablePtr table,
+                       const void *name);
+
+/*
+ * Retrieve the userdata.
+ */
+void *virHashLookup(virHashTablePtr table, const void *name);
+
+/*
+ * Retrieve & remove the userdata.
+ */
+void *virHashSteal(virHashTablePtr table, const void *name);
+
+/*
+ * Get the hash table's key/value pairs and have them optionally sorted.
+ * The returned array contains virHashSize() elements. Additionally,
+ * an empty element has been added to the end of the array (with key == NULL)
+ * to indicate the end of the array.
+ * The key/value pairs are only valid as long as the underlying hash
+ * table is not modified, i.e., no keys are removed or inserted, and
+ * the hash table is not deleted.
+ * The caller must only free the returned array using VIR_FREE().
+ * The caller must make copies of all returned keys and values if they are
+ * to be used somewhere else.
+ */
+typedef struct _virHashKeyValuePair virHashKeyValuePair;
+typedef virHashKeyValuePair *virHashKeyValuePairPtr;
+struct _virHashKeyValuePair {
+    const void *key;
+    const void *value;
+};
+typedef int (*virHashKeyComparator)(const virHashKeyValuePairPtr,
+                                    const virHashKeyValuePairPtr);
+virHashKeyValuePairPtr virHashGetItems(virHashTablePtr table,
+                                       virHashKeyComparator compar);
+
+/*
+ * Compare two tables for equality: the lookup of a key's value in
+ * both tables must result in an equivalent value.
+ * The caller must pass in a comparator function for comparing the values
+ * of two keys.
+ */
+typedef int (*virHashValueComparator)(const void *value1, const void *value2);
+bool virHashEqual(const virHashTablePtr table1,
+                  const virHashTablePtr table2,
+                  virHashValueComparator compar);
+
+
+/*
+ * Iterators
+ */
+ssize_t virHashForEach(virHashTablePtr table, virHashIterator iter, void *data);
+ssize_t virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, const void *data);
+void *virHashSearch(virHashTablePtr table, virHashSearcher iter, const void *data);
+
+#endif                          /* ! __VIR_HASH_H__ */
index 412237830185944dad804461e832b36a9d0cf247..3cefea336a251a108edcd462693047ea414e5975 100644 (file)
@@ -20,7 +20,7 @@
 #  include "xen_inotify.h"
 # endif
 # include "domain_event.h"
-# include "hash.h"
+# include "virhash.h"
 
 # ifndef HAVE_WINSOCK2_H
 #  include <sys/un.h>
index 9c376fb9dbeb2838fcfd00c8fa091271495c9f41..a34e906c429f6c89e29701f98c608509e255f520 100644 (file)
@@ -42,7 +42,7 @@
 #include "xend_internal.h"
 #include "xen_sxpr.h"
 #include "xen_xm.h"
-#include "hash.h"
+#include "virhash.h"
 #include "buf.h"
 #include "uuid.h"
 #include "util.h"
index f3b0c09185c8d70bf502fdd7618f276ce551ee17..ed47779cbbbf333e063c0e96c482cf943b1b62b4 100644 (file)
@@ -95,7 +95,7 @@ EXTRA_DIST =          \
 check_PROGRAMS = virshtest conftest sockettest \
        nodeinfotest qparamtest virbuftest \
        commandtest commandhelper seclabeltest \
-       hashtest virnetmessagetest virnetsockettest ssh \
+       virhashtest virnetmessagetest virnetsockettest ssh \
        utiltest virnettlscontexttest shunloadtest \
        virtimetest
 
@@ -214,7 +214,7 @@ TESTS = virshtest \
        sockettest \
        commandtest \
        seclabeltest \
-       hashtest \
+       virhashtest \
        virnetmessagetest \
        virnetsockettest \
        virnettlscontexttest \
@@ -515,9 +515,9 @@ virbuftest_SOURCES = \
        virbuftest.c testutils.h testutils.c
 virbuftest_LDADD = $(LDADDS)
 
-hashtest_SOURCES = \
-       hashtest.c hashdata.h testutils.h testutils.c
-hashtest_LDADD = $(LDADDS)
+virhashtest_SOURCES = \
+       virhashtest.c virhashdata.h testutils.h testutils.c
+virhashtest_LDADD = $(LDADDS)
 
 jsontest_SOURCES = \
        jsontest.c testutils.h testutils.c
diff --git a/tests/hashdata.h b/tests/hashdata.h
deleted file mode 100644 (file)
index 332e09c..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-const char *uuids[] = {
-/* [  2] */ "a9b02f96-e430-4f7c-a7ff-a647d080447a",
-/* [  4] */ "202e32ca-f82c-4f13-9266-28dc8d002074",
-/* [  5] */ "e0233ed8-22da-4a1e-a1a2-2d0343635173",
-            "4ce4f92a-e116-4c38-81ca-acebbdcab410",
-/* [  6] */ "4121c24d-bfc3-45f9-85c6-899679b5cc60",
-            "e641740a-85dd-4414-bdbf-37dbaee39e26",
-/* [  9] */ "a0c94fa8-7d41-4100-8907-9b9209e7954a",
-/* [ 10] */ "d3c7d973-046d-4c49-90bb-7a353aaea8a2",
-            "ad15e406-8258-49ad-a47e-cbb955b34220",
-/* [ 11] */ "0979803b-6bcc-4305-917c-079dcc0f1cb4",
-/* [ 12] */ "0311fc3f-e5b1-48f5-ab9e-e577fbfc6b82",
-/* [ 14] */ "512aa755-3c48-456b-9545-3cc6f729444f",
-/* [ 16] */ "43b7e89e-c5cb-44c6-9bdb-7f070d6e5cf7",
-/* [ 17] */ "3e4fd85d-57d8-4d1d-867e-71ba3b898dc3",
-/* [ 18] */ "8433c800-1cda-4bf1-8a3d-879f657e0068",
-/* [ 20] */ "fb55ed30-a8fe-44ab-aa25-4d609c487975",
-/* [ 21] */ "b7fa38f1-f329-430d-8450-57d75175f578",
-/* [ 22] */ "bbbff7ba-73d8-42a0-ace3-dbf39906223a",
-/* [ 23] */ "1ef274ef-2c99-488f-ba25-21da0285d7fe",
-/* [ 26] */ "24e30027-16cf-4848-a4be-6dffae973757",
-/* [ 28] */ "fd056c9c-9f39-43b8-90be-aaff3909a56c",
-/* [ 29] */ "2c53a1dc-3b62-4369-a583-71cad3d1fa98",
-            "063b19c7-1c96-4cc8-ac18-bc007f073a13",
-/* [ 32] */ "f210da80-6e0a-4185-a96e-7bd32a779e72",
-/* [ 33] */ "dd557d13-0f6d-460a-8002-9392ce483e50",
-/* [ 34] */ "d16f07e4-f5be-4744-b70a-dc6e26666c44",
-/* [ 35] */ "dafe133f-d48c-4a30-b156-f073725401f5",
-/* [ 36] */ "96dfe074-7236-4898-aad2-81963c23adda",
-            "c971ea2e-9410-4b3c-9027-d678a0d9db8d",
-/* [ 38] */ "7b417156-b90a-4450-9c77-e1e94e1c980c",
-/* [ 39] */ "a7334316-6572-47d5-9330-9a3e70c30c6d",
-/* [ 40] */ "1e33c931-ef3a-497f-9374-6d9dddf04893",
-            "ebc4d160-4418-41cd-bd2f-0ef2741ffafb",
-/* [ 41] */ "6e13dd0b-67f8-447c-8445-9b8476a2e556",
-/* [ 42] */ "6123a5df-4b0b-421e-8dcb-4ecb3b33113d",
-/* [ 44] */ "75fc3921-558b-4093-82ba-e9807551de84",
-/* [ 45] */ "3308bc39-5d59-4ae8-8e45-bc1607a5d5d3",
-            "ad064af6-e55a-4de9-95b8-6a0afc77ad81",
-/* [ 46] */ "f17494ba-2353-4af0-b1ba-13680858edcc",
-            "64ab4e78-1b6e-4b88-b47f-2def46c79a86",
-            "f99b0d59-ecff-4cc6-a9d3-20159536edc8",
-/* [ 48] */ "a697613f-349b-41f8-80c5-f416ee462ca2",
-/* [ 52] */ "e9af1e6f-016d-43f3-8890-a33d924b4368",
-            "4e5c715a-4f37-4260-ae33-a86bc97f2a69",
-/* [ 54] */ "ae82cd8a-d67a-4fc7-9323-06511cbe9f4d",
-            "32d7a14c-4138-459e-aa19-5263d4a6b410",
-/* [ 56] */ "9aba27ea-37e4-485c-983c-42de92c2d2ea",
-/* [ 59] */ "45826b95-3120-417b-a5ff-5480e342f25e",
-            "834a24b7-5c77-4287-9266-82c2f2c9e9fc",
-/* [ 62] */ "d4d09671-8132-4809-badf-efbef39c9dac",
-/* [ 66] */ "b0bd3bd8-1271-4755-84e7-e89fabb929b2",
-/* [ 69] */ "86e2a115-3e5b-480e-9109-12ac4b525761",
-/* [ 70] */ "2896d83a-ede2-4a01-8047-25a0db868b27",
-/* [ 71] */ "1f290a52-51ad-4ea6-ae11-b90c50ba8ea6",
-/* [ 72] */ "511b890f-d9f5-4fb4-90d4-39e93719c4bf",
-/* [ 74] */ "51bf1c00-6c0a-4ca4-8acc-1ab9c6bc44ce",
-/* [ 75] */ "e1bfa30f-bc0b-4a24-99ae-bed7f3f21a7b",
-            "acda5fa0-58de-4e1e-aa65-2124d1e29c54",
-/* [ 76] */ "5f476c28-8f26-48e0-98de-85745fe2f304",
-/* [ 79] */ "4a1f1b60-4c53-4525-b687-f0175b6e19bc",
-/* [ 80] */ "608bcc5e-5ccc-4967-a58f-4d61665685bc",
-            "b7028f70-6d4d-4d0a-8c78-ec61fd6e38fc",
-/* [ 81] */ "03cc8179-3b0e-4c9f-a665-9ca416ee0e9b",
-/* [ 83] */ "2f32ba02-7a07-46e0-b859-a7b82a5de8e0",
-/* [ 85] */ "490b8a1b-4d7a-4d14-81c3-af6c4824632f",
-/* [ 88] */ "48e8c968-c1b7-4b3b-a24a-abb94604758b",
-/* [ 89] */ "242fd86e-d804-4b7e-9a92-b8227becdb91",
-/* [ 90] */ "13315204-76aa-4ae6-9f27-44434facea60",
-/* [ 91] */ "548544c8-1737-4efe-8661-4783e4b6ef12",
-/* [ 92] */ "3e6f26ce-ddb3-485c-86ca-b455fcfb802a",
-/* [ 93] */ "a6b1df31-2f3f-4314-87f9-fd794aad8d5a",
-            "bce3d144-820d-489b-8506-f04fdea2ee48",
-/* [ 95] */ "e400060d-4de7-4c12-9533-a9aa4296c44c",
-/* [ 96] */ "9a0a6b84-7263-46d3-a45e-ad9e7b61a109",
-            "a9734665-e800-4c99-96ec-dd0426e20b00",
-/* [ 97] */ "d3efc444-1758-4733-9cfb-50412ba7cf79",
-            "999edbf0-b194-43aa-87ed-afc2ae0fe30b",
-/* [ 98] */ "e866d6bf-2e7c-4f97-8178-1ca758020d2c",
-/* [ 99] */ "87b97bc3-62d1-465d-94a8-7ae22efd8103",
-/* [100] */ "050d33f5-e7b1-42e8-a253-292b2769069a",
-            "1b5fff42-37dc-4770-9a41-6df2fe4b7858",
-            "d6a4b1a3-6c19-46e1-90b9-2de3ef471eb3",
-/* [101] */ "51e8e981-dd6a-4e85-a6b4-ed60d38a72ac",
-/* [102] */ "7f62af6b-3954-4a7a-9b32-721d770da3d8",
-            "8016379a-9905-43cb-a6bd-98fc83296982",
-            "e003782c-fcec-449a-a0e4-cda41893e78f",
-/* [103] */ "954d5d6a-98b6-45ad-a95c-85721664b1ea",
-/* [105] */ "ccd3680a-d8ac-4f68-ac08-a7b59f31af10",
-/* [106] */ "cded8a5d-874c-4400-86a4-eb483cfe0265",
-/* [109] */ "356df5ef-c744-4696-a697-91f4634c8559",
-/* [110] */ "faee6c44-f212-4c8a-8e8c-bea91fb26532",
-/* [113] */ "84377685-45f9-4c89-ad4f-5776f6ffcff4",
-/* [116] */ "b69c50ec-2bd3-4162-bca3-eec4398f2d12",
-            "fb5e4a60-efdb-4884-bb9e-ac911b1b5100",
-            "d59a5c99-5ce5-46bf-8a80-cdf916f71576",
-/* [117] */ "c09322ef-0b70-4ea0-922b-95832bb5469c",
-/* [118] */ "47e88680-4f46-4096-9f77-1bd4e271acd5",
-/* [119] */ "570d5f36-31e6-412b-84dd-e5aabb73dd5b",
-            "56cf0509-741a-4a5c-a82c-51060f009b9a",
-/* [122] */ "c257b495-e53c-4be5-8b05-491057531120",
-            "654139f2-cef5-48df-a6b2-6ca6e9abb1de",
-/* [123] */ "8be1d21c-cd35-4c7c-8fee-4b5046c7a62b",
-            "830f0d57-9f21-40e8-bb86-cbf41de23fd6",
-            "57044958-1b8a-4c02-ab75-2298c6e44263",
-            "d526cd6c-4a99-4d5f-abfb-fc9419edd9d0",
-/* [124] */ "36492c15-ce5a-4f9b-b75a-97937981f9b4",
-            "66a984a9-cd04-4683-b241-2b296da662bc",
-            "0b3404eb-022b-4ef1-a78d-a2b12230b258",
-/* [125] */ "f8d7efcf-1138-422b-a844-feffa7478be8",
-/* [130] */ "4f8ca175-6efa-476e-ab58-11efe9211415",
-/* [131] */ "87fcc2e2-0b65-4eaa-8bea-74de85abf3fe",
-            "ea0d108f-8a39-414a-88c6-fcabce029af7",
-            "b1f17225-efb3-4b8a-aae3-a2ca53eeb99e",
-            "45dcb41d-0628-485f-9f14-3296410555a5",
-/* [133] */ "a2b16b3f-93df-4d5a-a226-5f340bf2b0a3",
-/* [140] */ "373025da-238a-467f-8164-b5675cfe6422",
-/* [141] */ "8969aa50-6d2b-4659-ade1-b4a2169e0ed1",
-/* [142] */ "ba092226-be95-4ec2-8c35-215db61448e6",
-/* [143] */ "4213fb5a-6d28-4296-85a6-bb149a0468b7",
-/* [144] */ "05bd2d12-1062-46c3-9ac2-362617175b04",
-/* [145] */ "97cff77b-9f8d-40e9-8c41-601dc280a413",
-            "4d05b973-b30b-4416-bdd8-e3773b30cb6e",
-            "95382996-dfce-483d-8ff8-1d05c6c65bb5",
-/* [146] */ "04213584-d98a-4e82-a884-1238a7568c48",
-/* [148] */ "68bad966-22ec-4e87-9c6c-c1dd000959c4",
-            "f1b44f04-2028-4855-ad6c-9538ef6e44a2",
-/* [149] */ "8748c9ae-624d-4fb1-a3d3-5073716c882c",
-/* [150] */ "e0eb4d5b-d251-41c9-9215-0e2830413fe4",
-            "426795e5-a6e2-4b42-a81d-41cddb79f9b6",
-            "a16297c6-e9f4-49c4-b244-4e2ae2803ce3",
-/* [151] */ "ea07d3ec-4f35-41db-afd2-4bc2b3273e0f",
-            "f013f77d-8bd8-4a8e-82e9-82512071ac0f",
-/* [152] */ "754038bd-c382-4605-b53d-600f165aac10",
-/* [156] */ "06575e79-74dd-46c1-a752-de53b8bf8987",
-/* [158] */ "00a14b42-e60e-4214-9de1-9ff187a67e6e",
-/* [159] */ "93d02eb8-325b-42cc-b1b6-435eeb6e0449",
-/* [163] */ "f9e5528e-52ec-4164-8b4d-0b25a4715ce6",
-/* [166] */ "f1a3af6e-b8c3-4836-95da-3c4b740dab80",
-/* [169] */ "81af0cbf-b3c5-49b9-ae04-bf93e493943f",
-/* [170] */ "ab7bd5e5-68cc-4a04-9773-e668bf1d5e55",
-/* [172] */ "55ff86fa-2fc0-46c1-a222-3b9bfef434be",
-/* [174] */ "ed7dda66-4ec3-438b-8444-5f998528c7c1",
-/* [175] */ "3929d8b1-f6f7-44f6-8366-8ccc6d6c8dae",
-/* [178] */ "455a7a4c-1602-453b-9729-03c040ba1ed7",
-            "6e68d708-26c3-45db-ae71-52c0ef0e3879",
-/* [179] */ "c6be4f40-aad8-4be5-bc50-e8bb9217e988",
-/* [181] */ "550e511b-3105-485f-8856-593761339f08",
-/* [182] */ "dea7c93f-a9e5-4622-9da5-0959f2561e33",
-/* [183] */ "705c2f9b-08d2-4502-b53e-0b01db35acd3",
-            "819c7473-898f-439b-935d-fe4a96f64150",
-/* [185] */ "8c1fc53f-7867-4399-8c6c-a6e4b128a9f8",
-/* [187] */ "a1bf2aed-639d-4e1b-9aa3-6b7be8a49c59",
-/* [188] */ "4e92f93d-4667-414e-a7bf-b42d33bc409e",
-            "4013ec51-05a8-479b-9d5a-8f1149039e34",
-            "796ec0f2-b9f9-4a9e-ac8e-1ce726eef88c",
-/* [189] */ "7328ee55-9cd2-4f37-ac3c-630287a65f7c",
-            "225d01da-9bbd-4cb1-b892-fd8a4a604c76",
-/* [190] */ "97fd798d-94a7-4089-aaf6-50919d105c4c",
-            "cb792c37-7cd2-4649-ab92-180fef7b9911",
-/* [191] */ "7edcabaa-70f7-447d-9bb8-95537cd48b0d",
-/* [192] */ "df3348bf-5eda-480a-9a3b-c26eb9df3d80",
-/* [193] */ "854b565d-0ea7-40b3-ba41-054e2d4e1869",
-            "079d9a35-331e-489d-b153-493ca28fe95c",
-/* [194] */ "589778f4-cca0-4969-a27c-ccd29b2d35f0",
-/* [195] */ "e0505dd6-3f2c-4ac1-8d93-41fb021af558",
-/* [196] */ "ab8be1c6-18f4-4ecb-a115-8d839dba1bd0",
-/* [197] */ "7dab18d4-4fc6-451f-9558-0b719bb2ecec",
-/* [200] */ "f9c10e12-877a-4750-a697-d39691443c54",
-            "a5be8e6c-7d4c-48aa-b457-22168cf56ddf",
-            "72160964-cd58-4a01-bdbf-7f5151975ffe",
-/* [202] */ "84d91759-4a70-4bc3-808d-24a8fc4c0816",
-            "fad2acc3-ebda-490c-9698-06cd6690b924",
-            "17191452-f402-47a0-b3e9-ae3e5688a534",
-/* [203] */ "f328382f-2706-4a0b-aac8-b9ffed687997",
-            "5cbd8451-cc3e-4dc4-bd3b-0033d8c869ff",
-/* [204] */ "704436e1-e9b3-4269-813a-a1c6a425cb4d",
-/* [206] */ "80748ed5-3d42-4d95-ba21-30b071ac17ad",
-            "bb3f3be2-2ab7-48fb-b71b-45041b732887",
-/* [207] */ "ae45b5a6-ea00-4e0c-948a-ebf3c84dfd01",
-            "10363e09-d2e0-40a5-afce-0fdf852222d7",
-/* [209] */ "777174f9-d80c-46f9-9fe8-5d59c93abd64",
-            "5c75455b-4317-4285-818f-3ffc165b05f9",
-            "dc708225-bcb0-447b-99ca-4291d717a600",
-/* [210] */ "1dc43c46-ff0a-4527-9b01-34dde0abf4b8",
-            "559813cd-ba6f-446f-af56-224170d39cce",
-            "3c1c7283-78e1-4082-a191-d2eeed51d7fd",
-/* [212] */ "1cda8175-d221-452a-8aad-e96d2da674ed",
-/* [213] */ "751bcb18-2235-4bb9-b320-36551c3e8810",
-/* [214] */ "fe3a9c52-6058-4203-9fa0-6c657852026c",
-/* [215] */ "29fb462f-6975-41b0-b6fa-c2556a658a68",
-/* [216] */ "c0f80985-d1cc-4ea6-839e-02e52b33623f",
-            "404e1b0c-5e34-4419-818e-6707b8f90248",
-            "34d224fc-9803-4da5-a08e-4b49e5d24592",
-/* [217] */ "2977ad89-0ec8-4f60-8228-1b82a65a7c7c",
-            "b954246e-29cf-4792-ae60-b841e5710111",
-/* [218] */ "b54ede2a-70af-4a63-9d17-410ba5ee6c0c",
-/* [219] */ "b2baf136-de10-48ca-ae6b-0f802acbf09c",
-/* [220] */ "e55df82c-2128-43bf-a681-e626a2c4d1c3",
-            "67338b47-c2f1-4f73-956c-4b54e427e6e4",
-/* [221] */ "450cca9c-38f6-4eb8-b537-190fc3fff99d",
-/* [222] */ "6b4ccebf-e741-4a54-97a4-20ac92c18107",
-/* [225] */ "3a7ea080-fb0b-4ef3-b005-5b9e2aa931a2",
-            "78d7fc2b-883d-48b1-9896-bf660ca0fe5a",
-            "f12574f2-452c-4363-90a1-eeaa353936d6",
-/* [226] */ "1ae1d3f8-974e-47a7-8f26-a105766fc24d",
-/* [227] */ "9f2506cf-4aea-4c47-8897-f6b83ba814fb",
-/* [228] */ "125dba5c-b19a-4218-928f-553788c02637",
-/* [229] */ "5c7eb444-84c1-4a3b-8385-ccf4c6632dc3",
-/* [232] */ "5c2dfc36-cf78-4718-acf4-c2823c95054a",
-            "b6442198-b321-4f0d-9fdb-c12115831875",
-            "0cf5fc99-c43f-4a36-837a-b3bad7902cb8",
-/* [233] */ "b3631261-7322-405d-bb14-245bf29e729c",
-            "2cc98dd0-5ae1-4a01-b2fd-7e1074bc9110",
-            "3c6a9e1c-0425-4af3-aef8-d4e336fe4397",
-/* [235] */ "2f52aab9-c383-4ac6-b1e1-c317198a3105",
-            "b06bf0b1-0b05-42ed-b79e-4770671c90e2",
-/* [237] */ "3ab39f7f-4613-4da6-a216-c2d6acc441bb",
-            "ae20cf3c-38b8-483c-baea-6fb0994dc30c",
-            "cd204d90-2414-4b9e-9d4f-fed09c9a816f",
-/* [240] */ "ed2cc723-db4b-43aa-ab02-0e3161087499",
-/* [241] */ "9cc96bd6-0ca0-466a-b897-e11eb7540b07",
-/* [244] */ "8d45a51f-a945-4de1-b89c-2b39d1a5b90e",
-/* [245] */ "6cd02e53-40ac-4269-91c9-4e1088af91f1",
-/* [246] */ "8ada85bc-9bdf-4507-8334-849635ea0a01",
-            "8a7d5deb-615f-4cd3-8977-b5fab8ec4d05",
-/* [247] */ "dc2173b0-48fe-4555-b190-8052be1120eb",
-            "040e434d-68d8-41a9-b3a1-1bee239914c1",
-            "d1a564b2-c7f3-4b76-8712-3b8f5aae6ded",
-            "0e614f33-c1da-4cfe-b6d5-65ecd2d066f2",
-/* [250] */ "334fdaba-f373-42ff-8546-219c1463a7c5",
-            "d4ff408e-8d43-46ff-94a4-bcfa6c994776",
-/* [253] */ "d1abd887-d5de-46b0-88d6-f71f31a61305",
-/* [254] */ "1d76af65-64d6-4211-b1b5-f5b799595e4d",
-/* [255] */ "b3ad4257-29b0-4c44-b7a7-95f1d102769c",
-};
-
-const char *uuids_subset[] = {
-    "64ab4e78-1b6e-4b88-b47f-2def46c79a86",
-    "acda5fa0-58de-4e1e-aa65-2124d1e29c54",
-    "830f0d57-9f21-40e8-bb86-cbf41de23fd6",
-    "57044958-1b8a-4c02-ab75-2298c6e44263",
-    "ae20cf3c-38b8-483c-baea-6fb0994dc30c",
-    "040e434d-68d8-41a9-b3a1-1bee239914c1",
-    "d1a564b2-c7f3-4b76-8712-3b8f5aae6ded",
-    "8ada85bc-9bdf-4507-8334-849635ea0a01",
-    "97cff77b-9f8d-40e9-8c41-601dc280a413",
-    "4d05b973-b30b-4416-bdd8-e3773b30cb6e",
-    "95382996-dfce-483d-8ff8-1d05c6c65bb5",
-};
-
-const char *uuids_new[] = {
-    "a103cc42-d0e5-40fb-8f7f-3c1bee93e327",
-    "01e13dc5-e65b-4988-a0cc-0d2f1f1e10fe",
-    "71f3678a-a8c6-4176-a26e-c34779067135",
-    "4f054508-22d5-49e1-9962-7508225c8b16",
-    "e572116b-5b7b-45fd-bbe9-296029ce16b5",
-    "695c8cfe-9830-4d9a-be67-50a124cefb76",
-    "ea244996-645b-4a19-ad4a-48f3022b8e94",
-    "0fd98758-9cc4-4779-b403-95ae3500f138",
-    "b86772b4-0728-46ae-99e8-027799697838",
-    "1c0cd559-81cd-4c27-8e24-6aef6f5af7f1",
-    "2a37fe4a-8825-4fd6-9284-e1606967548a",
-    "5920cc9d-62a3-4772-9e73-eb97f0bc483c",
-    "53c215dd-bdba-4fdc-887a-86ab6f860df4",
-};
diff --git a/tests/hashtest.c b/tests/hashtest.c
deleted file mode 100644 (file)
index 8df6906..0000000
+++ /dev/null
@@ -1,698 +0,0 @@
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "internal.h"
-#include "hash.h"
-#include "hashdata.h"
-#include "testutils.h"
-#include "memory.h"
-
-
-#define testError(...)                                          \
-    do {                                                        \
-        fprintf(stderr, __VA_ARGS__);                           \
-        /* Pad to line up with test name ... in virTestRun */   \
-        fprintf(stderr, "%74s", "... ");                        \
-    } while (0)
-
-
-static virHashTablePtr
-testHashInit(int size)
-{
-    virHashTablePtr hash;
-    ssize_t i;
-
-    if (!(hash = virHashCreate(size, NULL)))
-        return NULL;
-
-    /* entires are added in reverse order so that they will be linked in
-     * collision list in the same order as in the uuids array
-     */
-    for (i = ARRAY_CARDINALITY(uuids) - 1; i >= 0; i--) {
-        ssize_t oldsize = virHashTableSize(hash);
-        if (virHashAddEntry(hash, uuids[i], (void *) uuids[i]) < 0) {
-            virHashFree(hash);
-            return NULL;
-        }
-
-        if (virHashTableSize(hash) != oldsize && virTestGetDebug()) {
-            fprintf(stderr, "\nhash grown from %zd to %zd",
-                    oldsize, virHashTableSize(hash));
-        }
-    }
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids); i++) {
-        if (!virHashLookup(hash, uuids[i])) {
-            if (virTestGetVerbose()) {
-                fprintf(stderr, "\nentry \"%s\" could not be found\n",
-                        uuids[i]);
-            }
-            virHashFree(hash);
-            return NULL;
-        }
-    }
-
-    if (size && size != virHashTableSize(hash) && virTestGetDebug())
-        fprintf(stderr, "\n");
-
-    return hash;
-}
-
-static void
-testHashCheckForEachCount(void *payload ATTRIBUTE_UNUSED,
-                          const void *name ATTRIBUTE_UNUSED,
-                          void *data ATTRIBUTE_UNUSED)
-{
-}
-
-static int
-testHashCheckCount(virHashTablePtr hash, size_t count)
-{
-    ssize_t iter_count = 0;
-
-    if (virHashSize(hash) != count) {
-        testError("\nhash contains %zd instead of %zu elements\n",
-                  virHashSize(hash), count);
-        return -1;
-    }
-
-    iter_count = virHashForEach(hash, testHashCheckForEachCount, NULL);
-    if (count != iter_count) {
-        testError("\nhash claims to have %zu elements but iteration finds %zd\n",
-                  count, iter_count);
-        return -1;
-    }
-
-    return 0;
-}
-
-
-struct testInfo {
-    void *data;
-    size_t count;
-};
-
-
-static int
-testHashGrow(const void *data)
-{
-    const struct testInfo *info = data;
-    virHashTablePtr hash;
-    int ret = -1;
-
-    if (!(hash = testHashInit(info->count)))
-        return -1;
-
-    if (testHashCheckCount(hash, ARRAY_CARDINALITY(uuids)) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-static int
-testHashUpdate(const void *data ATTRIBUTE_UNUSED)
-{
-    int count = ARRAY_CARDINALITY(uuids) + ARRAY_CARDINALITY(uuids_new);
-    virHashTablePtr hash;
-    int i;
-    int ret = -1;
-
-    if (!(hash = testHashInit(0)))
-        return -1;
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
-        if (virHashUpdateEntry(hash, uuids_subset[i], (void *) 1) < 0) {
-            if (virTestGetVerbose()) {
-                fprintf(stderr, "\nentry \"%s\" could not be updated\n",
-                        uuids_subset[i]);
-            }
-            goto cleanup;
-        }
-    }
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids_new); i++) {
-        if (virHashUpdateEntry(hash, uuids_new[i], (void *) 1) < 0) {
-            if (virTestGetVerbose()) {
-                fprintf(stderr, "\nnew entry \"%s\" could not be updated\n",
-                        uuids_new[i]);
-            }
-            goto cleanup;
-        }
-    }
-
-    if (testHashCheckCount(hash, count) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-static int
-testHashRemove(const void *data ATTRIBUTE_UNUSED)
-{
-    int count = ARRAY_CARDINALITY(uuids) - ARRAY_CARDINALITY(uuids_subset);
-    virHashTablePtr hash;
-    int i;
-    int ret = -1;
-
-    if (!(hash = testHashInit(0)))
-        return -1;
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
-        if (virHashRemoveEntry(hash, uuids_subset[i]) < 0) {
-            if (virTestGetVerbose()) {
-                fprintf(stderr, "\nentry \"%s\" could not be removed\n",
-                        uuids_subset[i]);
-            }
-            goto cleanup;
-        }
-    }
-
-    if (testHashCheckCount(hash, count) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-const int testHashCountRemoveForEachSome =
-    ARRAY_CARDINALITY(uuids) - ARRAY_CARDINALITY(uuids_subset);
-
-static void
-testHashRemoveForEachSome(void *payload ATTRIBUTE_UNUSED,
-                          const void *name,
-                          void *data)
-{
-    virHashTablePtr hash = data;
-    int i;
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
-        if (STREQ(uuids_subset[i], name)) {
-            if (virHashRemoveEntry(hash, name) < 0 && virTestGetVerbose()) {
-                fprintf(stderr, "\nentry \"%s\" could not be removed",
-                        uuids_subset[i]);
-            }
-            break;
-        }
-    }
-}
-
-
-const int testHashCountRemoveForEachAll = 0;
-
-static void
-testHashRemoveForEachAll(void *payload ATTRIBUTE_UNUSED,
-                         const void *name,
-                         void *data)
-{
-    virHashTablePtr hash = data;
-
-    virHashRemoveEntry(hash, name);
-}
-
-
-const int testHashCountRemoveForEachForbidden = ARRAY_CARDINALITY(uuids);
-
-static void
-testHashRemoveForEachForbidden(void *payload ATTRIBUTE_UNUSED,
-                               const void *name,
-                               void *data)
-{
-    virHashTablePtr hash = data;
-    int i;
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
-        if (STREQ(uuids_subset[i], name)) {
-            int next = (i + 1) % ARRAY_CARDINALITY(uuids_subset);
-
-            if (virHashRemoveEntry(hash, uuids_subset[next]) == 0 &&
-                virTestGetVerbose()) {
-                fprintf(stderr,
-                        "\nentry \"%s\" should not be allowed to be removed",
-                        uuids_subset[next]);
-            }
-            break;
-        }
-    }
-}
-
-
-static int
-testHashRemoveForEach(const void *data)
-{
-    const struct testInfo *info = data;
-    virHashTablePtr hash;
-    int count;
-    int ret = -1;
-
-    if (!(hash = testHashInit(0)))
-        return -1;
-
-    count = virHashForEach(hash, (virHashIterator) info->data, hash);
-
-    if (count != ARRAY_CARDINALITY(uuids)) {
-        if (virTestGetVerbose()) {
-            testError("\nvirHashForEach didn't go through all entries,"
-                      " %d != %zu\n",
-                      count, ARRAY_CARDINALITY(uuids));
-        }
-        goto cleanup;
-    }
-
-    if (testHashCheckCount(hash, info->count) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-static int
-testHashSteal(const void *data ATTRIBUTE_UNUSED)
-{
-    int count = ARRAY_CARDINALITY(uuids) - ARRAY_CARDINALITY(uuids_subset);
-    virHashTablePtr hash;
-    int i;
-    int ret = -1;
-
-    if (!(hash = testHashInit(0)))
-        return -1;
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
-        if (!virHashSteal(hash, uuids_subset[i])) {
-            if (virTestGetVerbose()) {
-                fprintf(stderr, "\nentry \"%s\" could not be stolen\n",
-                        uuids_subset[i]);
-            }
-            goto cleanup;
-        }
-    }
-
-    if (testHashCheckCount(hash, count) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-static void
-testHashIter(void *payload ATTRIBUTE_UNUSED,
-             const void *name ATTRIBUTE_UNUSED,
-             void *data ATTRIBUTE_UNUSED)
-{
-    return;
-}
-
-static void
-testHashForEachIter(void *payload ATTRIBUTE_UNUSED,
-                    const void *name ATTRIBUTE_UNUSED,
-                    void *data)
-{
-    virHashTablePtr hash = data;
-
-    if (virHashAddEntry(hash, uuids_new[0], NULL) == 0 &&
-        virTestGetVerbose()) {
-        fprintf(stderr, "\nadding entries in ForEach should be forbidden");
-    }
-
-    if (virHashUpdateEntry(hash, uuids_new[0], NULL) == 0 &&
-        virTestGetVerbose()) {
-        fprintf(stderr, "\nupdating entries in ForEach should be forbidden");
-    }
-
-    if (virHashSteal(hash, uuids_new[0]) != NULL &&
-        virTestGetVerbose()) {
-        fprintf(stderr, "\nstealing entries in ForEach should be forbidden");
-    }
-
-    if (virHashSteal(hash, uuids_new[0]) != NULL &&
-        virTestGetVerbose()) {
-        fprintf(stderr, "\nstealing entries in ForEach should be forbidden");
-    }
-
-    if (virHashForEach(hash, testHashIter, NULL) >= 0 &&
-        virTestGetVerbose()) {
-        fprintf(stderr, "\niterating through hash in ForEach"
-                " should be forbidden");
-    }
-}
-
-static int
-testHashForEach(const void *data ATTRIBUTE_UNUSED)
-{
-    virHashTablePtr hash;
-    int count;
-    int ret = -1;
-
-    if (!(hash = testHashInit(0)))
-        return -1;
-
-    count = virHashForEach(hash, testHashForEachIter, hash);
-
-    if (count != ARRAY_CARDINALITY(uuids)) {
-        if (virTestGetVerbose()) {
-            testError("\nvirHashForEach didn't go through all entries,"
-                      " %d != %zu\n",
-                      count, ARRAY_CARDINALITY(uuids));
-        }
-        goto cleanup;
-    }
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-static int
-testHashRemoveSetIter(const void *payload ATTRIBUTE_UNUSED,
-                      const void *name,
-                      const void *data)
-{
-    int *count = (int *) data;
-    bool rem = false;
-    int i;
-
-    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
-        if (STREQ(uuids_subset[i], name)) {
-            rem = true;
-            break;
-        }
-    }
-
-    if (rem || rand() % 2) {
-        (*count)++;
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
-static int
-testHashRemoveSet(const void *data ATTRIBUTE_UNUSED)
-{
-    virHashTablePtr hash;
-    int count = 0;
-    int rcount;
-    int ret = -1;
-
-    if (!(hash = testHashInit(0)))
-        return -1;
-
-    /* seed the generator so that rand() provides reproducible sequence */
-    srand(9000);
-
-    rcount = virHashRemoveSet(hash, testHashRemoveSetIter, &count);
-
-    if (count != rcount) {
-        if (virTestGetVerbose()) {
-            testError("\nvirHashRemoveSet didn't remove expected number of"
-                      " entries, %d != %u\n",
-                      rcount, count);
-        }
-        goto cleanup;
-    }
-
-    if (testHashCheckCount(hash, ARRAY_CARDINALITY(uuids) - count) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-const int testSearchIndex = ARRAY_CARDINALITY(uuids_subset) / 2;
-
-static int
-testHashSearchIter(const void *payload ATTRIBUTE_UNUSED,
-                   const void *name,
-                   const void *data ATTRIBUTE_UNUSED)
-{
-    return STREQ(uuids_subset[testSearchIndex], name);
-}
-
-static int
-testHashSearch(const void *data ATTRIBUTE_UNUSED)
-{
-    virHashTablePtr hash;
-    void *entry;
-    int ret = -1;
-
-    if (!(hash = testHashInit(0)))
-        return -1;
-
-    entry = virHashSearch(hash, testHashSearchIter, NULL);
-
-    if (!entry || STRNEQ(uuids_subset[testSearchIndex], entry)) {
-        if (virTestGetVerbose()) {
-            testError("\nvirHashSearch didn't find entry '%s'\n",
-                      uuids_subset[testSearchIndex]);
-        }
-        goto cleanup;
-    }
-
-    if (testHashCheckCount(hash, ARRAY_CARDINALITY(uuids)) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash);
-    return ret;
-}
-
-
-static int
-testHashGetItemsCompKey(const virHashKeyValuePairPtr a,
-                        const virHashKeyValuePairPtr b)
-{
-    return strcmp (a->key, b->key);
-}
-
-static int
-testHashGetItemsCompValue(const virHashKeyValuePairPtr a,
-                          const virHashKeyValuePairPtr b)
-{
-    return strcmp (a->value, b->value);
-}
-
-static int
-testHashGetItems(const void *data ATTRIBUTE_UNUSED)
-{
-    virHashTablePtr hash;
-    virHashKeyValuePairPtr array = NULL;
-    int ret = -1;
-    char keya[] = "a";
-    char keyb[] = "b";
-    char keyc[] = "c";
-    char value1[] = "1";
-    char value2[] = "2";
-    char value3[] = "3";
-
-    if (!(hash = virHashCreate(0, NULL)) ||
-        virHashAddEntry(hash, keya, value3) < 0 ||
-        virHashAddEntry(hash, keyc, value1) < 0 ||
-        virHashAddEntry(hash, keyb, value2) < 0) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed to create hash");
-        }
-        goto cleanup;
-    }
-
-    if (!(array = virHashGetItems(hash, NULL)) ||
-        array[3].key || array[3].value) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed to get items with NULL sort");
-        }
-        goto cleanup;
-    }
-    VIR_FREE(array);
-
-    if (!(array = virHashGetItems(hash, testHashGetItemsCompKey)) ||
-        STRNEQ(array[0].key, "a") ||
-        STRNEQ(array[0].value, "3") ||
-        STRNEQ(array[1].key, "b") ||
-        STRNEQ(array[1].value, "2") ||
-        STRNEQ(array[2].key, "c") ||
-        STRNEQ(array[2].value, "1") ||
-        array[3].key || array[3].value) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed to get items with key sort");
-        }
-        goto cleanup;
-    }
-    VIR_FREE(array);
-
-    if (!(array = virHashGetItems(hash, testHashGetItemsCompValue)) ||
-        STRNEQ(array[0].key, "c") ||
-        STRNEQ(array[0].value, "1") ||
-        STRNEQ(array[1].key, "b") ||
-        STRNEQ(array[1].value, "2") ||
-        STRNEQ(array[2].key, "a") ||
-        STRNEQ(array[2].value, "3") ||
-        array[3].key || array[3].value) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed to get items with value sort");
-        }
-        goto cleanup;
-    }
-
-    ret = 0;
-
-cleanup:
-    VIR_FREE(array);
-    virHashFree(hash);
-    return ret;
-}
-
-static int
-testHashEqualCompValue(const void *value1, const void *value2)
-{
-    return c_strcasecmp(value1, value2);
-}
-
-static int
-testHashEqual(const void *data ATTRIBUTE_UNUSED)
-{
-    virHashTablePtr hash1, hash2 = NULL;
-    int ret = -1;
-    char keya[] = "a";
-    char keyb[] = "b";
-    char keyc[] = "c";
-    char value1_l[] = "m";
-    char value2_l[] = "n";
-    char value3_l[] = "o";
-    char value1_u[] = "M";
-    char value2_u[] = "N";
-    char value3_u[] = "O";
-    char value4_u[] = "P";
-
-    if (!(hash1 = virHashCreate(0, NULL)) ||
-        !(hash2 = virHashCreate(0, NULL)) ||
-        virHashAddEntry(hash1, keya, value1_l) < 0 ||
-        virHashAddEntry(hash1, keyb, value2_l) < 0 ||
-        virHashAddEntry(hash1, keyc, value3_l) < 0 ||
-        virHashAddEntry(hash2, keya, value1_u) < 0 ||
-        virHashAddEntry(hash2, keyb, value2_u) < 0) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed to create hashes");
-        }
-        goto cleanup;
-    }
-
-    if (virHashEqual(hash1, hash2, testHashEqualCompValue)) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed equal test for different number of elements");
-        }
-        goto cleanup;
-    }
-
-    if (virHashAddEntry(hash2, keyc, value4_u) < 0) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed to add element to hash2");
-        }
-        goto cleanup;
-    }
-
-    if (virHashEqual(hash1, hash2, testHashEqualCompValue)) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed equal test for same number of elements");
-        }
-        goto cleanup;
-    }
-
-    if (virHashUpdateEntry(hash2, keyc, value3_u) < 0) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed to update element in hash2");
-        }
-        goto cleanup;
-    }
-
-    if (!virHashEqual(hash1, hash2, testHashEqualCompValue)) {
-        if (virTestGetVerbose()) {
-            testError("\nfailed equal test for equal hash tables");
-        }
-        goto cleanup;
-    }
-
-    ret = 0;
-
-cleanup:
-    virHashFree(hash1);
-    virHashFree(hash2);
-    return ret;
-}
-
-
-static int
-mymain(void)
-{
-    int ret = 0;
-
-#define DO_TEST_FULL(name, cmd, data, count)                        \
-    do {                                                            \
-        struct testInfo info = { data, count };                     \
-        if (virtTestRun(name, 1, testHash ## cmd, &info) < 0)       \
-            ret = -1;                                               \
-    } while (0)
-
-#define DO_TEST_DATA(name, cmd, data)                               \
-    DO_TEST_FULL(name "(" #data ")",                                \
-                 cmd,                                               \
-                 testHash ## cmd ## data,                           \
-                 testHashCount ## cmd ## data)
-
-#define DO_TEST_COUNT(name, cmd, count)                             \
-    DO_TEST_FULL(name "(" #count ")", cmd, NULL, count)
-
-#define DO_TEST(name, cmd)                                          \
-    DO_TEST_FULL(name, cmd, NULL, -1)
-
-    DO_TEST_COUNT("Grow", Grow, 1);
-    DO_TEST_COUNT("Grow", Grow, 10);
-    DO_TEST_COUNT("Grow", Grow, 42);
-    DO_TEST("Update", Update);
-    DO_TEST("Remove", Remove);
-    DO_TEST_DATA("Remove in ForEach", RemoveForEach, Some);
-    DO_TEST_DATA("Remove in ForEach", RemoveForEach, All);
-    DO_TEST_DATA("Remove in ForEach", RemoveForEach, Forbidden);
-    DO_TEST("Steal", Steal);
-    DO_TEST("Forbidden ops in ForEach", ForEach);
-    DO_TEST("RemoveSet", RemoveSet);
-    DO_TEST("Search", Search);
-    DO_TEST("GetItems", GetItems);
-    DO_TEST("Equal", Equal);
-
-    return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-VIRT_TEST_MAIN(mymain)
diff --git a/tests/virhashdata.h b/tests/virhashdata.h
new file mode 100644 (file)
index 0000000..332e09c
--- /dev/null
@@ -0,0 +1,266 @@
+const char *uuids[] = {
+/* [  2] */ "a9b02f96-e430-4f7c-a7ff-a647d080447a",
+/* [  4] */ "202e32ca-f82c-4f13-9266-28dc8d002074",
+/* [  5] */ "e0233ed8-22da-4a1e-a1a2-2d0343635173",
+            "4ce4f92a-e116-4c38-81ca-acebbdcab410",
+/* [  6] */ "4121c24d-bfc3-45f9-85c6-899679b5cc60",
+            "e641740a-85dd-4414-bdbf-37dbaee39e26",
+/* [  9] */ "a0c94fa8-7d41-4100-8907-9b9209e7954a",
+/* [ 10] */ "d3c7d973-046d-4c49-90bb-7a353aaea8a2",
+            "ad15e406-8258-49ad-a47e-cbb955b34220",
+/* [ 11] */ "0979803b-6bcc-4305-917c-079dcc0f1cb4",
+/* [ 12] */ "0311fc3f-e5b1-48f5-ab9e-e577fbfc6b82",
+/* [ 14] */ "512aa755-3c48-456b-9545-3cc6f729444f",
+/* [ 16] */ "43b7e89e-c5cb-44c6-9bdb-7f070d6e5cf7",
+/* [ 17] */ "3e4fd85d-57d8-4d1d-867e-71ba3b898dc3",
+/* [ 18] */ "8433c800-1cda-4bf1-8a3d-879f657e0068",
+/* [ 20] */ "fb55ed30-a8fe-44ab-aa25-4d609c487975",
+/* [ 21] */ "b7fa38f1-f329-430d-8450-57d75175f578",
+/* [ 22] */ "bbbff7ba-73d8-42a0-ace3-dbf39906223a",
+/* [ 23] */ "1ef274ef-2c99-488f-ba25-21da0285d7fe",
+/* [ 26] */ "24e30027-16cf-4848-a4be-6dffae973757",
+/* [ 28] */ "fd056c9c-9f39-43b8-90be-aaff3909a56c",
+/* [ 29] */ "2c53a1dc-3b62-4369-a583-71cad3d1fa98",
+            "063b19c7-1c96-4cc8-ac18-bc007f073a13",
+/* [ 32] */ "f210da80-6e0a-4185-a96e-7bd32a779e72",
+/* [ 33] */ "dd557d13-0f6d-460a-8002-9392ce483e50",
+/* [ 34] */ "d16f07e4-f5be-4744-b70a-dc6e26666c44",
+/* [ 35] */ "dafe133f-d48c-4a30-b156-f073725401f5",
+/* [ 36] */ "96dfe074-7236-4898-aad2-81963c23adda",
+            "c971ea2e-9410-4b3c-9027-d678a0d9db8d",
+/* [ 38] */ "7b417156-b90a-4450-9c77-e1e94e1c980c",
+/* [ 39] */ "a7334316-6572-47d5-9330-9a3e70c30c6d",
+/* [ 40] */ "1e33c931-ef3a-497f-9374-6d9dddf04893",
+            "ebc4d160-4418-41cd-bd2f-0ef2741ffafb",
+/* [ 41] */ "6e13dd0b-67f8-447c-8445-9b8476a2e556",
+/* [ 42] */ "6123a5df-4b0b-421e-8dcb-4ecb3b33113d",
+/* [ 44] */ "75fc3921-558b-4093-82ba-e9807551de84",
+/* [ 45] */ "3308bc39-5d59-4ae8-8e45-bc1607a5d5d3",
+            "ad064af6-e55a-4de9-95b8-6a0afc77ad81",
+/* [ 46] */ "f17494ba-2353-4af0-b1ba-13680858edcc",
+            "64ab4e78-1b6e-4b88-b47f-2def46c79a86",
+            "f99b0d59-ecff-4cc6-a9d3-20159536edc8",
+/* [ 48] */ "a697613f-349b-41f8-80c5-f416ee462ca2",
+/* [ 52] */ "e9af1e6f-016d-43f3-8890-a33d924b4368",
+            "4e5c715a-4f37-4260-ae33-a86bc97f2a69",
+/* [ 54] */ "ae82cd8a-d67a-4fc7-9323-06511cbe9f4d",
+            "32d7a14c-4138-459e-aa19-5263d4a6b410",
+/* [ 56] */ "9aba27ea-37e4-485c-983c-42de92c2d2ea",
+/* [ 59] */ "45826b95-3120-417b-a5ff-5480e342f25e",
+            "834a24b7-5c77-4287-9266-82c2f2c9e9fc",
+/* [ 62] */ "d4d09671-8132-4809-badf-efbef39c9dac",
+/* [ 66] */ "b0bd3bd8-1271-4755-84e7-e89fabb929b2",
+/* [ 69] */ "86e2a115-3e5b-480e-9109-12ac4b525761",
+/* [ 70] */ "2896d83a-ede2-4a01-8047-25a0db868b27",
+/* [ 71] */ "1f290a52-51ad-4ea6-ae11-b90c50ba8ea6",
+/* [ 72] */ "511b890f-d9f5-4fb4-90d4-39e93719c4bf",
+/* [ 74] */ "51bf1c00-6c0a-4ca4-8acc-1ab9c6bc44ce",
+/* [ 75] */ "e1bfa30f-bc0b-4a24-99ae-bed7f3f21a7b",
+            "acda5fa0-58de-4e1e-aa65-2124d1e29c54",
+/* [ 76] */ "5f476c28-8f26-48e0-98de-85745fe2f304",
+/* [ 79] */ "4a1f1b60-4c53-4525-b687-f0175b6e19bc",
+/* [ 80] */ "608bcc5e-5ccc-4967-a58f-4d61665685bc",
+            "b7028f70-6d4d-4d0a-8c78-ec61fd6e38fc",
+/* [ 81] */ "03cc8179-3b0e-4c9f-a665-9ca416ee0e9b",
+/* [ 83] */ "2f32ba02-7a07-46e0-b859-a7b82a5de8e0",
+/* [ 85] */ "490b8a1b-4d7a-4d14-81c3-af6c4824632f",
+/* [ 88] */ "48e8c968-c1b7-4b3b-a24a-abb94604758b",
+/* [ 89] */ "242fd86e-d804-4b7e-9a92-b8227becdb91",
+/* [ 90] */ "13315204-76aa-4ae6-9f27-44434facea60",
+/* [ 91] */ "548544c8-1737-4efe-8661-4783e4b6ef12",
+/* [ 92] */ "3e6f26ce-ddb3-485c-86ca-b455fcfb802a",
+/* [ 93] */ "a6b1df31-2f3f-4314-87f9-fd794aad8d5a",
+            "bce3d144-820d-489b-8506-f04fdea2ee48",
+/* [ 95] */ "e400060d-4de7-4c12-9533-a9aa4296c44c",
+/* [ 96] */ "9a0a6b84-7263-46d3-a45e-ad9e7b61a109",
+            "a9734665-e800-4c99-96ec-dd0426e20b00",
+/* [ 97] */ "d3efc444-1758-4733-9cfb-50412ba7cf79",
+            "999edbf0-b194-43aa-87ed-afc2ae0fe30b",
+/* [ 98] */ "e866d6bf-2e7c-4f97-8178-1ca758020d2c",
+/* [ 99] */ "87b97bc3-62d1-465d-94a8-7ae22efd8103",
+/* [100] */ "050d33f5-e7b1-42e8-a253-292b2769069a",
+            "1b5fff42-37dc-4770-9a41-6df2fe4b7858",
+            "d6a4b1a3-6c19-46e1-90b9-2de3ef471eb3",
+/* [101] */ "51e8e981-dd6a-4e85-a6b4-ed60d38a72ac",
+/* [102] */ "7f62af6b-3954-4a7a-9b32-721d770da3d8",
+            "8016379a-9905-43cb-a6bd-98fc83296982",
+            "e003782c-fcec-449a-a0e4-cda41893e78f",
+/* [103] */ "954d5d6a-98b6-45ad-a95c-85721664b1ea",
+/* [105] */ "ccd3680a-d8ac-4f68-ac08-a7b59f31af10",
+/* [106] */ "cded8a5d-874c-4400-86a4-eb483cfe0265",
+/* [109] */ "356df5ef-c744-4696-a697-91f4634c8559",
+/* [110] */ "faee6c44-f212-4c8a-8e8c-bea91fb26532",
+/* [113] */ "84377685-45f9-4c89-ad4f-5776f6ffcff4",
+/* [116] */ "b69c50ec-2bd3-4162-bca3-eec4398f2d12",
+            "fb5e4a60-efdb-4884-bb9e-ac911b1b5100",
+            "d59a5c99-5ce5-46bf-8a80-cdf916f71576",
+/* [117] */ "c09322ef-0b70-4ea0-922b-95832bb5469c",
+/* [118] */ "47e88680-4f46-4096-9f77-1bd4e271acd5",
+/* [119] */ "570d5f36-31e6-412b-84dd-e5aabb73dd5b",
+            "56cf0509-741a-4a5c-a82c-51060f009b9a",
+/* [122] */ "c257b495-e53c-4be5-8b05-491057531120",
+            "654139f2-cef5-48df-a6b2-6ca6e9abb1de",
+/* [123] */ "8be1d21c-cd35-4c7c-8fee-4b5046c7a62b",
+            "830f0d57-9f21-40e8-bb86-cbf41de23fd6",
+            "57044958-1b8a-4c02-ab75-2298c6e44263",
+            "d526cd6c-4a99-4d5f-abfb-fc9419edd9d0",
+/* [124] */ "36492c15-ce5a-4f9b-b75a-97937981f9b4",
+            "66a984a9-cd04-4683-b241-2b296da662bc",
+            "0b3404eb-022b-4ef1-a78d-a2b12230b258",
+/* [125] */ "f8d7efcf-1138-422b-a844-feffa7478be8",
+/* [130] */ "4f8ca175-6efa-476e-ab58-11efe9211415",
+/* [131] */ "87fcc2e2-0b65-4eaa-8bea-74de85abf3fe",
+            "ea0d108f-8a39-414a-88c6-fcabce029af7",
+            "b1f17225-efb3-4b8a-aae3-a2ca53eeb99e",
+            "45dcb41d-0628-485f-9f14-3296410555a5",
+/* [133] */ "a2b16b3f-93df-4d5a-a226-5f340bf2b0a3",
+/* [140] */ "373025da-238a-467f-8164-b5675cfe6422",
+/* [141] */ "8969aa50-6d2b-4659-ade1-b4a2169e0ed1",
+/* [142] */ "ba092226-be95-4ec2-8c35-215db61448e6",
+/* [143] */ "4213fb5a-6d28-4296-85a6-bb149a0468b7",
+/* [144] */ "05bd2d12-1062-46c3-9ac2-362617175b04",
+/* [145] */ "97cff77b-9f8d-40e9-8c41-601dc280a413",
+            "4d05b973-b30b-4416-bdd8-e3773b30cb6e",
+            "95382996-dfce-483d-8ff8-1d05c6c65bb5",
+/* [146] */ "04213584-d98a-4e82-a884-1238a7568c48",
+/* [148] */ "68bad966-22ec-4e87-9c6c-c1dd000959c4",
+            "f1b44f04-2028-4855-ad6c-9538ef6e44a2",
+/* [149] */ "8748c9ae-624d-4fb1-a3d3-5073716c882c",
+/* [150] */ "e0eb4d5b-d251-41c9-9215-0e2830413fe4",
+            "426795e5-a6e2-4b42-a81d-41cddb79f9b6",
+            "a16297c6-e9f4-49c4-b244-4e2ae2803ce3",
+/* [151] */ "ea07d3ec-4f35-41db-afd2-4bc2b3273e0f",
+            "f013f77d-8bd8-4a8e-82e9-82512071ac0f",
+/* [152] */ "754038bd-c382-4605-b53d-600f165aac10",
+/* [156] */ "06575e79-74dd-46c1-a752-de53b8bf8987",
+/* [158] */ "00a14b42-e60e-4214-9de1-9ff187a67e6e",
+/* [159] */ "93d02eb8-325b-42cc-b1b6-435eeb6e0449",
+/* [163] */ "f9e5528e-52ec-4164-8b4d-0b25a4715ce6",
+/* [166] */ "f1a3af6e-b8c3-4836-95da-3c4b740dab80",
+/* [169] */ "81af0cbf-b3c5-49b9-ae04-bf93e493943f",
+/* [170] */ "ab7bd5e5-68cc-4a04-9773-e668bf1d5e55",
+/* [172] */ "55ff86fa-2fc0-46c1-a222-3b9bfef434be",
+/* [174] */ "ed7dda66-4ec3-438b-8444-5f998528c7c1",
+/* [175] */ "3929d8b1-f6f7-44f6-8366-8ccc6d6c8dae",
+/* [178] */ "455a7a4c-1602-453b-9729-03c040ba1ed7",
+            "6e68d708-26c3-45db-ae71-52c0ef0e3879",
+/* [179] */ "c6be4f40-aad8-4be5-bc50-e8bb9217e988",
+/* [181] */ "550e511b-3105-485f-8856-593761339f08",
+/* [182] */ "dea7c93f-a9e5-4622-9da5-0959f2561e33",
+/* [183] */ "705c2f9b-08d2-4502-b53e-0b01db35acd3",
+            "819c7473-898f-439b-935d-fe4a96f64150",
+/* [185] */ "8c1fc53f-7867-4399-8c6c-a6e4b128a9f8",
+/* [187] */ "a1bf2aed-639d-4e1b-9aa3-6b7be8a49c59",
+/* [188] */ "4e92f93d-4667-414e-a7bf-b42d33bc409e",
+            "4013ec51-05a8-479b-9d5a-8f1149039e34",
+            "796ec0f2-b9f9-4a9e-ac8e-1ce726eef88c",
+/* [189] */ "7328ee55-9cd2-4f37-ac3c-630287a65f7c",
+            "225d01da-9bbd-4cb1-b892-fd8a4a604c76",
+/* [190] */ "97fd798d-94a7-4089-aaf6-50919d105c4c",
+            "cb792c37-7cd2-4649-ab92-180fef7b9911",
+/* [191] */ "7edcabaa-70f7-447d-9bb8-95537cd48b0d",
+/* [192] */ "df3348bf-5eda-480a-9a3b-c26eb9df3d80",
+/* [193] */ "854b565d-0ea7-40b3-ba41-054e2d4e1869",
+            "079d9a35-331e-489d-b153-493ca28fe95c",
+/* [194] */ "589778f4-cca0-4969-a27c-ccd29b2d35f0",
+/* [195] */ "e0505dd6-3f2c-4ac1-8d93-41fb021af558",
+/* [196] */ "ab8be1c6-18f4-4ecb-a115-8d839dba1bd0",
+/* [197] */ "7dab18d4-4fc6-451f-9558-0b719bb2ecec",
+/* [200] */ "f9c10e12-877a-4750-a697-d39691443c54",
+            "a5be8e6c-7d4c-48aa-b457-22168cf56ddf",
+            "72160964-cd58-4a01-bdbf-7f5151975ffe",
+/* [202] */ "84d91759-4a70-4bc3-808d-24a8fc4c0816",
+            "fad2acc3-ebda-490c-9698-06cd6690b924",
+            "17191452-f402-47a0-b3e9-ae3e5688a534",
+/* [203] */ "f328382f-2706-4a0b-aac8-b9ffed687997",
+            "5cbd8451-cc3e-4dc4-bd3b-0033d8c869ff",
+/* [204] */ "704436e1-e9b3-4269-813a-a1c6a425cb4d",
+/* [206] */ "80748ed5-3d42-4d95-ba21-30b071ac17ad",
+            "bb3f3be2-2ab7-48fb-b71b-45041b732887",
+/* [207] */ "ae45b5a6-ea00-4e0c-948a-ebf3c84dfd01",
+            "10363e09-d2e0-40a5-afce-0fdf852222d7",
+/* [209] */ "777174f9-d80c-46f9-9fe8-5d59c93abd64",
+            "5c75455b-4317-4285-818f-3ffc165b05f9",
+            "dc708225-bcb0-447b-99ca-4291d717a600",
+/* [210] */ "1dc43c46-ff0a-4527-9b01-34dde0abf4b8",
+            "559813cd-ba6f-446f-af56-224170d39cce",
+            "3c1c7283-78e1-4082-a191-d2eeed51d7fd",
+/* [212] */ "1cda8175-d221-452a-8aad-e96d2da674ed",
+/* [213] */ "751bcb18-2235-4bb9-b320-36551c3e8810",
+/* [214] */ "fe3a9c52-6058-4203-9fa0-6c657852026c",
+/* [215] */ "29fb462f-6975-41b0-b6fa-c2556a658a68",
+/* [216] */ "c0f80985-d1cc-4ea6-839e-02e52b33623f",
+            "404e1b0c-5e34-4419-818e-6707b8f90248",
+            "34d224fc-9803-4da5-a08e-4b49e5d24592",
+/* [217] */ "2977ad89-0ec8-4f60-8228-1b82a65a7c7c",
+            "b954246e-29cf-4792-ae60-b841e5710111",
+/* [218] */ "b54ede2a-70af-4a63-9d17-410ba5ee6c0c",
+/* [219] */ "b2baf136-de10-48ca-ae6b-0f802acbf09c",
+/* [220] */ "e55df82c-2128-43bf-a681-e626a2c4d1c3",
+            "67338b47-c2f1-4f73-956c-4b54e427e6e4",
+/* [221] */ "450cca9c-38f6-4eb8-b537-190fc3fff99d",
+/* [222] */ "6b4ccebf-e741-4a54-97a4-20ac92c18107",
+/* [225] */ "3a7ea080-fb0b-4ef3-b005-5b9e2aa931a2",
+            "78d7fc2b-883d-48b1-9896-bf660ca0fe5a",
+            "f12574f2-452c-4363-90a1-eeaa353936d6",
+/* [226] */ "1ae1d3f8-974e-47a7-8f26-a105766fc24d",
+/* [227] */ "9f2506cf-4aea-4c47-8897-f6b83ba814fb",
+/* [228] */ "125dba5c-b19a-4218-928f-553788c02637",
+/* [229] */ "5c7eb444-84c1-4a3b-8385-ccf4c6632dc3",
+/* [232] */ "5c2dfc36-cf78-4718-acf4-c2823c95054a",
+            "b6442198-b321-4f0d-9fdb-c12115831875",
+            "0cf5fc99-c43f-4a36-837a-b3bad7902cb8",
+/* [233] */ "b3631261-7322-405d-bb14-245bf29e729c",
+            "2cc98dd0-5ae1-4a01-b2fd-7e1074bc9110",
+            "3c6a9e1c-0425-4af3-aef8-d4e336fe4397",
+/* [235] */ "2f52aab9-c383-4ac6-b1e1-c317198a3105",
+            "b06bf0b1-0b05-42ed-b79e-4770671c90e2",
+/* [237] */ "3ab39f7f-4613-4da6-a216-c2d6acc441bb",
+            "ae20cf3c-38b8-483c-baea-6fb0994dc30c",
+            "cd204d90-2414-4b9e-9d4f-fed09c9a816f",
+/* [240] */ "ed2cc723-db4b-43aa-ab02-0e3161087499",
+/* [241] */ "9cc96bd6-0ca0-466a-b897-e11eb7540b07",
+/* [244] */ "8d45a51f-a945-4de1-b89c-2b39d1a5b90e",
+/* [245] */ "6cd02e53-40ac-4269-91c9-4e1088af91f1",
+/* [246] */ "8ada85bc-9bdf-4507-8334-849635ea0a01",
+            "8a7d5deb-615f-4cd3-8977-b5fab8ec4d05",
+/* [247] */ "dc2173b0-48fe-4555-b190-8052be1120eb",
+            "040e434d-68d8-41a9-b3a1-1bee239914c1",
+            "d1a564b2-c7f3-4b76-8712-3b8f5aae6ded",
+            "0e614f33-c1da-4cfe-b6d5-65ecd2d066f2",
+/* [250] */ "334fdaba-f373-42ff-8546-219c1463a7c5",
+            "d4ff408e-8d43-46ff-94a4-bcfa6c994776",
+/* [253] */ "d1abd887-d5de-46b0-88d6-f71f31a61305",
+/* [254] */ "1d76af65-64d6-4211-b1b5-f5b799595e4d",
+/* [255] */ "b3ad4257-29b0-4c44-b7a7-95f1d102769c",
+};
+
+const char *uuids_subset[] = {
+    "64ab4e78-1b6e-4b88-b47f-2def46c79a86",
+    "acda5fa0-58de-4e1e-aa65-2124d1e29c54",
+    "830f0d57-9f21-40e8-bb86-cbf41de23fd6",
+    "57044958-1b8a-4c02-ab75-2298c6e44263",
+    "ae20cf3c-38b8-483c-baea-6fb0994dc30c",
+    "040e434d-68d8-41a9-b3a1-1bee239914c1",
+    "d1a564b2-c7f3-4b76-8712-3b8f5aae6ded",
+    "8ada85bc-9bdf-4507-8334-849635ea0a01",
+    "97cff77b-9f8d-40e9-8c41-601dc280a413",
+    "4d05b973-b30b-4416-bdd8-e3773b30cb6e",
+    "95382996-dfce-483d-8ff8-1d05c6c65bb5",
+};
+
+const char *uuids_new[] = {
+    "a103cc42-d0e5-40fb-8f7f-3c1bee93e327",
+    "01e13dc5-e65b-4988-a0cc-0d2f1f1e10fe",
+    "71f3678a-a8c6-4176-a26e-c34779067135",
+    "4f054508-22d5-49e1-9962-7508225c8b16",
+    "e572116b-5b7b-45fd-bbe9-296029ce16b5",
+    "695c8cfe-9830-4d9a-be67-50a124cefb76",
+    "ea244996-645b-4a19-ad4a-48f3022b8e94",
+    "0fd98758-9cc4-4779-b403-95ae3500f138",
+    "b86772b4-0728-46ae-99e8-027799697838",
+    "1c0cd559-81cd-4c27-8e24-6aef6f5af7f1",
+    "2a37fe4a-8825-4fd6-9284-e1606967548a",
+    "5920cc9d-62a3-4772-9e73-eb97f0bc483c",
+    "53c215dd-bdba-4fdc-887a-86ab6f860df4",
+};
diff --git a/tests/virhashtest.c b/tests/virhashtest.c
new file mode 100644 (file)
index 0000000..ba0cf02
--- /dev/null
@@ -0,0 +1,698 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "internal.h"
+#include "virhash.h"
+#include "virhashdata.h"
+#include "testutils.h"
+#include "memory.h"
+
+
+#define testError(...)                                          \
+    do {                                                        \
+        fprintf(stderr, __VA_ARGS__);                           \
+        /* Pad to line up with test name ... in virTestRun */   \
+        fprintf(stderr, "%74s", "... ");                        \
+    } while (0)
+
+
+static virHashTablePtr
+testHashInit(int size)
+{
+    virHashTablePtr hash;
+    ssize_t i;
+
+    if (!(hash = virHashCreate(size, NULL)))
+        return NULL;
+
+    /* entires are added in reverse order so that they will be linked in
+     * collision list in the same order as in the uuids array
+     */
+    for (i = ARRAY_CARDINALITY(uuids) - 1; i >= 0; i--) {
+        ssize_t oldsize = virHashTableSize(hash);
+        if (virHashAddEntry(hash, uuids[i], (void *) uuids[i]) < 0) {
+            virHashFree(hash);
+            return NULL;
+        }
+
+        if (virHashTableSize(hash) != oldsize && virTestGetDebug()) {
+            fprintf(stderr, "\nhash grown from %zd to %zd",
+                    oldsize, virHashTableSize(hash));
+        }
+    }
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids); i++) {
+        if (!virHashLookup(hash, uuids[i])) {
+            if (virTestGetVerbose()) {
+                fprintf(stderr, "\nentry \"%s\" could not be found\n",
+                        uuids[i]);
+            }
+            virHashFree(hash);
+            return NULL;
+        }
+    }
+
+    if (size && size != virHashTableSize(hash) && virTestGetDebug())
+        fprintf(stderr, "\n");
+
+    return hash;
+}
+
+static void
+testHashCheckForEachCount(void *payload ATTRIBUTE_UNUSED,
+                          const void *name ATTRIBUTE_UNUSED,
+                          void *data ATTRIBUTE_UNUSED)
+{
+}
+
+static int
+testHashCheckCount(virHashTablePtr hash, size_t count)
+{
+    ssize_t iter_count = 0;
+
+    if (virHashSize(hash) != count) {
+        testError("\nhash contains %zd instead of %zu elements\n",
+                  virHashSize(hash), count);
+        return -1;
+    }
+
+    iter_count = virHashForEach(hash, testHashCheckForEachCount, NULL);
+    if (count != iter_count) {
+        testError("\nhash claims to have %zu elements but iteration finds %zd\n",
+                  count, iter_count);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+struct testInfo {
+    void *data;
+    size_t count;
+};
+
+
+static int
+testHashGrow(const void *data)
+{
+    const struct testInfo *info = data;
+    virHashTablePtr hash;
+    int ret = -1;
+
+    if (!(hash = testHashInit(info->count)))
+        return -1;
+
+    if (testHashCheckCount(hash, ARRAY_CARDINALITY(uuids)) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+static int
+testHashUpdate(const void *data ATTRIBUTE_UNUSED)
+{
+    int count = ARRAY_CARDINALITY(uuids) + ARRAY_CARDINALITY(uuids_new);
+    virHashTablePtr hash;
+    int i;
+    int ret = -1;
+
+    if (!(hash = testHashInit(0)))
+        return -1;
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
+        if (virHashUpdateEntry(hash, uuids_subset[i], (void *) 1) < 0) {
+            if (virTestGetVerbose()) {
+                fprintf(stderr, "\nentry \"%s\" could not be updated\n",
+                        uuids_subset[i]);
+            }
+            goto cleanup;
+        }
+    }
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids_new); i++) {
+        if (virHashUpdateEntry(hash, uuids_new[i], (void *) 1) < 0) {
+            if (virTestGetVerbose()) {
+                fprintf(stderr, "\nnew entry \"%s\" could not be updated\n",
+                        uuids_new[i]);
+            }
+            goto cleanup;
+        }
+    }
+
+    if (testHashCheckCount(hash, count) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+static int
+testHashRemove(const void *data ATTRIBUTE_UNUSED)
+{
+    int count = ARRAY_CARDINALITY(uuids) - ARRAY_CARDINALITY(uuids_subset);
+    virHashTablePtr hash;
+    int i;
+    int ret = -1;
+
+    if (!(hash = testHashInit(0)))
+        return -1;
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
+        if (virHashRemoveEntry(hash, uuids_subset[i]) < 0) {
+            if (virTestGetVerbose()) {
+                fprintf(stderr, "\nentry \"%s\" could not be removed\n",
+                        uuids_subset[i]);
+            }
+            goto cleanup;
+        }
+    }
+
+    if (testHashCheckCount(hash, count) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+const int testHashCountRemoveForEachSome =
+    ARRAY_CARDINALITY(uuids) - ARRAY_CARDINALITY(uuids_subset);
+
+static void
+testHashRemoveForEachSome(void *payload ATTRIBUTE_UNUSED,
+                          const void *name,
+                          void *data)
+{
+    virHashTablePtr hash = data;
+    int i;
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
+        if (STREQ(uuids_subset[i], name)) {
+            if (virHashRemoveEntry(hash, name) < 0 && virTestGetVerbose()) {
+                fprintf(stderr, "\nentry \"%s\" could not be removed",
+                        uuids_subset[i]);
+            }
+            break;
+        }
+    }
+}
+
+
+const int testHashCountRemoveForEachAll = 0;
+
+static void
+testHashRemoveForEachAll(void *payload ATTRIBUTE_UNUSED,
+                         const void *name,
+                         void *data)
+{
+    virHashTablePtr hash = data;
+
+    virHashRemoveEntry(hash, name);
+}
+
+
+const int testHashCountRemoveForEachForbidden = ARRAY_CARDINALITY(uuids);
+
+static void
+testHashRemoveForEachForbidden(void *payload ATTRIBUTE_UNUSED,
+                               const void *name,
+                               void *data)
+{
+    virHashTablePtr hash = data;
+    int i;
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
+        if (STREQ(uuids_subset[i], name)) {
+            int next = (i + 1) % ARRAY_CARDINALITY(uuids_subset);
+
+            if (virHashRemoveEntry(hash, uuids_subset[next]) == 0 &&
+                virTestGetVerbose()) {
+                fprintf(stderr,
+                        "\nentry \"%s\" should not be allowed to be removed",
+                        uuids_subset[next]);
+            }
+            break;
+        }
+    }
+}
+
+
+static int
+testHashRemoveForEach(const void *data)
+{
+    const struct testInfo *info = data;
+    virHashTablePtr hash;
+    int count;
+    int ret = -1;
+
+    if (!(hash = testHashInit(0)))
+        return -1;
+
+    count = virHashForEach(hash, (virHashIterator) info->data, hash);
+
+    if (count != ARRAY_CARDINALITY(uuids)) {
+        if (virTestGetVerbose()) {
+            testError("\nvirHashForEach didn't go through all entries,"
+                      " %d != %zu\n",
+                      count, ARRAY_CARDINALITY(uuids));
+        }
+        goto cleanup;
+    }
+
+    if (testHashCheckCount(hash, info->count) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+static int
+testHashSteal(const void *data ATTRIBUTE_UNUSED)
+{
+    int count = ARRAY_CARDINALITY(uuids) - ARRAY_CARDINALITY(uuids_subset);
+    virHashTablePtr hash;
+    int i;
+    int ret = -1;
+
+    if (!(hash = testHashInit(0)))
+        return -1;
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
+        if (!virHashSteal(hash, uuids_subset[i])) {
+            if (virTestGetVerbose()) {
+                fprintf(stderr, "\nentry \"%s\" could not be stolen\n",
+                        uuids_subset[i]);
+            }
+            goto cleanup;
+        }
+    }
+
+    if (testHashCheckCount(hash, count) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+static void
+testHashIter(void *payload ATTRIBUTE_UNUSED,
+             const void *name ATTRIBUTE_UNUSED,
+             void *data ATTRIBUTE_UNUSED)
+{
+    return;
+}
+
+static void
+testHashForEachIter(void *payload ATTRIBUTE_UNUSED,
+                    const void *name ATTRIBUTE_UNUSED,
+                    void *data)
+{
+    virHashTablePtr hash = data;
+
+    if (virHashAddEntry(hash, uuids_new[0], NULL) == 0 &&
+        virTestGetVerbose()) {
+        fprintf(stderr, "\nadding entries in ForEach should be forbidden");
+    }
+
+    if (virHashUpdateEntry(hash, uuids_new[0], NULL) == 0 &&
+        virTestGetVerbose()) {
+        fprintf(stderr, "\nupdating entries in ForEach should be forbidden");
+    }
+
+    if (virHashSteal(hash, uuids_new[0]) != NULL &&
+        virTestGetVerbose()) {
+        fprintf(stderr, "\nstealing entries in ForEach should be forbidden");
+    }
+
+    if (virHashSteal(hash, uuids_new[0]) != NULL &&
+        virTestGetVerbose()) {
+        fprintf(stderr, "\nstealing entries in ForEach should be forbidden");
+    }
+
+    if (virHashForEach(hash, testHashIter, NULL) >= 0 &&
+        virTestGetVerbose()) {
+        fprintf(stderr, "\niterating through hash in ForEach"
+                " should be forbidden");
+    }
+}
+
+static int
+testHashForEach(const void *data ATTRIBUTE_UNUSED)
+{
+    virHashTablePtr hash;
+    int count;
+    int ret = -1;
+
+    if (!(hash = testHashInit(0)))
+        return -1;
+
+    count = virHashForEach(hash, testHashForEachIter, hash);
+
+    if (count != ARRAY_CARDINALITY(uuids)) {
+        if (virTestGetVerbose()) {
+            testError("\nvirHashForEach didn't go through all entries,"
+                      " %d != %zu\n",
+                      count, ARRAY_CARDINALITY(uuids));
+        }
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+static int
+testHashRemoveSetIter(const void *payload ATTRIBUTE_UNUSED,
+                      const void *name,
+                      const void *data)
+{
+    int *count = (int *) data;
+    bool rem = false;
+    int i;
+
+    for (i = 0; i < ARRAY_CARDINALITY(uuids_subset); i++) {
+        if (STREQ(uuids_subset[i], name)) {
+            rem = true;
+            break;
+        }
+    }
+
+    if (rem || rand() % 2) {
+        (*count)++;
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+static int
+testHashRemoveSet(const void *data ATTRIBUTE_UNUSED)
+{
+    virHashTablePtr hash;
+    int count = 0;
+    int rcount;
+    int ret = -1;
+
+    if (!(hash = testHashInit(0)))
+        return -1;
+
+    /* seed the generator so that rand() provides reproducible sequence */
+    srand(9000);
+
+    rcount = virHashRemoveSet(hash, testHashRemoveSetIter, &count);
+
+    if (count != rcount) {
+        if (virTestGetVerbose()) {
+            testError("\nvirHashRemoveSet didn't remove expected number of"
+                      " entries, %d != %u\n",
+                      rcount, count);
+        }
+        goto cleanup;
+    }
+
+    if (testHashCheckCount(hash, ARRAY_CARDINALITY(uuids) - count) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+const int testSearchIndex = ARRAY_CARDINALITY(uuids_subset) / 2;
+
+static int
+testHashSearchIter(const void *payload ATTRIBUTE_UNUSED,
+                   const void *name,
+                   const void *data ATTRIBUTE_UNUSED)
+{
+    return STREQ(uuids_subset[testSearchIndex], name);
+}
+
+static int
+testHashSearch(const void *data ATTRIBUTE_UNUSED)
+{
+    virHashTablePtr hash;
+    void *entry;
+    int ret = -1;
+
+    if (!(hash = testHashInit(0)))
+        return -1;
+
+    entry = virHashSearch(hash, testHashSearchIter, NULL);
+
+    if (!entry || STRNEQ(uuids_subset[testSearchIndex], entry)) {
+        if (virTestGetVerbose()) {
+            testError("\nvirHashSearch didn't find entry '%s'\n",
+                      uuids_subset[testSearchIndex]);
+        }
+        goto cleanup;
+    }
+
+    if (testHashCheckCount(hash, ARRAY_CARDINALITY(uuids)) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash);
+    return ret;
+}
+
+
+static int
+testHashGetItemsCompKey(const virHashKeyValuePairPtr a,
+                        const virHashKeyValuePairPtr b)
+{
+    return strcmp (a->key, b->key);
+}
+
+static int
+testHashGetItemsCompValue(const virHashKeyValuePairPtr a,
+                          const virHashKeyValuePairPtr b)
+{
+    return strcmp (a->value, b->value);
+}
+
+static int
+testHashGetItems(const void *data ATTRIBUTE_UNUSED)
+{
+    virHashTablePtr hash;
+    virHashKeyValuePairPtr array = NULL;
+    int ret = -1;
+    char keya[] = "a";
+    char keyb[] = "b";
+    char keyc[] = "c";
+    char value1[] = "1";
+    char value2[] = "2";
+    char value3[] = "3";
+
+    if (!(hash = virHashCreate(0, NULL)) ||
+        virHashAddEntry(hash, keya, value3) < 0 ||
+        virHashAddEntry(hash, keyc, value1) < 0 ||
+        virHashAddEntry(hash, keyb, value2) < 0) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed to create hash");
+        }
+        goto cleanup;
+    }
+
+    if (!(array = virHashGetItems(hash, NULL)) ||
+        array[3].key || array[3].value) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed to get items with NULL sort");
+        }
+        goto cleanup;
+    }
+    VIR_FREE(array);
+
+    if (!(array = virHashGetItems(hash, testHashGetItemsCompKey)) ||
+        STRNEQ(array[0].key, "a") ||
+        STRNEQ(array[0].value, "3") ||
+        STRNEQ(array[1].key, "b") ||
+        STRNEQ(array[1].value, "2") ||
+        STRNEQ(array[2].key, "c") ||
+        STRNEQ(array[2].value, "1") ||
+        array[3].key || array[3].value) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed to get items with key sort");
+        }
+        goto cleanup;
+    }
+    VIR_FREE(array);
+
+    if (!(array = virHashGetItems(hash, testHashGetItemsCompValue)) ||
+        STRNEQ(array[0].key, "c") ||
+        STRNEQ(array[0].value, "1") ||
+        STRNEQ(array[1].key, "b") ||
+        STRNEQ(array[1].value, "2") ||
+        STRNEQ(array[2].key, "a") ||
+        STRNEQ(array[2].value, "3") ||
+        array[3].key || array[3].value) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed to get items with value sort");
+        }
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    VIR_FREE(array);
+    virHashFree(hash);
+    return ret;
+}
+
+static int
+testHashEqualCompValue(const void *value1, const void *value2)
+{
+    return c_strcasecmp(value1, value2);
+}
+
+static int
+testHashEqual(const void *data ATTRIBUTE_UNUSED)
+{
+    virHashTablePtr hash1, hash2 = NULL;
+    int ret = -1;
+    char keya[] = "a";
+    char keyb[] = "b";
+    char keyc[] = "c";
+    char value1_l[] = "m";
+    char value2_l[] = "n";
+    char value3_l[] = "o";
+    char value1_u[] = "M";
+    char value2_u[] = "N";
+    char value3_u[] = "O";
+    char value4_u[] = "P";
+
+    if (!(hash1 = virHashCreate(0, NULL)) ||
+        !(hash2 = virHashCreate(0, NULL)) ||
+        virHashAddEntry(hash1, keya, value1_l) < 0 ||
+        virHashAddEntry(hash1, keyb, value2_l) < 0 ||
+        virHashAddEntry(hash1, keyc, value3_l) < 0 ||
+        virHashAddEntry(hash2, keya, value1_u) < 0 ||
+        virHashAddEntry(hash2, keyb, value2_u) < 0) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed to create hashes");
+        }
+        goto cleanup;
+    }
+
+    if (virHashEqual(hash1, hash2, testHashEqualCompValue)) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed equal test for different number of elements");
+        }
+        goto cleanup;
+    }
+
+    if (virHashAddEntry(hash2, keyc, value4_u) < 0) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed to add element to hash2");
+        }
+        goto cleanup;
+    }
+
+    if (virHashEqual(hash1, hash2, testHashEqualCompValue)) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed equal test for same number of elements");
+        }
+        goto cleanup;
+    }
+
+    if (virHashUpdateEntry(hash2, keyc, value3_u) < 0) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed to update element in hash2");
+        }
+        goto cleanup;
+    }
+
+    if (!virHashEqual(hash1, hash2, testHashEqualCompValue)) {
+        if (virTestGetVerbose()) {
+            testError("\nfailed equal test for equal hash tables");
+        }
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    virHashFree(hash1);
+    virHashFree(hash2);
+    return ret;
+}
+
+
+static int
+mymain(void)
+{
+    int ret = 0;
+
+#define DO_TEST_FULL(name, cmd, data, count)                        \
+    do {                                                            \
+        struct testInfo info = { data, count };                     \
+        if (virtTestRun(name, 1, testHash ## cmd, &info) < 0)       \
+            ret = -1;                                               \
+    } while (0)
+
+#define DO_TEST_DATA(name, cmd, data)                               \
+    DO_TEST_FULL(name "(" #data ")",                                \
+                 cmd,                                               \
+                 testHash ## cmd ## data,                           \
+                 testHashCount ## cmd ## data)
+
+#define DO_TEST_COUNT(name, cmd, count)                             \
+    DO_TEST_FULL(name "(" #count ")", cmd, NULL, count)
+
+#define DO_TEST(name, cmd)                                          \
+    DO_TEST_FULL(name, cmd, NULL, -1)
+
+    DO_TEST_COUNT("Grow", Grow, 1);
+    DO_TEST_COUNT("Grow", Grow, 10);
+    DO_TEST_COUNT("Grow", Grow, 42);
+    DO_TEST("Update", Update);
+    DO_TEST("Remove", Remove);
+    DO_TEST_DATA("Remove in ForEach", RemoveForEach, Some);
+    DO_TEST_DATA("Remove in ForEach", RemoveForEach, All);
+    DO_TEST_DATA("Remove in ForEach", RemoveForEach, Forbidden);
+    DO_TEST("Steal", Steal);
+    DO_TEST("Forbidden ops in ForEach", ForEach);
+    DO_TEST("RemoveSet", RemoveSet);
+    DO_TEST("Search", Search);
+    DO_TEST("GetItems", GetItems);
+    DO_TEST("Equal", Equal);
+
+    return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN(mymain)