upgrade for hashvector ABI changes.
[rrq/rrqmisc.git] / vector / vector.h
index ccd57f30643fc5fef8b4c32a555a54ad588d93e3..4dc61f8ee793d2429a7807c56c07a060a8f0bf32 100644 (file)
 #ifndef vector_H
 #define vector_H
 
-/**
+/** \file
+ *
  * A vector is a dynamic pointer array implemented as an access tree
- * of index pages. The indexing is done using "unsigned long" indexes.
- */
-
-#ifndef VECTOR_LEVEL_BITS
-/*!
- * Macro: VECTOR_LEVEL_BITS
- * This defines the number of bits in the indexing bit field.
+ * of index pages. The indexing is done using "unsigned long" indexes,
+ * and the level 0 index corresponds to actual items.
+ *
+ * Actual vectors are assigned a leveling variant which defines the
+ * index page size for the vector. This must not be changed for a
+ * vector with entries.
  */
-#define VECTOR_LEVEL_BITS 8
-#endif
 
-/*!
- * Type: vector_index
- * This is the general indexing used for vector access.
+/**
+ * \brief This is the general indexing used for vector access.
+ *
+ * \related vector
  */
 typedef unsigned long vector_index;
 
-/*!
- * Macro: VECTOR_INDEX_BITS
- * This defines the number of bits of a vector index
+/**
+ * \brief A vector_page is an array of void* items. Its size depends
+ * on the applicable vector variant.
+ *
+ * \related vector
  */
-#define VECTOR_INDEX_BITS ( sizeof( vector_index ) * 8 )
+typedef void* vector_page[];
 
-/*!
- * Macro: VECTOR_INDEX_FIELDS
- * This defines the number of bit fields in an vector index
+/**
+ * \brief The implementation variants.
+ *
+ * - byte_index_levels (0) has 8-bit indexing parts and index pages
+ *   with 256 pointers,
+ *
+ * - nibble_index_levels (1) has 4-bit indexing parts and index pages
+ *   with 16 pointers,
+ *
+ * - bitpair_index_levels (2) has 2-bit indexing parts and index pages
+ *   with 4 pointers,
+ *
+ * - single_index_level (3) has a single page that is sized as the
+ *   vector.
+ *
+ * The first three variants are managed by adding/removing full pages
+ * of the indexing tree upon resize and access. The single_index_level
+ * variant is managed by using realloc upon resize. In all cases
+ * shrinking a vector might mean to reclaim items about to be "lost",
+ * if any, via a provided item reclaim callback function. The callback
+ * function may then also veto the shrinking.
+ *
+ * \related vector
  */
-#define VECTOR_INDEX_FIELDS \
-    ( ( VECTOR_INDEX_BITS - 1 ) / VECTOR_LEVEL_BITS + 1 )
+enum vector_variant {
+    byte_index_levels = 0,
+    nibble_index_levels = 1,
+    bitpair_index_levels = 2,
+    single_index_level = 3
+};
 
-/*!
- * Macro: VECTOR_SLOTS
- * This defines the number of slots spanned by an index level
+/**
+ * A vector struct is the "foot part" of a representation that
+ * constitutes the implementation variant for a vector abstraction. It
+ * holds the variant indicator, the intended slot size and a root
+ * pointer for the indexing structure, which consist of indexing pages
+ * according to the variant.
  */
-#define VECTOR_SLOTS ( 1 << VECTOR_LEVEL_BITS )
+typedef struct {
+    /**
+     * The indexing variant.
+     */
+    enum vector_variant variant;
+
+    /**
+     * The size of the vector.
+     */
+    vector_index size;
+
+    /**
+     * The root page of the indexing tree.
+     */
+    vector_page *entries;
+} vector;
 
-/*!
- * Type: vector_page
+/**
+ * \brief Return the number of slots spanned by an index level for the
+ * given vector variant.
  *
- * A vector_page is an array of 16 void* items.
+ * - 0 indicates 8-bit index parts, and 256 page slots
+ * - 1 indicates 4-bit index parts, and 16 page slots
+ * - 2 indicates 2-bit index parts, and 4 page slots
+ * - 3 indicates 64-bit index parts, and 1 page level following the size
+ * 
+ * The type 3 vector is managed by using realloc.
+ * \related vector
  */
