diff options
| author | Joel Klinghed <the_jk@yahoo.com> | 2011-11-17 21:32:51 +0100 |
|---|---|---|
| committer | Joel Klinghed <the_jk@yahoo.com> | 2011-11-17 21:32:51 +0100 |
| commit | 574e9ca2bc2d2893767b14e0732cbffd07d4979a (patch) | |
| tree | 291523ce96b6376d85dcdac86063351e6f6552ba /test/test_hashlist.c | |
| parent | 331d327671af3969e56e8019657a91ead88643d3 (diff) | |
autofoo & finishing touches on VIEW torrent. Interaction next time
Diffstat (limited to 'test/test_hashlist.c')
| -rw-r--r-- | test/test_hashlist.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/test/test_hashlist.c b/test/test_hashlist.c new file mode 100644 index 0000000..a0dbbf0 --- /dev/null +++ b/test/test_hashlist.c @@ -0,0 +1,284 @@ +#include "common.h" + +#include <glib.h> +#include <stdio.h> +#include <string.h> + +typedef struct _hashlist_t +{ + gchar** data; + gboolean* mark; + gsize size, fill; + + const gchar** added; + const gchar** removed; +} hashlist_t; + +static void hashlist_init(hashlist_t* hlist); +static void hashlist_clear(hashlist_t* hlist); +static void hashlist_free(hashlist_t* hlist); +static gboolean hashlist_sync(hashlist_t* hlist, + const gchar** list, gsize count); + +static gboolean check(const gchar* name, hashlist_t* hlist, ...); + +#define CHECK(name, args...) \ + do { \ + ++tot; ok += check(name, &list, args) ? 1 : 0; \ + } while (0) + +int main(int argc, char** argv) +{ + static const gchar* data[] = { "foo", "bar", "meh", "muh" }; + int tot = 0, ok = 0; + hashlist_t list; + + hashlist_init(&list); + + hashlist_sync(&list, data, 0); + CHECK("nop sync", NULL, NULL); + + hashlist_sync(&list, data, 2); + CHECK("add foo,bar", "foo", "bar", NULL, NULL); + + hashlist_sync(&list, data, 4); + CHECK("add meh,muh", "meh", "muh", NULL, NULL); + + hashlist_sync(&list, data + 2, 2); + CHECK("remove foo,bar", NULL, "foo", "bar", NULL); + + hashlist_sync(&list, data, 4); + CHECK("add foo,bar", "foo", "bar", NULL, NULL); + + hashlist_sync(&list, data, 3); + CHECK("remove muh", NULL, "muh", NULL); + + hashlist_sync(&list, data + 1, 1); + CHECK("remove foo,meh", NULL, "meh", "foo", NULL); + + hashlist_sync(&list, data + 2, 2); + CHECK("remove bar, add meh,muh", "meh", "muh", NULL, "bar", NULL); + + hashlist_clear(&list); + CHECK("clear", NULL, NULL); + + hashlist_free(&list); + + fprintf(stdout, "OK %d/%d\n", ok, tot); + return EXIT_SUCCESS; +} + +void hashlist_init(hashlist_t* hlist) +{ + hlist->fill = 0; + hlist->size = 10; + hlist->data = g_new0(gchar*, hlist->size); + hlist->mark = g_new0(gboolean, hlist->size); + hlist->added = (const gchar**)hlist->data; + hlist->removed = (const gchar**)hlist->data + hlist->size - 1; +} + +void hashlist_clear(hashlist_t* hlist) +{ + gsize i, a, r; + for (a = hlist->added - (const gchar**)hlist->data; hlist->data[a]; ++a); + r = hlist->removed - (const gchar**)hlist->data; + for (i = 0; i < a; ++i) + { + g_free(hlist->data[i]); + } + for (i = r; hlist->data[i]; ++i) + { + g_free(hlist->data[i]); + } + hlist->data[0] = NULL; + hlist->fill = 0; + hlist->added = (const gchar**)hlist->data; + hlist->removed = (const gchar**)hlist->data + hlist->size - 1; +} + +void hashlist_free(hashlist_t* hlist) +{ + hashlist_clear(hlist); + g_free(hlist->data); + g_free(hlist->mark); +} + +gboolean hashlist_resize(hashlist_t* hlist, gsize* a, gsize* r) +{ + gsize ns = hlist->size * 2; + gchar** tmp; + g_assert(*r == hlist->size - 1); + if (ns < 10) ns = 10; + tmp = realloc(hlist->data, ns * sizeof(gchar**)); + if (tmp == NULL) + { + hlist->added = (const gchar**)hlist->data + hlist->fill; + hlist->removed = (const gchar**)hlist->data + *r; + return FALSE; + } + memset(tmp + hlist->size, 0, (ns - hlist->size) * sizeof(gchar*)); + hlist->data = tmp; + hlist->size = ns; + *r = hlist->size - 1; + return TRUE; +} + +gboolean hashlist_sync(hashlist_t* hlist, const gchar** list, gsize count) +{ + gsize i, j, a, r; + gsize found = 0; + g_assert((const gchar**)hlist->data + hlist->fill == hlist->added); + for (a = hlist->added - (const gchar**)hlist->data; hlist->data[a]; ++a); + hlist->fill = a; + hlist->added = (const gchar**)hlist->data + a; + for (r = hlist->removed - (const gchar**)hlist->data; hlist->data[r]; ++r) + { + g_free(hlist->data[r]); + } + g_assert(r == hlist->size - 1); + if (a + 5 > r) + { + gsize ns = a + 10; + gchar** tmp = realloc(hlist->data, ns * sizeof(gchar*)); + if (tmp != NULL) + { + hlist->data = tmp; + memset(hlist->data + hlist->size, 0, + (ns - hlist->size) * sizeof(gchar*)); + hlist->size = ns; + r = hlist->size - 1; + } + } + memset(hlist->mark, 0, hlist->fill * sizeof(gboolean)); + for (i = 0; i < count; ++i) + { + const gchar* hash = list[i]; + if (found == hlist->fill) + { + if (a + 1 == r && + !hashlist_resize(hlist, &a, &r)) + { + return FALSE; + } + hlist->data[a++] = g_strdup(hash); + continue; + } + /* Quick path */ + if (i < hlist->fill && !hlist->mark[i] && + strcmp(hlist->data[i], hash) == 0) + { + hlist->mark[i] = TRUE; + found++; + continue; + } + for (j = i + 1; j != i; ++j) + { + if (j >= hlist->fill) + { + j = 0; + if (i == 0) + { + break; + } + } + if (hlist->mark[j]) + { + continue; + } + if (strcmp(hlist->data[j], hash) == 0) + { + break; + } + } + if (j != i) + { + hlist->mark[j] = TRUE; + found++; + } + else + { + /* New */ + if (a + 1 == r && + !hashlist_resize(hlist, &a, &r)) + { + return FALSE; + } + hlist->data[a++] = g_strdup(hash); + } + } + if (found < hlist->fill) + { + gsize n = hlist->fill - found; + for (j = hlist->fill - 1; n > 0; --j) + { + if (!hlist->mark[j]) + { + hlist->data[--r] = hlist->data[j]; + a--; + hlist->fill--; + memmove(hlist->data + j, hlist->data + j + 1, + (a - j) * sizeof(gchar*)); + hlist->data[a] = NULL; + n--; + } + } + } + hlist->added = (const gchar**)hlist->data + hlist->fill; + hlist->removed = (const gchar**)hlist->data + r; + return TRUE; +} + +gboolean check(const gchar* name, hashlist_t* hlist, ...) +{ + va_list args; + const gchar* x, **a, **r; + va_start(args, hlist); + a = hlist->added; + while ((x = va_arg(args, const gchar*)) != NULL) + { + if (*a == NULL) + { + fprintf(stderr, "%s: Expected added `%s` got EOL\n", + name, x); + return FALSE; + } + if (strcmp(*a, x) != 0) + { + fprintf(stderr, "%s: Expected added `%s` got `%s`\n", name, x, *a); + return FALSE; + } + ++a; + } + if (*a != NULL) + { + fprintf(stderr, "%s: Expected added EOL got `%s`\n", + name, *a); + return FALSE; + } + r = hlist->removed; + while ((x = va_arg(args, const gchar*)) != NULL) + { + if (*r == NULL) + { + fprintf(stderr, "%s: Expected removed `%s` got EOL\n", + name, x); + return FALSE; + } + if (strcmp(*r, x) != 0) + { + fprintf(stderr, "%s: Expected removed `%s` got `%s`\n", + name, x, *r); + return FALSE; + } + ++r; + } + va_end(args); + if (*r != NULL) + { + fprintf(stderr, "%s: Expected removed EOL got `%s`\n", + name, *r); + return FALSE; + } + return TRUE; +} |
