#ifndef EINA_BLIST_H_
#define EINA_BLIST_H_

// eina_BlockLIST
//
// unrolled linked list. also could be called "linked arrays" or maybe
// "array list" as it's a linked list of arrays. so:
// 
// {[1][2][3][4]}->{[5][6][7][8]}->{[9]}

// list base like eina_hash or eina_array - unlike eina_list
typedef struct _Eina_Blist      Eina_Blist;
// a handle to an item in the list you can use to iterate or "point to" an
// item, but it is not a permanent handle. it is really only valid until
// the list is modified (or specifically modified in a way that would
// affect the item handle - modify the block the item is in). but as this is
// implementation specific, assume any modifications invalidate item handles
typedef struct _Eina_Blist_Item Eina_Blist_Item;

// note that the blist handle is auto-allocated when first item is added and
// auto-freed and set to NULL when the last item is removed if the list
// believes that is a good idea. you MUST call eina_blist_free() to ensure it
// is freed when you don't want the list anymore.
Eina_Blist_Item *eina_blist_item_find             (Eina_Blist **blist, const void *data);
Eina_Blist_Item *eina_blist_item_first            (Eina_Blist **blist);
Eina_Blist_Item *eina_blist_item_last             (Eina_Blist **blist);
Eina_Blist_Item *eina_blist_item_nth              (Eina_Blist **blist, unsigned int n);
void             eina_blist_item_remove           (Eina_Blist **blist, Eina_Blist_Item *item);
void             eina_blist_item_relative_append  (Eina_Blist **blist, const void *data, Eina_Blist_Item *item);
void             eina_blist_item_relative_prepend (Eina_Blist **blist, const void *data, Eina_Blist_Item *item);
// free the list and call the free func on each item in it during free and
// set list ptr to NULL in the end
void             eina_blist_free                  (Eina_Blist **blist);
// the free func to be called on all items freed or removed if its not NULL
void             eina_blist_free_func_set         (Eina_Blist **blist, void (*func) (void *data));
void             eina_blist_append                (Eina_Blist **blist, const void *data);
void             eina_blist_prepend               (Eina_Blist **blist, const void *data);
void             eina_blist_relative_append       (Eina_Blist **blist, const void *data, const void *rel);
void             eina_blist_relative_prepend      (Eina_Blist **blist, const void *data, const void *rel);
void             eina_blist_remove                (Eina_Blist **blist, const void *data);
void            *eina_blist_first                 (Eina_Blist **blist);
void            *eina_blist_last                  (Eina_Blist **blist);
void            *eina_blist_nth                   (Eina_Blist **blist, unsigned int n);
// returnes cached number - doesn't have to walk
unsigned int     eina_blist_count                 (Eina_Blist **blist);
// clean/defragment list if it is too fragmented (whatever blist thinks)
void             eina_blist_clean                 (Eina_Blist **blist);
// clean/defrag list regardless if its fragmented or not.
void             eina_blist_clean_force           (Eina_Blist **blist);
// return how many blocks are not full (a sign of fragmentation if > 0). this
// explicitly walks to figure this out as opposed to using the accounting
// values that track this status
// XXX: need this?
unsigned int     eina_blist_frag_scan             (Eina_Blist **blist);

// XXX: things that can be added but are not necessary:
// new Eina_Iterator
// new Eina_Iterator reversed
// new Eina_Accessor
// sort blist
// sorted insert
// clone blist
// reverse blist
// reverse clone blist
// promote
// demote
// find (return data ptr)
// shuffle blist
// merge blist1, blist2
// sorted merge blist1, blist2
// split blist at item
// get item index (nth)

Eina_Blist_Item *eina_blist_item_next             (Eina_Blist_Item *item);
Eina_Blist_Item *eina_blist_item_prev             (Eina_Blist_Item *item);
void            *eina_blist_item_data_get         (Eina_Blist_Item *item);
void             eina_blist_item_data_set         (Eina_Blist_Item *item, const void *data);

#define EINA_BLIST_FOREACH(blist, l, ptr) \
   for (l = eina_blist_item_first(blist), d = eina_blist_item_data_get(l); \
        l; l = eina_blist_item_next(l), d = eina_blist_item_data_get(l))
#define EINA_BLIST_REVERSE_FOREACH(blist, l, ptr) \
   for (l = eina_blist_item_last(blist), d = eina_blist_item_data_get(l); \
        l; l = eina_blist_item_prev(l), d = eina_blist_item_data_get(l))

#endif
