/*
 * Copyright (c) 2002 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-ring.c,v 1.8 2002/12/13 18:43:06 ca Exp $")

#include "sm/assert.h"
#include "sm/test.h"
#include "sm/ring.h"

#include <stdio.h>
#include <sys/time.h>
#define toseconds(x, y)	(x.tv_sec - y.tv_sec)

static void
test_harness(void)
{
	sm_ring_T r1, r2, r3, *r;
	int c;

	sm_ring_init(&r1);
	SM_TEST(sm_ring_succ(&r1) == &r1);
	SM_TEST(sm_ring_pred(&r1) == &r1);
	sm_ring_append(&r1, &r2);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r2);
	SM_TEST(sm_ring_succ(&r2) == &r1);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	sm_ring_prepend(&r1, &r3);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r3);
	SM_TEST(sm_ring_succ(&r2) == &r3);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	SM_TEST(sm_ring_succ(&r3) == &r1);
	SM_TEST(sm_ring_pred(&r3) == &r2);

	r = &r1;
	c = 0;
	do
	{
		r = sm_ring_succ(r);
		++c;
	} while (r != &r1 && c < 10);
	SM_TEST(c == 3);

	sm_ring_delentry(&r3);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r2);
	SM_TEST(sm_ring_succ(&r2) == &r1);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	sm_ring_delentry(&r1);
	SM_TEST(sm_ring_succ(&r2) == &r2);
	SM_TEST(sm_ring_pred(&r2) == &r2);
}

static void
test_del(void)
{
	sm_ring_T r1, r2, r3, *r, *rn;

	sm_ring_init(&r1);
	SM_TEST(sm_ring_succ(&r1) == &r1);
	SM_TEST(sm_ring_pred(&r1) == &r1);
	sm_ring_append(&r1, &r2);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r2);
	SM_TEST(sm_ring_succ(&r2) == &r1);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	sm_ring_prepend(&r1, &r3);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r3);
	SM_TEST(sm_ring_succ(&r2) == &r3);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	SM_TEST(sm_ring_succ(&r3) == &r1);
	SM_TEST(sm_ring_pred(&r3) == &r2);

	for (r = &r1; r != NULL; r = rn)
	{
		rn = sm_ring_succ(r);
		if (rn == r)
			rn = NULL;
		sm_ring_delentry(r);
	}
	SM_TEST(sm_ring_succ(&r1) == NULL);
	SM_TEST(sm_ring_pred(&r1) == NULL);
	SM_TEST(sm_ring_succ(&r2) == NULL);
	SM_TEST(sm_ring_pred(&r2) == NULL);
	SM_TEST(sm_ring_succ(&r3) == NULL);
	SM_TEST(sm_ring_pred(&r3) == NULL);
}

static void
test_inline(void)
{
	sm_ring_T r1, r2, r3;

	SM_RING_INIT(&r1);
	SM_TEST(sm_ring_succ(&r1) == &r1);
	SM_TEST(sm_ring_pred(&r1) == &r1);
	SM_RING_APPEND(&r1, &r2);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r2);
	SM_TEST(sm_ring_succ(&r2) == &r1);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	SM_RING_PREPEND(&r1, &r3);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r3);
	SM_TEST(sm_ring_succ(&r2) == &r3);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	SM_TEST(sm_ring_succ(&r3) == &r1);
	SM_TEST(sm_ring_pred(&r3) == &r2);
	sm_ring_delentry(&r3);
	SM_TEST(sm_ring_succ(&r1) == &r2);
	SM_TEST(sm_ring_pred(&r1) == &r2);
	SM_TEST(sm_ring_succ(&r2) == &r1);
	SM_TEST(sm_ring_pred(&r2) == &r1);
	sm_ring_delentry(&r1);
	SM_TEST(sm_ring_succ(&r2) == &r2);
	SM_TEST(sm_ring_pred(&r2) == &r2);
}

struct appl_S
{
	int		a_key;
	int		a_value;
	sm_ring_T	a_ring;
};

typedef struct appl_S	appl_T;

#define SM_A_R(a)		(&((a).a_ring))
#define SM_R_A(r)		SM_RING_EMBED((r), appl_T, a_ring)
#define SM_APPL_R_INIT(a)	SM_RING_INIT(SM_A_R(a))
#define SM_APPL_R_APP(a, e)	SM_RING_APPEND(SM_A_R(a), SM_A_R(e))
#define SM_APPL_R_PRE(a, e)	SM_RING_PREPEND(SM_A_R(a), SM_A_R(e))
#define sm_appl_r_succ(a)	sm_ring_succ(SM_A_R(a))
#define sm_appl_r_pred(a)	sm_ring_pred(SM_A_R(a))

static void
test_appl(void)
{
	appl_T a1, a2, a3;

	a1.a_key = 1;
	a2.a_key = 2;
	a3.a_key = 3;
	a1.a_value = 11;
	a2.a_value = 22;
	a3.a_value = 33;
	SM_APPL_R_INIT(a1);
	SM_TEST(sm_appl_r_succ(a1) == SM_A_R(a1));
	SM_TEST(sm_appl_r_pred(a1) == SM_A_R(a1));

	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_value = 11);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_value = 11);

	SM_APPL_R_APP(a1, a2);
	SM_TEST(sm_appl_r_succ(a1) == SM_A_R(a2));
	SM_TEST(sm_appl_r_pred(a1) == SM_A_R(a2));
	SM_TEST(sm_appl_r_succ(a2) == SM_A_R(a1));
	SM_TEST(sm_appl_r_pred(a2) == SM_A_R(a1));

	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_value = 22);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_value = 22);

	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_value = 11);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_value = 11);

	SM_APPL_R_PRE(a1, a3);
	SM_TEST(sm_ring_succ(SM_A_R(a1)) == SM_A_R(a2));
	SM_TEST(sm_ring_pred(SM_A_R(a1)) == SM_A_R(a3));
	SM_TEST(sm_ring_succ(SM_A_R(a2)) == SM_A_R(a3));
	SM_TEST(sm_ring_pred(SM_A_R(a2)) == SM_A_R(a1));
	SM_TEST(sm_ring_succ(SM_A_R(a3)) == SM_A_R(a1));
	SM_TEST(sm_ring_pred(SM_A_R(a3)) == SM_A_R(a2));

	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_value = 22);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_key = 3);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_value = 33);

	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_value = 22);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_value = 11);

	SM_TEST(SM_R_A(sm_appl_r_succ(a3))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_succ(a3))->a_value = 11);
	SM_TEST(SM_R_A(sm_appl_r_pred(a3))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_pred(a3))->a_value = 22);

	sm_ring_delentry(SM_A_R(a3));
	SM_TEST(sm_ring_succ(SM_A_R(a1)) == SM_A_R(a2));
	SM_TEST(sm_ring_pred(SM_A_R(a1)) == SM_A_R(a2));
	SM_TEST(sm_ring_succ(SM_A_R(a2)) == SM_A_R(a1));
	SM_TEST(sm_ring_pred(SM_A_R(a2)) == SM_A_R(a1));

	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_succ(a1))->a_value = 22);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_pred(a1))->a_value = 22);

	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_value = 11);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_key = 1);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_value = 11);

	sm_ring_delentry(SM_A_R(a1));
	SM_TEST(sm_ring_succ(SM_A_R(a2)) == SM_A_R(a2));
	SM_TEST(sm_ring_pred(SM_A_R(a2)) == SM_A_R(a2));

	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_succ(a2))->a_value = 22);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_key = 2);
	SM_TEST(SM_R_A(sm_appl_r_pred(a2))->a_value = 22);
}

struct appl2_S
{
	int		a2_key;
	int		a2_value;
	sm_ring_T	a2_ring;
};

typedef struct appl2_S	appl2_T;

#define SM_A2_R(a)		(&((a).a2_ring))
#define SM_R_A2(r)		SM_RING_EMBED((r), appl2_T, a2_ring)
#define SM_A2_R_INIT(a)		SM_RING_INIT(SM_A2_R(a))
#define SM_A2_R_APP(a, e)	SM_RING_APPEND(SM_A2_R(a), SM_A2_R(e))
#define SM_A2_R_PRE(a, e)	SM_RING_PREPEND(SM_A2_R(a), SM_A2_R(e))
#define sm_a2_r_succ(a)	SM_R_A2(sm_ring_succ(SM_A2_R(a)))
#define sm_a2_r_pred(a)	SM_R_A2(sm_ring_pred(SM_A2_R(a)))
#define sm_a2_r_delentry(a)	sm_ring_delentry(SM_A2_R(a))

static void
test_appl2(void)
{
	appl2_T a1, a2, a3;

	a1.a2_key = 1;
	a2.a2_key = 2;
	a3.a2_key = 3;
	a1.a2_value = 11;
	a2.a2_value = 22;
	a3.a2_value = 33;
	SM_A2_R_INIT(a1);
	SM_TEST(sm_a2_r_succ(a1)->a2_key = 1);
	SM_TEST(sm_a2_r_succ(a1)->a2_value = 11);
	SM_TEST(sm_a2_r_pred(a1)->a2_key = 1);
	SM_TEST(sm_a2_r_pred(a1)->a2_value = 11);

	SM_A2_R_APP(a1, a2);

	SM_TEST(sm_a2_r_succ(a1)->a2_key = 2);
	SM_TEST(sm_a2_r_succ(a1)->a2_value = 22);
	SM_TEST(sm_a2_r_pred(a1)->a2_key = 2);
	SM_TEST(sm_a2_r_pred(a1)->a2_value = 22);

	SM_TEST(sm_a2_r_succ(a2)->a2_key = 1);
	SM_TEST(sm_a2_r_succ(a2)->a2_value = 11);
	SM_TEST(sm_a2_r_pred(a2)->a2_key = 1);
	SM_TEST(sm_a2_r_pred(a2)->a2_value = 11);

	SM_A2_R_PRE(a1, a3);

	SM_TEST(sm_a2_r_succ(a1)->a2_key = 2);
	SM_TEST(sm_a2_r_succ(a1)->a2_value = 22);
	SM_TEST(sm_a2_r_pred(a1)->a2_key = 3);
	SM_TEST(sm_a2_r_pred(a1)->a2_value = 33);

	SM_TEST(sm_a2_r_succ(a2)->a2_key = 2);
	SM_TEST(sm_a2_r_succ(a2)->a2_value = 22);
	SM_TEST(sm_a2_r_pred(a2)->a2_key = 1);
	SM_TEST(sm_a2_r_pred(a2)->a2_value = 11);

	SM_TEST(sm_a2_r_succ(a3)->a2_key = 1);
	SM_TEST(sm_a2_r_succ(a3)->a2_value = 11);
	SM_TEST(sm_a2_r_pred(a3)->a2_key = 2);
	SM_TEST(sm_a2_r_pred(a3)->a2_value = 22);

	sm_a2_r_delentry(a3);

	SM_TEST(sm_a2_r_succ(a1)->a2_key = 2);
	SM_TEST(sm_a2_r_succ(a1)->a2_value = 22);
	SM_TEST(sm_a2_r_pred(a1)->a2_key = 2);
	SM_TEST(sm_a2_r_pred(a1)->a2_value = 22);

	SM_TEST(sm_a2_r_succ(a2)->a2_key = 1);
	SM_TEST(sm_a2_r_succ(a2)->a2_value = 11);
	SM_TEST(sm_a2_r_pred(a2)->a2_key = 1);
	SM_TEST(sm_a2_r_pred(a2)->a2_value = 11);

	sm_a2_r_delentry(a1);

	SM_TEST(sm_a2_r_succ(a2)->a2_key = 2);
	SM_TEST(sm_a2_r_succ(a2)->a2_value = 22);
	SM_TEST(sm_a2_r_pred(a2)->a2_key = 2);
	SM_TEST(sm_a2_r_pred(a2)->a2_value = 22);

	sm_a2_r_delentry(a2);
}

int
main(int argc, char *argv[])
{
	int i, cnt;

	sm_test_begin(argc, argv, "test rings");
	if (argc > 1)
	{
		struct timeval t1, t2;

		cnt = atoi(argv[1]);
		if (gettimeofday(&t1, NULL) < 0)
			perror("gettimeofday");
		for (i = 0; i < cnt; i++)
			test_harness();
		if (gettimeofday(&t2, NULL) < 0)
			perror("gettimeofday");
		printf("function time: %ld seconds\n",
			toseconds(t2, t1));
		if (gettimeofday(&t1, NULL) < 0)
			perror("gettimeofday");
		for (i = 0; i < cnt; i++)
			test_inline();
		if (gettimeofday(&t2, NULL) < 0)
			perror("gettimeofday");
		printf("inline time: %ld seconds\n",
			toseconds(t2, t1));

	}
	else
	{
		test_del();
		test_harness();
		test_inline();
		test_appl();
		test_appl2();
	}
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1