-typedef void* vector_page[ VECTOR_SLOTS ];
+extern unsigned long VECTOR_SLOTS(vector *pv);
 
-/*!
- * Type: vector
+/**
+ * \brief Find the nearest used (non-null) slot at given or higher
+ * index.
+ *
+ * \param pv is the vector concerned.
  *
- * A vector is a compound of a size and a vector_page pointer, which
- * when non-null points out the top-most page of the vector. The
- * number of levels is derived from its size with level 0 being the
- * leaf level of actual content. E.g., a vector larger than 16
- * items, has at least two levels, and generally N levels may span up
- * to 16^N content entries.
+ * \param index is the index to change.
+ *
+ * \returns a pointer to the first non-null vector slot from the given
+ * index, and *index set accordingly. If no non-null slot is found,
+ * the 0 is returned and *index is set to the vector size.
+ *
+ * \related vector
  */
-typedef struct _vector {
-    vector_index size;     //!< Limit for the logical entries[]
-    vector_page *entries; //!< Pointer to entries indexing
-} vector;
+extern void **vector_next_used(vector *pv,vector_index *index);
 
-/*!
- * Find the next used slot at given index or later. With a reclaim
- * function, it will be invoked for verifying that the item is
- * actually in use, in which case it returns 1. Otherwise it should
- * reclaim any memory for the item and return 0;
+/**
+ * \brief Find the nearest used (non-null) slot at given or lower
+ * index.
+ *
+ * \param pv is the vector concerned.
+ *
+ * \param index is the index to change.
+ *
+ * \returns a pointer to the first non-null vector slot from the given
+ * index, and *index set accordingly. If no non-null slot is found,
+ * the 0 is returned and *index is set to the vector size.
+ *
+ * \related vector
  */
-void **vector_next_used(
-    vector *pv,vector_index *index,
-    int (*reclaim)(vector *pv,vector_index index,void *item,void *data),
-    void *data );
+extern void **vector_prev_used(vector *pv,vector_index *index);
 
-/*!
- * Function: int vector_resize(
- *              vector *pv,vector_index new_size,
- *              int (*reclaim)(vector *,vector_index,void *item,void *data),
- *              void *data )
- * \param pv
- * \param new_size
- * \param reclaim
- * \param data
- *
- * Tries to resize the given vector to a new size. This may result in
- * the introduction or removal of indexing pages, so that the leveling
- * is consistent with the vector size. Thus, if it grows into a new
- * 16^N level, then one or more new upper level pages are inserted as
- * needed. If it shrinks below the current level, then top-level pages
- * are remove.
+/**
+ * \brief Resize a vector.
+ *
+ * \param pv is the vector concerned.
+ *
+ * \param new_size is the new size it should have,
+ *
+ * \param reclaim is used upon shrinking in size for handling any
+ * current items above the new size, or vetoing the attempted resize.
+ *
+ * \param data is passed on the the reclaim function to use as context
+ * as needed.
+ *
+ * \returns the index of a resizing veto any, or <0 otherwise, with -1
+ * indicating success and -2 indicating OOM.
+ *
+ * This function attempts to resize the given vector to a new size.
+ * This may result in the introduction or removal of indexing pages,
+ * so that the index tree leveling is consistent with the vector size.
+ * Thus, if it grows into a new level, then one or more new upper
+ * level pages are inserted as needed. If it shrinks below the current
+ * level, then top-level pages are removed.
  *
  * Also, if the new size is smaller than currently, then the now
  * excess tail of entries is scanned for any used slots and the given
  * reclaim function is invoked successively for these. The reclaim
  * function must, in addition to memory-managing the entry, return 0
- * upon success and non-zero to veto the attempted vector size
- * change. The data argument is passed on to the reclaim function.
+ * upon success, or non-zero to veto the attempted vector size change.
+ * The data argument is passed on to the reclaim function as given.
  *
- * The vector_resize function returns 0 on success, with the size
- * duly changed. Otherwise the function retains the current size and
- * returns -index-1 for the index of the veto-ed entry.
+ * \related vector
  */
