/*
* Copyright (c) 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: t-ringinsert.h,v 1.1 2004/09/10 18:53:13 ca Exp $
*/
/*
needs:
RING_CMP(el1, el2) function/macro to compare two ring elements
*/
/*
** RING_INSERT -- insert new elem into ring
**
** Parameters:
** elem -- previous element (may be NULL)
** new -- element to insert
**
** Returns:
** usual sm_error code
**
** Invariant:
** if not all elements in the ring are the same then there is
** exactly one element F for which: L=pred(F) > F ("First"/"Head"),
** (and succ(L)=F: L: Last, F: First)
** for all others E: pred <= E.
** for each element E:
** if E isn't the first nor the last: pred(E) <= E <= succ(E)
** if E is the first: pred(E) >= E <= succ(E)
** if E is the last: pred(E) <= E >= succ(E)
**
** Problem: there's no explicit head (or tail) of the "list"
** because it is a ring: X -> B -> D -> E -> X
** hence the code must be prepared to "walk" in any direction
** and stop when it reaches "First"/"Last", or when it comes
** back to the start.
*/
static sm_ret_T
ring_insert(sm_ring_P elem, sm_ring_P new)
{
int direction;
sm_ring_P nxt, cur;
if (elem == NULL)
{
SM_RING_INIT(new);
return SM_SUCCESS;
}
nxt = cur = elem;
direction = RING_CMP(new, nxt);
if (direction == 0)
{
SM_RING_APPEND(elem, new);
return SM_SUCCESS;
}
else if (direction < 0)
{
/*
** initial: new < nxt
** go to the "left" (pred)
** stop if new >= nxt (can't be on first round)
** found place to insert (append to nxt)
** stop if nxt > cur (L > F)
** this means new is less than every element in the ring
** and nxt is the largest element, hence new must be
** appended to nxt
** stop if elem is reached:
** this means new is less than every element in the ring
** and elem is the largest element, hence new must be
** appended to elem (= nxt)
*/
while ((nxt = sm_ring_pred(nxt)) != elem &&
!(RING_CMP(new, nxt) >= 0 || RING_CMP(nxt, cur) > 0))
{
cur = nxt;
}
SM_RING_APPEND(nxt, new);
}
else
{
/*
** initial: new > nxt
** go to the "right" (succ)
** stop if new <= nxt (can't be on first round)
** found place to insert (prepend to nxt)
** stop if nxt < cur (F > L)
** this means new is greater than every element in the ring
** and next is the smallest element, hence new must be
** prepended to nxt
** stop if elem is reached:
** this means new is greater than every element in the ring
** and elem is the smallest element, hence new must be
** prepended to elem (= nxt)
*/
while ((nxt = sm_ring_succ(nxt)) != elem &&
!(RING_CMP(new, nxt) <= 0 || RING_CMP(nxt, cur) < 0))
{
cur = nxt;
}
SM_RING_PREPEND(nxt, new);
}
return SM_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1