/*--------------------------------------------------------------------------*/
/* ALBERTA_UTIL:  tools for messages, memory allocation, parameters, etc.   */
/*                                                                          */
/* file: alberta_util_inline.h                                              */
/*                                                                          */
/* description: header for inline functions of the ALBERTA_UTIL package     */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  authors:   Alfred Schmidt                                               */
/*             Zentrum fuer Technomathematik                                */
/*             Fachbereich 3 Mathematik/Informatik                          */
/*             Universitaet Bremen                                          */
/*             Bibliothekstr. 2                                             */
/*             D-28359 Bremen, Germany                                      */
/*                                                                          */
/*             Kunibert G. Siebert                                          */
/*             Institut fuer Mathematik                                     */
/*             Universitaet Augsburg                                        */
/*             Universitaetsstr. 14                                         */
/*             D-86159 Augsburg, Germany                                    */
/*                                                                          */
/*             Claus-Justus Heine                                           */
/*             Abteilung fuer Angewandte Mathematik                         */
/*             Albert-Ludwigs-Universitaet Freiburg                         */
/*             Hermann-Herder-Str. 10                                       */
/*             D-79104 Freiburg im Breisgau, Germany                        */
/*                                                                          */
/*  http://www.mathematik.uni-freiburg.de/IAM/ALBERTA                       */
/*                                                                          */
/*  (c) by A. Schmidt and K.G. Siebert (1996-2003),                         */
/*         C.-J. Heine (2007-2008)                                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/

#ifndef _ALBERTA_UTIL_INLINES_H_
#define _ALBERTA_UTIL_INLINES_H_

#line 40 "./alberta_util_inlines.h.in.in"

#ifndef USE_LIBBLAS
# define USE_LIBBLAS 0
#endif

#if USE_LIBBLAS
#define DNRM2_F77  
#define DAXPY_F77  
#define DCOPY_F77  
#define DDOT_F77   
#define DSCAL_F77  
#define DSWAP_F77  

extern double DNRM2_F77(int *n, const double *x, int *ix);
extern void DAXPY_F77(int *n, double *alpha, const double *x, int *ix,
                      double *y, int *iy);
extern void DCOPY_F77(int *n, const double *x, int *ix, double *y, int *iy);
extern double DDOT_F77(int *n, const double *x, int *ix, const double *y, 
		       int *iy);
extern void DSCAL_F77(int *n, double *alpha, double *x, int *ix);
extern void DSWAP_F77(int *n, double *x, int *ix, double *y, int *iy);
#endif

static inline void daxpy(int n, double alpha, const double *x, 
			 int ix, double *y, int iy)
{
#if USE_LIBBLAS
  DAXPY_F77(&n, &alpha, x, &ix, y, &iy);
#else
  int i;
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < n; ++i) {
    *y += alpha * *x;
    x += ix;
    y += iy;
  }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
}

static inline void dexpy(int n, const double *x, int ix, double *y, int iy)
{
#if USE_LIBBLAS
  /* DEXPY_F77(&n, x, &ix, y, &iy); */
  REAL one = 1.0;
  DAXPY_F77(&n, &one, x, &ix, y, &iy);
#else
  int i;
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < n; ++i) {
    *y += *x;
    x += ix;
    y += iy;
 }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
}

static inline void dmxpy(int n, const double *x, int ix, double *y, int iy)
{
#if USE_LIBBLAS
  /* DMXPY_F77(&n, x, &ix, y, &iy); */
  REAL mone = -1.0;
  DAXPY_F77(&n, &mone, x, &ix, y, &iy);
#else
  int i;
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < n; ++i) {
    *y -= *x;
    x += ix;
    y += iy;
 }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
}

static inline void dcopy(int n, const double *x, int ix, double *y, int iy)
{
#if USE_LIBBLAS
  DCOPY_F77(&n, x, &ix, y, &iy);
#else
  int i;
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < n; ++i) {
    *y = *x;
    x += ix;
    y += iy;
  }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
}

