[Opensrf-commits] r1766 - trunk/src/libopensrf (scottmk)
svn at svn.open-ils.org
svn at svn.open-ils.org
Thu Sep 3 16:00:54 EDT 2009
Author: scottmk
Date: 2009-09-03 16:00:49 -0400 (Thu, 03 Sep 2009)
New Revision: 1766
Modified:
trunk/src/libopensrf/osrf_list.c
Log:
1. In osrfListSetDefault(): install the standard function
free() as the default item-freeing callback function,
instead of the gossamer-thin and useless wrapper for it,
osrfListVanillaFree(). This change eliminates a layer of
function call overhead.
2. Eliminate osrfListVanillaFree() as neither used nor useful.
3. Add doxygen-style comments to document every function.
Modified: trunk/src/libopensrf/osrf_list.c
===================================================================
--- trunk/src/libopensrf/osrf_list.c 2009-09-03 12:34:42 UTC (rev 1765)
+++ trunk/src/libopensrf/osrf_list.c 2009-09-03 20:00:49 UTC (rev 1766)
@@ -1,13 +1,52 @@
+/**
+ @file osrf_list.c
+ @brief Implementation of osrfList, sort of like a vector class.
+
+ An osrfList manages an array of void pointers, allocating additional memory as
+ needed when the array needs to grow. Optionally, it may call a designated callback
+ function as a destructor when one of the void pointers is removed, or when the
+ array itself is destroyed.
+
+ The callback function must be of type void and accept a void pointer as its parameter.
+ There is no specific function for installing or uninstalling such a callback; just assign
+ directly to the freeItem member of the osrfList structure.
+
+ Unlike a typical vector class in, or example, C++, an osrfList does NOT shift items
+ around to fill in the gap when you remove an item. Items stay put.
+
+ The use of void pointers involves the usual risk of type errors, so be careful.
+
+ NULL pointers are a special case. On the one hand an osrfList will happily store
+ a NULL if you ask it to. On the other hand it may overwrite a NULL pointer previously
+ stored, treating it as disposable. Conclusion: you can store NULLs in an osrfList, but
+ not safely, unless you are familiar with the internal details of the implementation and
+ work around them accordingly.
+*/
+
#include <opensrf/osrf_list.h>
-
+/** @brief The initial size of the array when none is specified */
#define OSRF_LIST_DEFAULT_SIZE 48 /* most opensrf lists are small... */
+/** @brief How many slots to add at a time when the array grows */
#define OSRF_LIST_INC_SIZE 256
//#define OSRF_LIST_MAX_SIZE 10240
+/**
+ @brief Create a new osrfList with OSRF_LIST_DEFAULT_SIZE slots.
+ @return A pointer to the new osrfList.
+
+ The calling code is responsible for freeing the osrfList by calling osrfListFree().
+*/
osrfList* osrfNewList() {
return osrfNewListSize( OSRF_LIST_DEFAULT_SIZE );
}
+/**
+ @brief Create a new osrfList with a specified number of slots.
+ @param size How many pointers to store initially.
+ @return A pointer to the new osrfList.
+
+ The calling code is responsible for freeing the osrfList by calling osrfListFree().
+*/
osrfList* osrfNewListSize( unsigned int size ) {
osrfList* list;
OSRF_MALLOC(list, sizeof(osrfList));
@@ -22,17 +61,40 @@
int i;
for( i = 0; i < list->arrsize; ++i )
list->arrlist[ i ] = NULL;
-
+
return list;
}
+/**
+ @brief Add a pointer to the end of the array.
+ @param list A pointer to the osrfList
+ @param item A pointer to be added to the list.
+ @return Zero if successful, or -1 if the list parameter is NULL.
+
+ The item pointer is stored one position past the last slot that might be in use. The calling
+ code should, in general, make no assumptions about where that position is. See the discussion
+ of osrfListGetCount() for the dirty details.
+*/
int osrfListPush( osrfList* list, void* item ) {
if(!(list)) return -1;
osrfListSet( list, item, list->size );
return 0;
}
+/**
+ @brief Store a pointer in the first unoccupied slot.
+ @param list A pointer to the osrfList.
+ @param item The pointer to be stored.
+ @return If successful, the number of slots currently in use, or -1 if either of the
+ parameters is NULL.
+
+ Find the lowest-numbered position holding a NULL and overwrite it with the specified
+ item pointer.
+
+ The meaning of the return value (other than -1) is fuzzy and probably not useful,
+ because some of the slots counted as "in use" may in fact hold NULLs.
+*/
int osrfListPushFirst( osrfList* list, void* item ) {
if(!(list && item)) return -1;
int i;
@@ -42,6 +104,24 @@
return list->size;
}
+/**
+ @brief Store a pointer at a specified position in an osrfList.
+ @param list A pointer to the osrfList.
+ @param item The pointer to be stored.
+ @param position Where to store it (a zero-based subscript).
+ @return A pointer to the previous occupant of the specified slot, if any, or NULL if
+ it was unoccupied, or if we have freed the occupant.
+
+ If the pointer previously stored in the specified slot is not NULL, then the behavior
+ depends on whether the calling code has provided a callback function for freeing stored
+ items. If there is such a callback function, we call it for the previously stored
+ pointer, and return NULL. Otherwise we return the previously stored pointer, so that
+ the calling code can free it if it needs to.
+
+ If the specified position is beyond the physical bounds of the array, we replace the
+ existing array with one that's big enough. This replacement is transparent to the
+ calling code.
+*/
void* osrfListSet( osrfList* list, void* item, unsigned int position ) {
if(!list || position < 0) return NULL;
@@ -73,11 +153,28 @@
}
+/**
+ @brief Fetch the pointer stored at a specified position.
+ @param list A pointer to an osrfList.
+ @param position A zero-based index specifying which item to fetch.
+ @return The pointer stored at the specified position, if any, or NULL.
+
+ The contents of the osrfList are unchanged.
+
+ If either parameter is invalid, the return value is NULL.
+*/
void* osrfListGetIndex( const osrfList* list, unsigned int position ) {
if(!list || position >= list->size || position < 0) return NULL;
return list->arrlist[position];
}
+/**
+ @brief Free an osrfList, and, optionally, everything in it.
+ @param list A pointer to the osrfList to be freed.
+
+ If the calling code has specified a function for freeing items, it is called for every
+ non-NULL pointer in the array.
+*/
void osrfListFree( osrfList* list ) {
if(!list) return;
@@ -93,6 +190,22 @@
free(list);
}
+/**
+ @brief Remove the pointer from a specified position.
+ @param list A pointer to the osrfList.
+ @param position A zero-based index identifying the pointer to be removed.
+ @return A copy of the pointer removed, or NULL if the item was freed.
+
+ Returns NULL if either parameter is invalid. Otherwise:
+
+ If a callback function has been installed for freeing the item to which the pointer
+ points, it is called, and osrfListRemove returns NULL. Otherwise it returns the pointer
+ at the specified position in the array. In either case it overwrites the pointer in
+ the array with NULL.
+
+ Note that other positions in the array are not affected; i.e. osrfListRemove does NOT
+ shift other pointers down to fill in the hole left by the removal.
+*/
void* osrfListRemove( osrfList* list, unsigned int position ) {
if(!list || position >= list->size || position < 0) return NULL;
@@ -107,6 +220,15 @@
return olditem;
}
+/**
+ @brief Remove a pointer from a specified position and return it.
+ @param list A pointer to the osrfList.
+ @param position A zero-based subscript identifying the pointer to be extracted.
+ @return The pointer at the specified position.
+
+ This function is identical to osrfListRemove(), except that it never frees the item
+ to which the pointer points, even if an item-freeing function has been designated.
+*/
void* osrfListExtract( osrfList* list, unsigned int position ) {
if(!list || position >= list->size || position < 0) return NULL;
@@ -118,6 +240,18 @@
}
+/**
+ @brief Find the position where a given pointer is stored.
+ @param list A pointer to the osrfList.
+ @param addr A void pointer possibly stored in the osrfList.
+ @return A zero-based index indicating where the specified pointer resides in the array,
+ or -1 if no such pointer is found.
+
+ If either parameter is NULL, osrfListFind returns -1.
+
+ If the pointer in question is stored in more than one slot, osrfListFind returns the
+ lowest applicable index.
+*/
int osrfListFind( const osrfList* list, void* addr ) {
if(!(list && addr)) return -1;
int index;
@@ -129,18 +263,66 @@
}
+/**
+ @brief Return the number of slots in use.
+ @param list A pointer to an osrfList.
+ @return The number of slots in use.
+
+ The concept of "in use" is highly counter-intuitive and not, in general, very useful for the
+ calling code. It is an internal optimization trick: it keeps track of how many slots *might*
+ contain non-NULL pointers, not how many slots *do* contain non_NULL pointers. It
+ represents how many slots certain operations need to look at before they can safely stop.
+
+ Extreme example: starting with an empty osrfList, call osrfListSet()
+ to add a pointer at slot 15. If you then call osrfListGetCount(),
+ it returns 16, because you installed the pointer in the sixteenth slot (counting from 1),
+ even though the array contains only one non-NULL pointer.
+
+ Now call osrfListRemove() to remove the pointer you just added. If you then call
+ osrfListGetCount(), it returns 15, even though all the pointers in the array are NULL,
+ because osrfListRemove() simply decremented the counter from its previous value of 16.
+
+ Conclusion: osrfListGetCount() tells you next to nothing about the contents of the array.
+ The value returned reflects not only the current state of the array but also the history
+ and sequence of previous operations.
+
+ If you have changed the contents of the array only by calls to osrfListPush() and/or
+ osrfListPushFirst(), thereby leaving no holes in the array at any time, then
+ osrfListGetCount() will return the answer you expect. Otherwise all bets are off.
+*/
unsigned int osrfListGetCount( const osrfList* list ) {
if(!list) return -1;
return list->size;
}
+/**
+ @brief Remove the last pointer from the array.
+ @param list A pointer to an osrfList.
+ @return The pointer so removed, or NULL.
+
+ As with osrfListRemove(), if a callback function has been defined, osrfListPop() calls it
+ for the pointer it removes, and returns NULL. Otherwise it returns the removed pointer.
+
+ The concept of "last pointer" is non-intuitive. It reflects, in part, the history and
+ sequence of previous operations on the osrfList. The pointer removed is the one with
+ subscript n - 1, where n is the value returned by osrfListGetCount(). See the discussion
+ of the latter function for the dirty details.
+
+ In brief, osrfListPop() will behave in the obvious and expected way as long as you never
+ create holes in the array via calls to osrfListSet(), osrfListRemove(), or osrfListExtract().
+*/
void* osrfListPop( osrfList* list ) {
if(!list) return NULL;
return osrfListRemove( list, list->size - 1 );
}
+/**
+ @brief Create and initialize an osrfListIterator for a given osrfList.
+ @param list A pointer to an osrfList.
+ @return A pointer to the newly constructed osrfListIterator.
+*/
osrfListIterator* osrfNewListIterator( const osrfList* list ) {
if(!list) return NULL;
osrfListIterator* itr;
@@ -150,29 +332,54 @@
return itr;
}
+/**
+ @brief Advance an osrfListIterator to the next position in the array.
+ @param itr A pointer to the osrfListIterator to be advanced.
+ @return The pointer at the next position in the array; or NULL, if the osrfIterator
+ is already past the end.
+
+ The first call to osrfListIteratorNext() for a given osrfListIterator returns the first
+ pointer in the array (i.e slot zero, counting from zero). Subsequent calls return successive
+ pointers from the array. Once it has returned the last pointer, the iterator responds to
+ subsequent calls by returning NULL, unless it is restored to an initial state by a call to
+ osrfListIteratorReset().
+
+ A return value of NULL does not necessarily indicate that the iterator has reached the end
+ of the array. Depending on the history and sequence of previous operations, the array may
+ include NULLs that are regarded as part of the array. See the discussions of osrfListPop()
+ and osrfListGetCount().
+*/
void* osrfListIteratorNext( osrfListIterator* itr ) {
if(!(itr && itr->list)) return NULL;
if(itr->current >= itr->list->size) return NULL;
return itr->list->arrlist[itr->current++];
}
+/**
+ @brief Free an osrfListIterator.
+ @param itr A pointer to the osrfListIterator to be freed.
+*/
void osrfListIteratorFree( osrfListIterator* itr ) {
if(!itr) return;
free(itr);
}
+/**
+ @brief Reset an osrfListIterator to the beginning of the associated osrfList.
+ @param itr A pointer to the osrfListIterator to be reset.
+*/
void osrfListIteratorReset( osrfListIterator* itr ) {
if(!itr) return;
itr->current = 0;
}
-void osrfListVanillaFree( void* item ) {
- free(item);
-}
-
+/**
+ @brief Install a default item-freeing callback function (the ANSI standard free() function).
+ @param list A pointer to the osrfList where the callback function will be installed.
+ */
void osrfListSetDefaultFree( osrfList* list ) {
if(!list) return;
- list->freeItem = osrfListVanillaFree;
+ list->freeItem = free;
}
More information about the opensrf-commits
mailing list