/*
 * Copyright (c) 2003, 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.
 *
 *	$Id: ringhd.h,v 1.7 2006/12/26 23:43:36 ca Exp $
 */

#ifndef SM_RINGHD_H
#define SM_RINGHD_H 1

#include "sm/generic.h"
#include "sm/types.h"
#include "sm/assert.h"
#include "sm/ring.h"

/*
**  Define a ring with a head (see sm/ring.h about rings).
**  The head points to one element in a ring.
**  Special precautions must be taken:
**  - for append/prepend if the ring is empty (hd == NULL)
**  - for delete if the ring has only one element
**
**  hd: head of ring: pointer to a structure that has a ring embedded
**  entry: pointer to a structure that has a ring embedded
**  entry_ring: pointer to ring
**  ring_member: name of field that is the ring in structure
**
**  append(hd, entry) makes entry the last element in the list,
**	i.e., it prepend entry to the element that hd points to.
**  prepend(hd, entry) makes entry the first element in the list,
**	i.e., it prepend entry to the element that hd points to and
**	hd points afterwards to entry.
**
**  Note: it is possible to perform operations on the ring itself,
**  especially walking through the entries, and even adding entries.
**  However, deleting entries will cause problems if:
**  - the ring becomes empty
**  - the entry to which the head points is removed.
**  Be careful!
**
**  example:

struct entry_S {
	some		e_types;
	sm_ring_T	e_ring;
};

struct head_S {
	some	hd_types;
	entry_P	hd_entry;
};

entry_P entry;
head_P hd;

SM_RINGHD_INIT(hd->hd_entry);
SM_RINGHD_APPEND(hd, entry, e_ring);
SM_RINGHD_DELETE(hd, &(entry->e_ring));
*/

#ifndef SM_RINGHD_INLINE
# define SM_RINGHD_INLINE	0
#endif

#define SM_RINGHD_INIT(hd_entry)        (hd_entry) = NULLPTR

#define SM_RINGHD_APPEND(hd, entry, ring_member)           \
	do {                                                   \
	       if ((hd) == NULLPTR) {                          \
	               (hd) = (entry);                         \
	               SM_RING_INIT(&((entry)->ring_member));  \
	       }                                               \
	       else {                                          \
	               SM_RING_PREPEND(&((hd)->ring_member),   \
	                       &((entry)->ring_member));       \
	       }                                               \
	} while (0)

#define SM_RINGHD_PREPEND(hd, entry, ring_member)       \
	do {                                                   \
	       if ((hd) == NULLPTR) {                          \
	               SM_RING_INIT(&((entry)->ring_member));  \
	       }                                               \
	       else {                                          \
	               SM_RING_PREPEND(&((hd)->ring_member),   \
	                       &((entry)->ring_member));       \
	       }                                               \
	       (hd) = (entry);                                 \
	} while (0)

#define SM_RINGHD_DELENTRY(hd, entry_ring)                        \
	do {                                                          \
	       sm_ring_P succ, pred;                                  \
	                                                              \
	       SM_REQUIRE((hd) != NULLPTR);                           \
	       succ = (entry_ring)->sm_rg_succ;                       \
	       pred = (entry_ring)->sm_rg_pred;                       \
	       if ((succ == NULL && pred == NULL)                     \
	           || (succ == (entry_ring) && pred == (entry_ring))) \
	               (hd) = NULLPTR;                                \
	       else {                                                 \
	               pred->sm_rg_succ = succ;                       \
	               succ->sm_rg_pred = pred;                       \
	               (entry_ring)->sm_rg_succ =                     \
	               (entry_ring)->sm_rg_pred = NULL;               \
	       }                                                      \
	} while (0)

#endif /* SM_RINGHD_H */


syntax highlighted by Code2HTML, v. 0.9.1