static inline double ddot(int n, const double *x, int ix,
			  const double *y, int iy)
{
#if USE_LIBBLAS
  return DDOT_F77(&n, x, &ix, y, &iy);
#else
  int i;
  REAL result = 0.0;
# if HAVE_OPENMP
#  pragma omp parallel for reduction(+:result)
# endif
  for (i = 0; i < n; ++i) {
    result += *x * *y;
    x += ix;
    y += iy;
  }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
  return result;
#endif
}

static inline double dnrm2(int n, const double *x, int ix)
{
#if USE_LIBBLAS
  return DNRM2_F77(&n, x, &ix);
#else
  return sqrt(ddot(n , x, ix, x, ix));
#endif
}

static inline void dscal(int n, double alpha, double *x, int ix)
{
#if USE_LIBBLAS
  DSCAL_F77(&n, &alpha, x, &ix);
#else
  int i, nix = n*ix;
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < nix; i += ix) {
    x[i] *= alpha;
  }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
}

static inline void dswap(int n, double *x, int ix, double *y, int iy)
{
#if USE_LIBBLAS
  DSWAP_F77(&n, x, &ix, y, &iy);
#else
  int i;
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < n; ++i) {
    REAL swap = *y; *y = *x; *x = swap;
    x += ix;
    y += iy;
  }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
}

static inline void dxpay(int n, const double *x, int ix, double alpha,
			 double *y, int iy)
{
#if false && USE_LIBBLAS
  /*DXPAY_F77(&n, x, &ix, &alpha, y, &iy);*/
  DSCAL_F77(&n, &alpha, y, &ix);
  dexpy(n, x, ix, y, iy);
#else
  int i;
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < n; ++i) {
    *y = alpha * *y + *x;
    x += ix;
    y += iy;
  }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
  return;
}

static inline void drandn(int n, double *x, int seed)
{
#if false && USE_LIBBLAS
  DRANDN_F77(&n, x, &seed);
#else
  int i;

  if (seed > 0) {
    srand(seed);
  }
# if HAVE_OPENMP
#  pragma omp parallel for
# endif
  for (i = 0; i < n; ++i) {
    x[i] = (double)rand() / (double)RAND_MAX;
  }
# if HAVE_OPENMP
#  pragma omp barrier
# endif
#endif
  return;
}

static inline void dset(int n, double alpha, double *x, int ix)
{
  int i;
#if HAVE_OPENMP
# pragma omp parallel for
#endif
  for (i = 0; i < n; ++i) {
    *x = alpha;
    x += ix;
  }
#if HAVE_OPENMP
# pragma omp barrier
#endif
}

/* Standard scp function. */
static inline REAL std_scp(void *dummy, int dim, const REAL *x, const REAL *y)
{
  return ddot(dim, x, 1, y, 1);
}

/******************************************************************************
 *
 * bit-field operations for the boundary flags (e.g.)
 *
 */

static inline bool bitfield_tst(const FLAGS *bits, int nr)
{
  int word = nr / (sizeof(*bits) * 8);
  int bit  = nr % (sizeof(*bits) * 8);
  
  return (bits[word] & (1 << bit)) != 0;
}

static inline void bitfield_set(FLAGS *bits, int nr)
{
  int word = nr / (sizeof(*bits) * 8);
  int bit  = nr % (sizeof(*bits) * 8);
  
  bits[word] |= 1 << bit;
}

static inline void bitfield_clr(FLAGS *bits, int nr)
{
  int word = nr / (sizeof(*bits) * 8);
  int bit  = nr % (sizeof(*bits) * 8);
  
  bits[word] &= ~(1 << bit);
}

static inline void bitfield_inv(FLAGS *bits, int nr)
{
  int word = nr / (sizeof(*bits) * 8);
  int bit  = nr % (sizeof(*bits) * 8);
  
  bits[word] ^= (1 << bit);
}

static inline int bitfield_nwords(int nbits)
{
  return (nbits + sizeof(FLAGS)*8 - 1) / (sizeof(FLAGS)*8);
}

static inline void bitfield_zap(FLAGS *bits, int nbits)
{
  int i;
  
  for (i = 0; i < bitfield_nwords(nbits); i++) {
    bits[i] = 0;
  }
}

