
/*
 *  $Id: util_Inter.c,v 1.2 2002/09/30 16:21:18 czo Exp $
 *
 *  /----------------------------------------------------------------\
 *  |                                                                |
 *  |        A l l i a n c e   C A D   S y s t e m                   |
 *  |  S i l i c o n   E n s e m b l e / A l l i a n c e             |
 *  |                                                                |
 *  |  Author    :                      Jean-Paul CHAPUT             |
 *  |  E-mail    :         alliance-users@asim.lip6.fr             |
 *  | ============================================================== |
 *  |  C Module  :         "./util_Inter.c"                          |
 *  | ************************************************************** |
 *  |  U p d a t e s                                                 |
 *  |                                                                |
 *  \----------------------------------------------------------------/
 */


# include  "util_Defs.h"
# include  "debugoff.h"



/*  ------------------------------------------------------------------
 *  Local constants.
 */

# define        SHIFT_MAX            8
# define        F_MIN_IN             0x00000001
# define        F_MIN_LOWER          0x00000002
# define        F_MIN_GREATER        0x00000004
# define        F_MAX_IN            ((F_MIN_IN)      << SHIFT_MAX)
# define        F_MAX_LOWER         ((F_MIN_LOWER)   << SHIFT_MAX)
# define        F_MAX_GREATER       ((F_MIN_GREATER) << SHIFT_MAX)
# define        C_INTER_LOWER       (F_MIN_LOWER   | F_MAX_LOWER  )
# define        C_INTER_CROSS_MIN   (F_MIN_LOWER   | F_MAX_IN     )
# define        C_INTER_IN          (F_MIN_IN      | F_MAX_IN     )
# define        C_INTER_CROSS_MAX   (F_MIN_IN      | F_MAX_GREATER)
# define        C_INTER_GREATER     (F_MIN_GREATER | F_MAX_GREATER)
# define        C_INTER_OUT         (F_MIN_LOWER   | F_MAX_GREATER)


# define        INBOUNDS_INTER(i,v)  (inbounds ((i)->min, (i)->max, (v)))


/*  ------------------------------------------------------------------
 *  Local functions declarations.
 */

static long             inbounds    __FP((long aMin, long aMax, long aValue));
static struct eInter_s *alloceinter __FP((long aMin, long aMax));
static            void  freeeinter  __FP((struct eInter_s *apInter));
static            long  cmpeinter   __FP((struct eInter_s *apInterA,
                                          struct eInter_s *apInterB));



/*
 *  /----------------------------------------------------------------\
 *  |                   Functions Definitions                        |
 *  \----------------------------------------------------------------/
 */

/*  ------------------------------------------------------------------
 *  Function  :  "inbounds()".
 */

static long  inbounds (aMin, aMax, aValue)
  long aMin, aMax, aValue;
{
  if ((aValue >= aMin) && (aValue <= aMax)) return (F_MIN_IN);

  if (aValue < aMin) return (F_MIN_LOWER);

  return (F_MIN_GREATER);
}


/*  ------------------------------------------------------------------
 *  Function  :  "alloceinter()".
 */

static struct eInter_s *alloceinter (aMin, aMax)
  long  aMin, aMax;
{
  struct eInter_s *newInter;


  if (!(newInter = (struct eInter_s*)mbkalloc(sizeof (struct eInter_s)))) {
    eprinth ("util_Inter.c");
    eprintf ("Not enough memory to allcate an interval element.\n");
    EXIT (1);
  }

  newInter->min  = aMin;
  newInter->max  = aMax;
  newInter->next = NULL;

  return (newInter);
}


/*  ------------------------------------------------------------------
 *  Function  :  "freeeinter()".
 */

static void  freeeinter (apInter)
  struct eInter_s *apInter;
{
  mbkfree ((void*)apInter);
}


/*  ------------------------------------------------------------------
 *  Function  :  "cmpeinter()".
 */

static long  cmpeinter (apInterA, apInterB)
  struct eInter_s *apInterA, *apInterB;
{
  long  state;


  state  = INBOUNDS_INTER(apInterA, apInterB->min);
  state |= INBOUNDS_INTER(apInterA, apInterB->max) << SHIFT_MAX;

