/*

  silclist.h

  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>

  Copyright (C) 2000 Pekka Riikonen

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

*/

#ifndef SILCLIST_H
#define SILCLIST_H

#include "trq_list.h"

/*
   SILC List API

   SILC List API is a list API defined over TRQ library. TRQ is efficient
   deque and list handling library programmed by Timo J. Rinne and the code
   is available from http://www.iki.fi/~tri/.  Read COPYRIGHT if you intend
   to use TRQ.

   I don't particularly like the TRQ API so I decided to define own SILC List
   API over it and it should be a bit clearer now. See comments below for
   usage of the list.

   The API uses only necessary functions from the TRQ. TRQ defines a lot
   more functions that could be used but currently they are not needed in
   SILC. More may be added later if needed.
   
*/

/* SilcList type definition */
typedef trq_list SilcList;

/* Functions return SILC_LIST_END if the list pointer becomes invalid. This
   happens if the list gets empty. */
#define SILC_LIST_END TRQ_NO_ITEM

/* Initializes SilcList object. Example:

   SilcList list;

   silc_list_init(list, struct SilcInternalEntryStruct, next);

   Where `list' is the defined list, and second argument is the structure
   of the entries in the list and last argument is the pointer in the entry
   structure that is used as list member. SilcInternalEntry might be as 
   follows:

   struct SilcInternalEntryStruct {
     char *dummy;
     struct SilcInternalEntryStruct *next; // The list member pointer
   };

   The `next' pointer in the structure (or some other pointer for that matter)
   is given for the silc_list_init as the last argument. This pointer is used
   by the list routines to link the entries together in the list. Your code
   should not touch the member pointer manually.
*/
#define silc_list_init(x, t, m) trq_list_init(&(x), t, m)

/* Uninits the list by removing all entries from the list. This does not
   free the memory of the entry pointers but just invalidates the list
   pointer. This should be called to remove entries from the list (unless
   removed them one by one, manually). Note: usually this is not needed
   as caller has to free the entries manually anyway, so they are removed
   from the list when free'ing the memory. */
#define silc_list_uninit(x) trq_list_clear(&(x))

/* Return the number of entries in the list */
#define silc_list_count(x) trq_list_length(&(x))

/* Set the start of the list. This prepares the list for traversing entries
   from the start of the list. */
/*#define silc_list_start(x) (trq_list_reverse(&(x)), trq_list_rewind(&(x)))*/
#define silc_list_start(x) trq_list_rewind(&(x))

/* Adds new entry `p' to the list. This is the default function to
   add new entries to the list. */
#define silc_list_add(x, p) trq_list_insert_head(&(x), p)

/* Remove entry `p' from the list. Returns < 0 on error, 0 otherwise. */
#define silc_list_del(x, p) trq_list_remove(&(x), p)

/* Returns current entry from the list and moves the list pointer forward
   so that calling this next time returns the next entry from the list. This
   can be used to traverse the list. Return SILC_LIST_END when the entire
   list has ben traversed. Later, silc_list_start must be called again when 
   re-starting list traversing. Example:

   // Traverse the list from the beginning to the end 
   silc_list_start(list)
   while ((entry = silc_list_get(list)) != SILC_LIST_END) {
     ...
   }
   
*/
#define silc_list_get(x) __silc_list_get(&(x))

extern inline
void *__silc_list_get(SilcList *x)
{
  void *e = trq_list_get_fw(x);
  if (e != TRQ_NO_ITEM) {
    if (trq_list_pointer_valid(x))
      trq_list_put_before(x, e);
    else
      trq_list_insert_head(x, e);
  }
  return e;
}

/* Quicksort the list. The `test' is pointer to tester function of following
   type: int (*test)(void *item1, void *item2, void *context). 

   Note that quicksort is bad choice of sorting when the list is already or
   very closely in order. */
#define silc_list_quicksort(x, test, context) 	\
  trq_list_quicksort(x, test, context)

/* Bubblesort the list. The `test' is pointer to tester function of following
   type: int (*test)(void *item1, void *item2, void *context). 

   Note that that bubblesort is bad choice when the list is large and in very
   random order. */
#define silc_list_bubblesort(x, test, context) 	\
  trq_list_bubblesort(x, test, context)

/* Mergesort the list. The `test' is pointer to tester function of following
   type: int (*test)(void *item1, void *item2, void *context). 

   Merge sort is a pretty good choice in all cases.
*/
#define silc_list_mergesort(x, test, context) 	\
  trq_list_mergesort(x, test, context)

#endif