static inline void bitfield_fill(FLAGS *bits, int nbits)
{
  int i;
  
  for (i = 0; i < bitfield_nwords(nbits); i++) {
    bits[i] = ~(FLAGS)0;
  }
}

static inline void bitfield_cpy(FLAGS *to, const FLAGS *from, int nbits)
{
  int i;
  
  for (i = 0; i < bitfield_nwords(nbits); i++) {
    to[i] = from[i];
  }
}

/* Return true if A and B have common bits set. NBITS must be a multiple
 * of 8.
 */
static inline bool bitfield_andp(const FLAGS *a, const FLAGS *b,
				 int offset, int nbits)
{
  int i;
  
  i       = bitfield_nwords(offset);
  offset %= sizeof(FLAGS)*8;
  if (offset != 0) {
    FLAGS mask = ~0UL;
    mask <<= offset;
    if (a[i-1] & b[i-1] & mask) {
      return true;
    }
  }
  for (i = bitfield_nwords(offset); i < bitfield_nwords(nbits); i++) {
    if (a[i] & b[i]) {
      return true;
    }
  }
  return false;
}

/* Compare two bitfields as unsigned numbers */
static inline int bitfield_cmp(const FLAGS *a, const FLAGS *b, int nbits)
{
  int i;
  
  for (i = bitfield_nwords(nbits) - 1; i >= 0; i--) {
    if (a[i] > b[i]) {
      return 1;
    }
    if (a[i] < b[i]) {
      return -1;
    }
  }
  return 0;
}

/* bit-wise and */
static inline void bitfield_and(FLAGS *to, const FLAGS *from, int nbits)
{
  int i;
  
  for (i = 0; i < bitfield_nwords(nbits); i++) {
    to[i] &= from[i];
  }
}

/* bit-wise or */
static inline void bitfield_or(FLAGS *to, const FLAGS *from, int nbits)
{
  int i;
  
  for (i = 0; i < bitfield_nwords(nbits); i++) {
    to[i] |= from[i];
  }
}

/* bit-wise xor */
static inline void bitfield_xor(FLAGS *to, const FLAGS *from, int nbits)
{
  int i;
  
  for (i = 0; i < bitfield_nwords(nbits); i++) {
    to[i] ^= from[i];
  }
}

static inline int ffs_flags(FLAGS bits)
{
  FUNCNAME("ffs_flags");

  TEST_EXIT(sizeof(long) == sizeof(FLAGS),
	    "FIXME: sizeof(long) != sizeof(FLAGS)\n");
  TEST_EXIT(sizeof(long) >= 4,
	    "FIXME: sizeof(long) < 4\n");

#if HAVE_FFSL
# if !HAVE_DECL_FFSL
  extern int ffsl(long int i);
# endif
  return ffsl(bits)-1;
#else
  {
    int r = 0;
    FLAGS mask = ~(FLAGS)0;

    if (!bits) {
      return -1;
    }

    /* The MIN() stuff is only to disable a compiler warning */
    if (sizeof(FLAGS) == 16) {
      mask >>= MIN(64, sizeof(FLAGS)*8-1);
      if (!(bits & mask)) {
	bits >>= MIN(64, sizeof(FLAGS)*8-1);
	r     += 64;
      }
    }
    if (sizeof(FLAGS) >= 8) {
      mask >>= MIN(32, sizeof(FLAGS)*8-1);
      if (!(bits & 0xFFFFFFFF)) {
	bits >>= MIN(32, sizeof(FLAGS)*8-1);
	r += 32;
      }
    }
    if (!(bits & 0xFFFF)) {
      bits >>= 16;
      r += 16;
    }
    /* assume longs are at least 2 bytes ... ;) */
    if (!(bits & 0xFF)) {
      bits >>= 8;
      r += 8;
    }
    if (!(bits & 0xF)) {
      bits >>= 4;
      r += 4;
    }
    if (!(bits & 0x3)) {
      bits >>= 2;
      r += 2;
    }
    if (!(bits & 0x1)) {
      bits >>= 1;
      r += 1;
    }
    return r;
  }
#endif
}