  return (state);
}


/*  ------------------------------------------------------------------
 *  Function  :  "allocinter()".
 */

static struct lInter_s *allocinter ()
{
  struct lInter_s *newInter;


  if (!(newInter = (struct lInter_s*)mbkalloc(sizeof (struct lInter_s)))) {
    eprinth ("util_Inter.c");
    eprintf ("Not enough memory to allocate an interval object.\n");
    EXIT (1);
  }

  newInter->min  = 0;
  newInter->max  = 0;
  newInter->len  = 0;
  newInter->l    = NULL;

  return (newInter);
}


/*  ------------------------------------------------------------------
 *  Function  :  "printinter()".
 */

extern void  printinter (apInter)
  struct lInter_s *apInter;
{
  struct eInter_s *pInter;


  fflush (stderr);
  fprintf (stdout, "  o  Interval set : (min = %ld, max = %ld, len = %ld)\n",
           apInter->min,
           apInter->max,
           apInter->len);
  fflush (stdout);

  for (pInter = apInter->l; pInter != NULL; pInter = pInter->next) {
    fprintf (stdout, "     [%6ld,%6ld]\n", pInter->min, pInter->max);
    fflush (stdout);
  }
}


/*  ------------------------------------------------------------------
 *  Function  :  "addinter()".
 */

extern struct lInter_s *addinter (apInter, aMin, aMax)
  struct lInter_s *apInter;
             long  aMin;
             long  aMax;
{
  struct eInter_s  *currInter;
  struct eInter_s  *newInter;
  struct eInter_s   mergeInter;
  struct eInter_s **ppInter;


  /* Case of the first interval. */
  if (apInter == NULL) apInter = allocinter  ();


  /* Update the interval list bounds. */
  apInter->max = m_Max(apInter->max, aMax);
  apInter->min = m_Min(apInter->min, aMin);


  mergeInter.min = aMin;
  mergeInter.max = aMax;
  newInter = NULL;
  ppInter  = &(apInter->l);


  for (; *ppInter != NULL;) {
    switch (cmpeinter (&mergeInter, *ppInter)) {
      case C_INTER_LOWER: break;
      case C_INTER_OUT:   break;

      case C_INTER_CROSS_MIN:
        (*ppInter)->max = mergeInter.max;
        newInter        = *ppInter;
        break;

      case C_INTER_IN:
        if (!newInter) {
          (*ppInter)->min = mergeInter.min;
          (*ppInter)->max = mergeInter.max;
          newInter        = *ppInter;
        } else {
          currInter = *ppInter;
          *ppInter  = (*ppInter)->next;
          freeeinter (currInter);
          apInter->len -= 1;
          continue;
        }
        break;

      case C_INTER_CROSS_MAX:
        if (!newInter) {
          (*ppInter)->min = mergeInter.min;
          newInter        = *ppInter;
        } else {
          newInter->max  = (*ppInter)->max;
          mergeInter.max = (*ppInter)->max;

          currInter = *ppInter;
          *ppInter  = (*ppInter)->next;
          freeeinter (currInter);
          apInter->len -= 1;
          continue;
        }
        break;

      case C_INTER_GREATER:
        if (!newInter) {
          newInter       = alloceinter (mergeInter.min, mergeInter.max);
          newInter->next = *ppInter;
          *ppInter       = newInter;
          apInter->len  += 1;
        }
        break;
    }

    ppInter  = &((*ppInter)->next);
  }


  /* Tail of first added interval. */
  if (!newInter) {
    *ppInter      = alloceinter (aMin, aMax);
    apInter->len += 1;
  }


  return (apInter);
}


/*  ------------------------------------------------------------------
 *  Function  :  "freeinter()".
 */

extern void  freeinter (apInter)
  struct lInter_s *apInter;
{
  struct eInter_s *pNextInter;
  struct eInter_s *pInter;


  for (pInter = apInter->l; pInter != NULL; ) {
    pNextInter = pInter->next;

    freeeinter (pInter);

    pInter = pNextInter;
  }

  mbkfree ((void*)apInter);
}
