/*
 * Copyright (c) 2002, 2003 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: ring.h,v 1.6 2005/06/16 00:09:34 ca Exp $
 */

#ifndef SM_RING_H
#define SM_RING_H 1

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

#ifndef SM_RING_INLINE
# define SM_RING_INLINE	0
#endif

/*
**  A ring is embedded in a structure (see SM_RING_EMBED)
**  and is a "circular queue" without a head.
*/

typedef struct sm_ring_S	sm_ring_T, *sm_ring_P;

struct sm_ring_S
{
	sm_ring_P	sm_rg_succ;
	sm_ring_P	sm_rg_pred;
};

void sm_ring_init(sm_ring_P _ring);
void sm_ring_prepend(sm_ring_P _ring1, sm_ring_P _ring2);
void sm_ring_append(sm_ring_P _ring1, sm_ring_P _ring2);

#define SM_RING_INIT(ring)	\
	do {			\
		(ring)->sm_rg_pred = (ring)->sm_rg_succ = (ring);	\
	} while (0)

#define SM_RING_APPEND(ring, entry)	\
	do {				\
		(entry)->sm_rg_succ = (ring)->sm_rg_succ;	\
		(entry)->sm_rg_pred = (ring);			\
		(ring)->sm_rg_succ->sm_rg_pred = (entry);	\
		(ring)->sm_rg_succ = (entry);			\
	} while (0)

#define SM_RING_PREPEND(ring, entry)	\
	do {				\
		(entry)->sm_rg_pred = (ring)->sm_rg_pred;	\
		(entry)->sm_rg_succ = (ring);			\
		(ring)->sm_rg_pred->sm_rg_succ = (entry);	\
		(ring)->sm_rg_pred = (entry);			\
	} while (0)

void sm_ring_delentry(sm_ring_P);

#define sm_ring_succ(c) ((c)->sm_rg_succ)
#define sm_ring_pred(c) ((c)->sm_rg_pred)

#define SM_RING_EMBED(ring_p, struct_S, ring_member) \
    ((struct_S *) (((char *) (ring_p)) - offsetof(struct_S, ring_member)))

#if 0

Example how to use a ring:

get the (address of the) ring in the structure:
#define STRUCT_LINK2R(struct)	(&((struct)->struct_link))

get from the ring to the structure:
#define STRUCT_R2LINK(ring)	SM_RING_EMBED((ring), struct, struct_link)

define structure specific macros for ring operations by applying
the two macros defined above:
#define STRUCT_LINK_INIT(struct)	SM_RING_INIT(STRUCT_LINK2R(struct))
#define STRUCT_LINK_APP(struct, struct_nxt)	SM_RING_APPEND(STRUCT_LINK2R(struct), STRUCT_LINK2R(struct_nxt))
#define STRUCT_LINK_PRE(struct, struct_nxt)	SM_RING_PREPEND(STRUCT_LINK2R(struct), STRUCT_LINK2R(struct_nxt))
#define STRUCT_LINK_SUCC(struct)	STRUCT_R2LINK(sm_ring_succ(STRUCT_LINK2R(struct)))
#define STRUCT_LINK_PRED(struct)	STRUCT_R2LINK(sm_ring_pred(STRUCT_LINK2R(struct)))
#define STRUCT_LINK_DELENTRY(struct)	sm_ring_delentry(STRUCT_LINK2R(struct))

#endif /* 0 */

#endif /* SM_RING_H */


syntax highlighted by Code2HTML, v. 0.9.1