/* Find first set bit, starting at offset */
static inline int bitfield_ffs(const FLAGS *bits, int offset, int nbits)
{
  int i, r, i0;
  FLAGS mask = (~(FLAGS)0) << offset;
  
  i0 = offset > 0 ? bitfield_nwords(offset) - 1 : 0;

  for (i = i0; i < bitfield_nwords(nbits); i++) {
    if ((r = ffs_flags(*bits++ & mask)) >= 0) {
      r += i * sizeof(*bits) * 8;
      return r;
    }
    mask = ~(FLAGS)0;
  }
  return -1;
}

/******************************************************************************/

/*******************************************************************************
 *
 * Doubly linked list managenent/
 *
 * A doubly linked list is abstracted as a pair of a next and a prev
 * pointer. The empty list is characterised by the prev and next
 * pointer of the list-head pointing back to the list-head.
 *
 */

/** Inititializer for the list head. */
#define DBL_LIST_INITIALIZER(name) \
  { (DBL_LIST_NODE *)&(name), (DBL_LIST_NODE *)&(name) }

#define DBL_LIST(name)					\
  DBL_LIST_NODE name = DBL_LIST_INITIALIZER(name)

#define DBL_LIST_INIT(ptr) do {			\
    (ptr)->next = (ptr); (ptr)->prev = (ptr);	\
  } while (0)

/**
 * list_entry - get the struct for this entry
 * @param[in] ptr the struct list_head pointer.
 * @param[in] type the type of the struct this is embedded in.
 * @param[in] member the name of the list_struct within the struct.
 *
 * Example:
 *
 * @code
 * struct my_struct {
 *   int datum;
 *   DBL_LIST_NODE node;
 * };
 *
 *
 * DBL_LIST_NODE *pos; // pointing to &my_struct::node
 * struct my_struct *ptr = dbl_list_entry(pos, struct my_struct, node);
 * @end code
 */
#define dbl_list_entry(ptr, type, member) \
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

/** Iterate over list of given type, it is safe to call
 * dbl_list_delete(pos) inside the loop.
 *
 * @param[in,out] pos The position pointer to use as a loop counter. It
 * has type @c type (i.e. not DBL_LIST_NODE).
 *
 * @param[in,out] next Storage for pos->next, in case pos is deleted
 * from the list inside the loop.
 *
 * @param[in,out] head The list head, DBL_LIST_NODE.
 * 
 * @param[in] type The type of the struct this list's nodes are
 * embedded in.
 *
 * @param[in[ member The name of the DBL_LIST_NODE within the struct.
 */
#define dbl_list_for_each_entry_safe(pos, nextptr, head, type, member)	\
	for (pos = dbl_list_entry((head)->next, type, member),		\
	       (nextptr) = (pos)->member.next;				\
	     &pos->member != (head);					\
	     (pos) = dbl_list_entry(nextptr, type, member),		\
	       (nextptr) = (pos)->member.next)

/** Iterate over list of given type in reverse direction, it is safe
 * to call dbl_list_delete(pos) inside the loop.
 *
 * @param[in,out] pos The position pointer to use as a loop counter. It
 * has type @c type (i.e. not DBL_LIST_NODE).
 *
 * @param[in,out] next Storage for pos->next, in case pos is deleted
 * from the list inside the loop.
 *
 * @param[in,out] head The list head, DBL_LIST_NODE.
 * 
 * @param[in] type The type of the struct this list's nodes are
 * embedded in.
 *
 * @param[in[ member The name of the DBL_LIST_NODE within the struct.
 */
#define dbl_list_for_each_entry_rev_safe(pos, prevptr, head, type, member) \
	for (pos = dbl_list_entry((head)->prev, type, member),		\
	       (nextptr) = (pos)->member.prev;				\
	     &pos->member != (head);					\
	     (pos) = dbl_list_entry(nextptr, type, member),		\
	       (prevptr) = (pos)->member.prev)

