/* test.c
 * Some timing tests for libdict
 * Copyright (C) 2001-2004 Farooq Mela <fmela@uci.edu> */

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>

/* These includes renders this file non-ANSI */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>

#include "dict.h"

const char appname[] = "test";

char *xstrdup(const char *str);

#ifdef __GNUC__
# define NORETURN	__attribute__((__noreturn__))
#else
# define NORETURN
#endif
void quit(const char *, ...) NORETURN;
void *xmalloc(size_t size);
void *xcalloc(size_t size);
void *xrealloc(void *ptr, size_t size);
void *xdup(const void *ptr, size_t size);

unsigned s_hash(const unsigned char *p);
void shuffle(char **p, unsigned size);

unsigned
s_hash(const unsigned char *p)
{
	unsigned hash = 0;

	while (*p) {
		hash *= 31;
		hash += *p++;
	}
	return hash;
}

void
shuffle(char **p, unsigned size)
{
	unsigned i, n;
	char *t;

	for (i = 0; i < size - 1; i++) {
		n = rand() % (size - i);
		t = p[i+n]; p[i+n] = p[i]; p[i] = t;
	}
}

#define HSIZE		599

#define NWORDS	235881

static size_t malloced = 0;

int
main(int argc, char **argv)
{
	unsigned i;
	char buf[512], *ptr, *p;
	char *words[NWORDS];
	FILE *fp;
	int rv;
	dict *dct;
	struct rusage start, end;
	struct timeval total = { 0, 0 };

	if (argc != 3) {
		fprintf(stderr, "usage: %s [type] [input]\n", appname);
		exit(EXIT_FAILURE);
	}

	srand((unsigned)time(NULL));

	dict_set_malloc(xmalloc);

	++argv;
	switch (argv[0][0]) {
	case 'h':
		dct = hb_dict_new(dict_str_cmp, free, NULL);
		break;
	case 'p':
		dct = pr_dict_new(dict_str_cmp, free, NULL);
		break;
	case 'r':
		dct = rb_dict_new(dict_str_cmp, free, NULL);
		break;
	case 't':
		dct = tr_dict_new(dict_str_cmp, free, NULL);
		break;
	case 's':
		dct = sp_dict_new(dict_str_cmp, free, NULL);
		break;
	case 'w':
		dct = wb_dict_new(dict_str_cmp, free, NULL);
		break;
	case 'H':
		dct = hashtable_dict_new(dict_str_cmp,
								 (dict_hsh_func)s_hash, free, NULL, HSIZE);
		break;
	default:
		quit("type must be one of h, p, r, t, s, w or H");
	}

	if (!dct)
		quit("can't create container");

	fp = fopen(argv[1], "r");
	if (fp == NULL)
		quit("cant open file `%s': %s", argv[1], strerror(errno));

	i = 0;
	for (i = 0; i < NWORDS && fgets(buf, sizeof(buf), fp); i++) {
		strtok(buf, "\n");
		words[i] = xstrdup(buf);
	}
	fclose(fp);

	malloced = 0;
	getrusage(RUSAGE_SELF, &start);
	for (i = 0; i < NWORDS; i++) {
		ptr = words[i];
		if ((rv = dict_insert(dct, ptr, ptr, 0)) != 0)
			quit("insert failed with %d for `%s'", rv, ptr);
	}
	getrusage(RUSAGE_SELF, &end);
	if (end.ru_utime.tv_usec < start.ru_utime.tv_usec)
		end.ru_utime.tv_usec += 1000000, end.ru_utime.tv_sec--;
	end.ru_utime.tv_usec -= start.ru_utime.tv_usec;
	end.ru_utime.tv_sec -= start.ru_utime.tv_sec;
	total.tv_sec += end.ru_utime.tv_sec;
	if ((total.tv_usec += end.ru_utime.tv_usec) > 1000000)
		total.tv_usec -= 1000000, total.tv_sec++;
	printf("insert = %02f s\n",
		   (end.ru_utime.tv_sec * 1000000 + end.ru_utime.tv_usec) / 1000000.0);
/*	printf("memory used = %u bytes\n", malloced); */

	if ((i = dict_count(dct)) != NWORDS)
		quit("bad count (%u)!", i);

	getrusage(RUSAGE_SELF, &start);
	for (i = 0; i < NWORDS; i++) {
		ptr = words[i];
		if ((p = dict_search(dct, ptr)) == NULL)
			quit("lookup failed for `%s'", buf);
		if (p != ptr)
			quit("bad data for `%s', got `%s' instead", ptr, p);
	}
	getrusage(RUSAGE_SELF, &end);
	if (end.ru_utime.tv_usec < start.ru_utime.tv_usec)
		end.ru_utime.tv_usec += 1000000, end.ru_utime.tv_sec--;
	end.ru_utime.tv_usec -= start.ru_utime.tv_usec;
	end.ru_utime.tv_sec -= start.ru_utime.tv_sec;
	total.tv_sec += end.ru_utime.tv_sec;
	if ((total.tv_usec += end.ru_utime.tv_usec) > 1000000)
		total.tv_usec -= 1000000, total.tv_sec++;
	printf("search = %02f s\n",
		   (end.ru_utime.tv_sec * 1000000 + end.ru_utime.tv_usec) / 1000000.0);

	getrusage(RUSAGE_SELF, &start);
	for (i = 0; i < NWORDS; i++) {
		ptr = words[i];
		if ((rv = dict_remove(dct, ptr, TRUE)) != 0)
			quit("removing `%s' failed (%d)!\n", ptr, rv);
	}
	getrusage(RUSAGE_SELF, &end);
	if (end.ru_utime.tv_usec < start.ru_utime.tv_usec)
		end.ru_utime.tv_usec += 1000000, end.ru_utime.tv_sec--;
	end.ru_utime.tv_usec -= start.ru_utime.tv_usec;
	end.ru_utime.tv_sec -= start.ru_utime.tv_sec;
	total.tv_sec += end.ru_utime.tv_sec;
	if ((total.tv_usec += end.ru_utime.tv_usec) > 1000000)
		total.tv_usec -= 1000000, total.tv_sec++;
	printf("remove = %02f s\n",
		   (end.ru_utime.tv_sec * 1000000 + end.ru_utime.tv_usec) / 1000000.0);

	if ((i = dict_count(dct)) != 0)
		quit("error - count not zero (%u)!", i);

	dict_destroy(dct, TRUE);

	printf(" total = %02f s\n",
		   (total.tv_sec * 1000000 + total.tv_usec) / 1000000.0);

	exit(EXIT_SUCCESS);
}

char *
xstrdup(const char *str)
{
	return xdup(str, strlen(str) + 1);
}

void
quit(const char *fmt, ...)
{
	va_list args;

	va_start(args, fmt);
	fprintf(stderr, "%s: ", appname);
	vfprintf(stderr, fmt, args);
	fprintf(stderr, "\n");
	va_end(args);

	exit(EXIT_FAILURE);
}

void *
xmalloc(size_t size)
{
	void *p;

	if ((p = malloc(size)) == NULL)
		quit("out of memory");
	malloced += size;
	return p;
}

void *
xcalloc(size_t size)
{
	void *p;

	p = xmalloc(size);
	memset(p, 0, size);
	return p;
}

void *
xrealloc(void *ptr, size_t size)
{
	void *p;

	if ((p = realloc(ptr, size)) == NULL && size != 0)
		quit("out of memory");
	return p;
}

void *
xdup(const void *ptr, size_t size)
{
	void *p;

	p = xmalloc(size);
	memcpy(p, ptr, size);
	return p;
}


syntax highlighted by Code2HTML, v. 0.9.1