-int vector_resize(
+extern int vector_resize(
     vector *pv, vector_index new_size,
     int (*reclaim)(vector *pv,vector_index index,void *item,void *data),
     void *data );
 
-/*!
- * Function: void **vector_entry(vector *pv,vector_index index)
- * \param pv - the vector record
- * \param index - the slot index
+/** 
+ * \brief Return pointer to the indexed page slot at the requested
+ * level, and adding intermediate index pages if so requested.
+ *
+ * \param pv is the vector concerned.
+ *
+ * \param index is the slot index.
+ *
+ * \param level is the indexing level to access. Level 0 is the leaf
+ * level that holds the slots for the items; level 1 is one level up,
+ * for vectors larger than 256 items; ans so on.
+ *
+ * \param add is a flag to indicate (with 1) that missing index pages
+ * should be added, or (with 0) that the function should simply return
+ * null if an index page to access at any level is missing.
+ *
+ * \returns a pointer to the slot for the indexed item (level 0), or
+ * (for higher levels) the slot for the index page on the access path
+ * to the indexed item. The function returns 0 if the access path is
+ * broken by a missing index page, or (with add==1) the allocation of
+ * a new index page fails.
+ *
+ * \note The index tree for the vector is populated on demand only
+ * where access has been requested.
+ *
+ * \related vector
+ */
+extern void **vector_access(vector *pv,vector_index index,int level,int add);
+
+/**
+ * \brief Return the slot value at the given index.
+ *
+ * \param pv is the vector concerned.
  *
- * [pgix,epix] = modulo( index, pv->page );
+ * \param index is the slot index.
  *
  * \returns a direct pointer to the slot of the given index in the
- * array, or 0 if the index is beyond the array limits (0-limit). Note
- * that slot pointers are only valid while the vector size is
- * unchanged.
+ * array, or 0 if the index is beyond the array limits (0-limit).
+ *
+ * \note Note that slot pointers are only valid while the vector size
+ * is unchanged.
+ *
+ * \related vector
  */
 extern void **vector_entry(vector *pv,vector_index index); 
 
-/*!
- * Function: vector_index vector_size(vector *pv)
- * \param pv - the vector record
+/**
+ * \param pv - the vector concerned
  * \returns the size of the vector.
+ * \related vector
  */
-inline vector_index vector_size(vector *pv) {
-    return pv->size;
-}
+#define vector_size(pv) ((vector_index) (pv)->size)
 
-void vector_set(vector *pv,vector_index index,void *value);
+/**
+ * \brief Set the vector value at the given index.
+ *
+ * \param pv is the vector concerned
+ * \param index is the index for the slot to assign
+ * \param value is the new slot value
+ *
+ * \note An assignment of 0 will be treated as an unused slot.
+ *
+ * \related vector
+ */
+extern void vector_set(vector *pv,vector_index index,void *value);
 
-void *vector_get(vector *pv,vector_index index);
+/**
+ * \brief Set the vector value at the given index and return the prior
+ * value.
+ *
+ * \param pv is the vector concerned
+ * \param index is the index for the slot to assign
+ * \param value is the new slot value
+ *
+ * \note An assignment of 0 will be treated as an unused slot.
+ *
+ * \related vector
+ */
+extern void *vector_get_set(vector *pv,vector_index index,void *value);
+
+/**
+ * \brief Get the vector value at the given index.
+ *
+ * \param pv is the vector concerned
+ * \param index is the index for the slot to assign
+ *
+ * \note This function will allocate all traversed indeex tree pages
+ * even for accessing an unassigned slot.
+ *
+ * \related vector
+ */
+extern void *vector_get(vector *pv,vector_index index);
+
+/**
+ * \brief Grow the vector by one and assign the added slot.
+ *
+ * \param pv is the vector concerned
+ * \param value is the new slot value
+ *
+ * \related vector
+ */
+extern void vector_append(vector *pv,void *value);
+
+/**
+ * \brief Copy a consecutive region from one vector into another, or
+ * possibly the same vector.
+ *
+ * \param pv is the vector concerned
+ * \param value is the new slot value
+ *
+ * \note This transfers all slots from the source region to the
+ * destination region, including zero slots. The vectors must be large
+ * enough for the transfer, which is carried out from lowest to
+ * highest or highest to lowest index depending on wther the move is
+ * to higher index or to lower index respectively.
+ *
+ * \related vector
+ */
+extern void vector_copy(
+    vector *dst,vector_index di,
+    vector *src,vector_index si,
+    vector_index n);
+
+/**
+ * \brief Allocate a copy of a vector into one in the given variant.
+ */
+extern vector *vector_clone(enum vector_variant variant,vector *src);
+
+/**
+ * \brief Utility function that invokes the itemdump function for all
+ * used (non-null) slots.
+ *
+ * \related vector
+ * \seealso vector_iterate
+ */
+extern void vector_dump(
+    vector *pv,
+    void (*itemdump)(const vector_index ,const void *));
+
+/**
+ * \brief Sort a vector with quicksort using the provided ordering
+ * collback function.
+ *
+ * \related vector
+ */
+extern void vector_qsort(vector *pv,int (*compar)(const void *,const void *));
 
-void vector_append(vector *pv,void *value);
+/**
+ * Steps through the vector item by item invoking the given function
+ * for each. Continues stepping while the item function returns 0.
+ *
+ * \related vector
+ */
+extern void vector_iterate(
+    vector *pv, vector_index start,
+    int (*itemfn)(vector_index,void *item,void *data),
+    void *data);
 
-void vector_copy(vector *dst,vector_index di,
-                 vector *src,vector_index si,vector_index n);
+/**
+ * \brief Binary search in a sorted vector for an item of the given
+ * key, with a callback function providing the sorting order.
+ *
+ * \param pv is the vector concerned.
+ *
+ * \param index is a vector_index pointer for returning the index of
+ * the found item.
+ *
+ * \param key is the lookup key to find.
+ *
+ * \param compare is a callback function that should return the search
+ * direction given a key and an item. It should return 0 if the key is
+ * a match for the item, <0 if the sought item is expected at a higher
+ * index, and >0 if the sought item is expected at a lower index.
+ *
+ * \return a pointer to the found item and *index set to its index. If
+ * there is no matching item, then 0 is returned, and the index is set
+ * to the vector size.
+ *
+ * \related vector
+ */
+extern void *vector_bsearch(
+    vector *pv, vector_index *index, const void *key,
+    int (*compare)(const void *key, const void *item));
+
+/**
+ * \brief Find the index for a given value
+ *
+ * \param pv is the vector concerned
+ * \param is the value to find
+ *
+ * This function scans the vector for the first, if any, occurrence of
+ * the value, or returns pv->size if not found.
+ *
+ * \related vector
+ */
+extern vector_index vector_find(vector *pv,void *value);
 
-void vector_dump(vector *pv,
-                 int (*itemdump)(const vector_index ,const void *));
+/**
+ * \brief Find the next used slot at or after the given index.
+ *
+ * \param pv the vector concerned.
+ * \param index pointer to the index to advance.
+ * \return the new index, or the vector size if no unused slot is
+ * found.
+ *
+ * Scans forward in the vector for the first unused (null) vector slot
+ * at or after the given index. Returns pv->size if full.
+ *
+ * \related vector
+ */
+extern vector_index vector_next_unused(vector *pv,vector_index index);
 
-void vector_qsort(vector *pv,int (*compar)(const void *,const void *));
+/**
+ * \brief Convenience callback function for vector shrinking to free
+ * any existing slot assignment.
+ *
+ * \related vector
+ */
+extern int vector_free_any(vector *pv,vector_index ix,void *item,void *data);
 
-void vector_iterate(vector *pv,
-                    int (*itemfn)(vector_index,void*,void*),
-                    void*);
+/**
+ * \brief Convenience callback function for vector shrinking to ignore
+ * any existing slot assignment (without free-ing them).
+ *
+ * \related vector
+ */
+extern int vector_clear_any(vector *pv,vector_index ix,void *item,void *data);
 
 #endif