/** Iterate over list of given type, it is @b not safe to call
 * dbl_list_delete(pos) inside the loop.
 *
 * @param[in,out] pos The position pointer to use as a loop counter. It
 * has type @c type (i.e. not DBL_LIST_NODE).
 *
 * @param[in,out] head The list head, DBL_LIST_NODE.
 * 
 * @param[in] type The type of the struct this list's nodes are
 * embedded in.
 *
 * @param[in[ member The name of the DBL_LIST_NODE within the struct.
 */
#define dbl_list_for_each_entry(pos, head, type, member)		\
  for ((pos) = dbl_list_entry((head)->next, type, member);		\
       &(pos)->member != (head);					\
       (pos) = dbl_list_entry((pos)->member.next, type, member))

/** Iterate over list of given type in reverse direction, it is @b not
 * safe to call dbl_list_delete(pos) inside the loop.
 *
 * @param[in,out] pos The position pointer to use as a loop counter. It
 * has type @c type (i.e. not DBL_LIST_NODE).
 *
 * @param[in,out] head The list head, DBL_LIST_NODE.
 * 
 * @param[in] type The type of the struct this list's nodes are
 * embedded in.
 *
 * @param[in[ member The name of the DBL_LIST_NODE within the struct.
 */
#define dbl_list_for_each_entry_rev(pos, head, type, member)		\
  for ((pos) = dbl_list_entry((head)->prev, type, member);		\
       &(pos)->member != (head);					\
       (pos) = dbl_list_entry((pos)->member.prev, type, member))

/* A do-while loop for cyclic list, i.e. the list head itself belongs
 * to a real data-item.
 *
 * The expected usage is:
 *
 * dbl_list_do_cyclic(list, my_list_struct, node_name) {
 *   ... but NEVER delete elements
 * } dbl_list_while_cyclic(list, my_list_struct, node_name)
 *
 * When the loop has finished then LIST should point again to the
 * first element, so it should be safe to do the loop with the
 * list-head.
 *
 * Breaking out of the loop will leave you with "list" pointing to the
 * current element.
 */
#define dbl_list_do_cyclic(list, type, member)		\
  {							\
    const DBL_LIST_NODE *_AI_anchor = &(list)->member;	\
    do

#define dbl_list_while_cyclic(list, type, member)			\
  while ((list) = dbl_list_entry((list)->member.next, type, member),	\
	 &(list)->member != _AI_anchor);				\
  }

#define dbl_list_do_cyclic_rev(list, type, member)		\
  {								\
    const DBL_LIST_NODE *_AI_anchor = (list)->member.prev;	\
    (list) = dbl_list_entry((list)->member.prev, type, member);	\
    do

#define dbl_list_while_cyclic_rev(list, type, member)			\
  while ((list) = dbl_list_entry((list)->member.prev, type, member),	\
	 &(list)->member != _AI_anchor);				\
  }

/** Add newnode to head, where newnode will be the new first element
 * of the list.
 */
static inline void
dbl_list_add_head(DBL_LIST_NODE *head, DBL_LIST_NODE *newnode)
{
  head->next->prev = newnode;
  newnode->next = head->next;
  newnode->prev = head;
  head->next = newnode;
}

/** Add newnode to head, where newnode will become the new last
 * element of the list.
 */
static inline void
dbl_list_add_tail(DBL_LIST_NODE *head, DBL_LIST_NODE *newnode)
{
  head->prev->next = newnode;
  newnode->prev    = head->prev;
  newnode->next    = head;
  head->prev       = newnode;
}

/** Delete entry from the list it belongs to. Afterwards entry will
 * point to itself.
 */
static inline void dbl_list_del(DBL_LIST_NODE *entry)
{
  entry->next->prev = entry->prev;
  entry->prev->next = entry->next;
  entry->next       = entry;
  entry->prev       = entry;
}

/** Return true if the given list-head is an empty list. */
static inline bool dbl_list_empty(const DBL_LIST_NODE *head)
{
  return head->next == head;
}

/******************************************************************************/

#endif  /* _ALBERTA_UTIL_INLINES_H_  */

/*
 * Local Variables: ***
 * mode: C ***
 * End: ***
 */
