/*
 * Copyright (c) 2002-2004 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-sortq.c,v 1.10 2004/12/29 23:47:29 ca Exp $")

#include "sm/assert.h"
#include "sm/error.h"
#include "sm/time.h"
#include "sm/heap.h"
#include "sm/test.h"
#include "sm/queue.h"

#include <stdio.h>

#define ELEMS	1024
#define ITER	100

static int elems = ELEMS;
static int Verbose = 0;

struct cq_entry
{
	int			item;
	int			which;
	CIRCLEQ_ENTRY(cq_entry)	entries;
};

CIRCLEQ_HEAD(cq, cq_entry) cq_head;

typedef struct cq_entry cq_entry_T;
typedef struct cq cq_T;

#define WH_UNSORTED	0
#define WH_SORTED	1

static sm_ret_T
ins(cq_T *hd, cq_entry_T *entry)
{
	cq_entry_T *lp;

	CIRCLEQ_FOREACH(lp, hd, entries)
	{
		if (lp->item > entry->item)
		{
			CIRCLEQ_INSERT_BEFORE(hd, lp, entry, entries);
			return SM_SUCCESS;
		}
	}
	CIRCLEQ_INSERT_TAIL(hd, entry, entries);
	return SM_SUCCESS;
}


static sm_ret_T
chk(cq_T *hd, int cnt)
{
	cq_entry_T *lp;
	int i, prev;

	prev = -1;
	i = 0;
	CIRCLEQ_FOREACH(lp, hd, entries)
	{
		if (prev > lp->item)
		{
			return SM_FAILURE;
		}
		prev = lp->item;
		++i;
	}
	if (i != cnt)
	{
		return SM_FAILURE;
	}
	return SM_SUCCESS;
}


static void
test_cq(int iter)
{
	int i, j;
	cq_T head;
	cq_entry_T *cqe;
	sm_ret_T ret;

	cqe = (cq_entry_T *) sm_malloc(elems * sizeof(*cqe));
	SM_TEST(cqe != NULL);
	if (cqe == NULL)
		return;

	srand((uint) cqe + iter);
	for (j = 0; j < iter; j++)
	{
		CIRCLEQ_INIT(&head);
		SM_TEST(CIRCLEQ_EMPTY(&head));
		for (i = 0; i < elems; i++)
			cqe[i].item = (int) rand();

		for (i = 0; i < elems; i++)
		{
			ret = ins(&head, &(cqe[i]));
			SM_TEST(ret == SM_SUCCESS);
			ret = chk(&head, i + 1);
			SM_TEST(ret == SM_SUCCESS);
		}
	}
	sm_free(cqe);
}

static sm_ret_T
ins2(cq_T *hd, cq_entry_T *entry)
{
	cq_entry_T *lp;

	CIRCLEQ_FOREACH(lp, hd, entries)
	{
		if (lp->which != WH_SORTED || lp->item > entry->item)
		{
			CIRCLEQ_INSERT_BEFORE(hd, lp, entry, entries);
			return SM_SUCCESS;
		}
	}
	CIRCLEQ_INSERT_TAIL(hd, entry, entries);
	return SM_SUCCESS;
}

static sm_ret_T
chk2(cq_T *hd, int cnt)
{
	cq_entry_T *lp;
	int i, prev;

	prev = -1;
	i = 0;
	CIRCLEQ_FOREACH(lp, hd, entries)
	{
		if (Verbose > 0)
			printf("%4d: %10d (%d)\n", i, lp->item, lp->which);
		if (lp->which == WH_SORTED)
		{
			if (prev > lp->item)
				return SM_FAILURE;
			prev = lp->item;
			++i;
		}
		else
			break;
	}
	if (i != cnt)
	{
		if (Verbose > 1)
			printf("i=%d, cnt=%d\n", i, cnt);
		return SM_FAILURE;
	}
	return SM_SUCCESS;
}

static void
test_cq2(int iter)
{
	int i, j, r, items;
	cq_T head;
	cq_entry_T *cqe;
	sm_ret_T ret;
	struct timeval now;

	cqe = (cq_entry_T *) sm_malloc(elems * sizeof(*cqe));
	SM_TEST(cqe != NULL);
	if (cqe == NULL)
		return;

	i = gettimeofday(&now, NULL);
	srand((uint) cqe + iter + now.tv_usec);
	for (j = 0; j < iter; j++)
	{
		CIRCLEQ_INIT(&head);
		SM_TEST(CIRCLEQ_EMPTY(&head));
		for (i = 0; i < elems; i++)
		{
			cqe[i].item = (int) rand();
			r = (int) rand();
			cqe[i].which = (r & 0x10) ? WH_UNSORTED : WH_SORTED;
			if (Verbose > 2)
				printf("%4d: %10d (%d) %d\n", i, cqe[i].item, cqe[i].which, j);
		}
		for (i = 0; i < elems; i++)
		{
			if (cqe[i].which == WH_UNSORTED)
			{
				CIRCLEQ_INSERT_TAIL(&head, &(cqe[i]), entries);
			}
		}

		items = 0;
		for (i = 0; i < elems; i++)
		{
			if (cqe[i].which == WH_SORTED)
			{
				ret = ins2(&head, &(cqe[i]));
				SM_TEST(ret == SM_SUCCESS);
				++items;
				ret = chk2(&head, items);
				SM_TEST(ret == SM_SUCCESS);
			}
		}
	}
	sm_free(cqe);
}


int
main(int argc, char *argv[])
{
	int c, iter;

	iter = ITER;
	while ((c = getopt(argc, argv, "e:l:V")) != -1)
	{
		switch (c)
		{
		  case 'e':
			elems = atoi(optarg);
			break;
		  case 'l':
			iter = atoi(optarg);
			break;
		  case 'V':
			Verbose++;
			break;
#if 0
		  default:
			usage(argv[0]);
			return(1);
#endif /* 0 */
		}
	}
	sm_test_begin(argc, argv, "test sorted queue");
	test_cq(iter);
	test_cq2(iter);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1