/**
 * Associates the specified value with the specified key in this map.
 *
 * If the map previously contained a mapping for the key, the old value is replaced by the specified value.
 * (A map m is said to contain a mapping for a key k if and only if pblMapContainsKey(k) would return true.)
 *
 * For hash maps this method has a time complexity of O(1).
 * For tree maps this method has a time complexity of O(Log N).
 *
 * @return int rc >  0: The map did not already contain a mapping for the key.
 * @return int rc == 0: The map did already contain a mapping for the key.
 * @return int rc <  0: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_MEMORY - Out of memory.
 * <BR>PBL_ERROR_OUT_OF_BOUNDS - Maximum capacity of the hash set exceeded.
 */
int pblMapAdd( /*                                             */
PblMap * map, /**                   The map to add to         */
void * key, /**                     Key to add a mapping for  */
size_t keyLength, /**               Length of the key         */
void * value, /**                   Value of the new mapping  */
size_t valueLength /**              Length of the value       */
)
{
    int rc;
    PblMapEntry * mapEntry;
    PblMapEntry * newEntry =
            pblMapEntryNew( key, keyLength, value, valueLength );
    if( !newEntry )
    {
        return -1;
    }

    mapEntry = (PblMapEntry *)pblSetReplaceElement( map->entrySet, newEntry );
    if( mapEntry )
    {
        PBL_FREE( mapEntry );
        return 0;
    }

    rc = pblSetAdd( map->entrySet, newEntry );
    if( rc < 0 )
    {
        PBL_FREE(newEntry);
        return -1;
    }

    return 1;
}
Beispiel #2
0
int pblHtRemove(
pblHashTable_t            * h,     /** hash table to remove from           */
void                      * key,   /** OPT: key to remove                  */
size_t                      keylen /** OPT: length of that key             */
)
{
    pbl_hashtable_t  * ht = ( pbl_hashtable_t * )h;
    pbl_hashbucket_t * bucket = 0;
    pbl_hashitem_t   * item = 0;

    int                hashval = 0;

    if( keylen && key )
    {
        hashval = hash( key, keylen );
        bucket = ht->buckets + hashval;

        for( item = bucket->head; item; item = item->bucketnext )
        {
            if(( item->keylen == keylen ) && !memcmp( item->key, key, keylen ))
            {
                break;
            }
        }
    }
    else
    {
        item = ht->current;

        if( item )
        {
            hashval = hash( item->key, item->keylen );
            bucket = ht->buckets + hashval;
        }
    }

    if( item )
    {
        if( item == ht->current )
        {
            ht->currentdeleted = 1;
            ht->current = item->next;
        }

        /*
         * unlink the item
         */
        PBL_LIST_UNLINK( bucket->head, bucket->tail, item,
                         bucketnext, bucketprev );
        PBL_LIST_UNLINK( ht->head, ht->tail, item, next, prev );

        PBL_FREE( item->key );
        PBL_FREE( item );
        return( 0 );
    }

    pbl_errno = PBL_ERROR_NOT_FOUND;
    return( -1 );
}
Beispiel #3
0
/**
 * create a new hash table
 *
 * @return pblHashTable_t * retptr != NULL: pointer to new hash table
 * @return pblHashTable_t * retptr == NULL: OUT OF MEMORY
 */
pblHashTable_t * pblHtCreate( void )
{
    pbl_hashtable_t * ht;

    ht = pbl_malloc0( "pblHtCreate hashtable", sizeof( pbl_hashtable_t ) );
    if( !ht )
    {
        return( 0 );
    }

    ht->buckets = pbl_malloc0( "pblHtCreate buckets",
                               sizeof( pbl_hashbucket_t ) * PBL_HASHTABLE_SIZE);
    if( !ht->buckets )
    {
        PBL_FREE( ht );
        return( 0 );
    }

    /*
     * set the magic marker of the hashtable
     */
    ht->magic = rcsid;

    return( ( pblHashTable_t * )ht );
}
Beispiel #4
0
/**
 * Adds the element with the specified priority to the
 * end of the priority queue without ensuring the
 * heap condition.
 *
 * This function has a time complexity of O(1).
 *
 * This function together with \Ref{pblPriorityQueueConstruct}()
 * can be used to build a priority queue with N elements
 * in time proportional to N.
 *
 * First create an empty queue with \Ref{pblPriorityQueueNew}()
 * and ensure the queue has space for N elements via a
 * call to \Ref{pblPriorityQueueEnsureCapacity}(),
 * then add all elements via calls to this function
 * and finally ensure the heap condition with a call
 * to \Ref{pblPriorityQueueConstruct}().
 *
 * @return int rc >= 0: The size of the queue.
 * @return int rc <  0: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_MEMORY - Out of memory.
 */
int pblPriorityQueueAddLast( /*                       */
PblPriorityQueue * queue, /** The queue to use        */
int priority, /** Priority of the element to be added */
void * element /** Element to be added to the queue   */
)
{
	int rc;
	PblPriorityQueueEntry *newEntry = (PblPriorityQueueEntry *) pbl_malloc("pblPriorityQueueAddLast",
			sizeof(PblPriorityQueueEntry));
	if (!newEntry)
	{
		return -1;
	}

	newEntry->element = element;
	newEntry->priority = priority;

	rc = pblHeapAddLast((PblHeap *) queue, newEntry);
	if (rc < 0)
	{
		PBL_FREE(newEntry);
		return rc;
	}

	return pblHeapSize((PblHeap *) queue);
}
/**
 * Returns a reverse iterator over the elements in this collection in proper sequence.
 *
 * The reverse iterator starts the iteration at the end of the collection.
 *
 * <B>Note:</B> The memory allocated by this method for the iterator returned needs to be released
 *       by calling pblIteratorFree() once the iterator is no longer needed.
 *
 * The iterators returned by the this method are fail-fast:
 * if the collection is structurally modified at any time after the iterator is created,
 * in any way except through the Iterator's own remove or add methods,
 * the iterator will return a PBL_ERROR_CONCURRENT_MODIFICATION error.
 *
 * Thus, in the face of concurrent modification,
 * the iterator fails quickly and cleanly,
 * rather than risking arbitrary, non-deterministic
 * behavior at an undetermined time in the future.
 *
 * This method has a time complexity of O(1).
 *
 * @return void * retptr != NULL: The iterator.
 * @return void * retptr == NULL: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_MEMORY      - Out of memory.
 * <BR>PBL_COLLECTION_IS_COLLECTION - The collection cannot be iterated.
 */
PblIterator * pblIteratorReverseNew(
PblCollection * collection          /** The collection to create the iterator for */
)
{
    PblIterator * iterator;

    if( !PBL_COLLECTION_IS_COLLECTION( collection ) )
    {
        pbl_errno = PBL_ERROR_PARAM_COLLECTION;
        return NULL;
    }

    iterator = pbl_malloc( "pblIteratorReverseNew", sizeof(PblIterator) );
    if( !iterator )
    {
        return NULL;
    }

    if( pblIteratorReverseInit( collection, iterator ) < 0 )
    {
        PBL_FREE( iterator );
        return NULL;
    }

    return (PblIterator *)iterator;
}
Beispiel #6
0
/**
 * Removes the last element from the priority queue,
 * maintaining the heap condition of the queue.
 *
 * <B>Note:</B> The last element is not guaranteed to be
 * the element with the lowest priority!
 *
 * This function has a time complexity of O(1).
 *
 * @return void* retptr != (void*)-1: The element removed.
 * @return void* retptr == (void*)-1: An error see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_BOUNDS - The queue is empty.
 */
void * pblPriorityQueueRemoveLast( /*                                     */
PblPriorityQueue * queue, /** The queue to use                            */
int * priority /** On return contains the priority of the element removed */
)
{
	void * retptr;
	PblPriorityQueueEntry *lastEntry = (PblPriorityQueueEntry *) pblHeapRemoveLast((PblHeap *) queue);

	if (lastEntry == (PblPriorityQueueEntry *) -1)
	{
		return (void*) -1;
	}

	retptr = lastEntry->element;
	if (priority)
	{
		*priority = lastEntry->priority;
	}

	PBL_FREE(lastEntry);

	// Removing the last entry cannot break the heap condition!
	//
	return retptr;
}
Beispiel #7
0
int pblHtInsert(
pblHashTable_t          * h,      /** hash table to insert to             */
void                    * key,    /** key to insert                       */
size_t                    keylen, /** length of that key                  */
void                    * dataptr /** dataptr to insert                   */
)
{
    pbl_hashtable_t  * ht = ( pbl_hashtable_t * )h;
    pbl_hashbucket_t * bucket = 0;
    pbl_hashitem_t   * item = 0;

    int                hashval = hash( key, keylen );
    
    bucket = ht->buckets + hashval;

    if( keylen < (size_t)1 )
    {
        /*
         * the length of the key can not be smaller than 1
         */
        pbl_errno = PBL_ERROR_EXISTS;
        return( -1 );
    }

    for( item = bucket->head; item; item = item->bucketnext )
    {
        if(( item->keylen == keylen ) && !memcmp( item->key, key, keylen ))
        {
            snprintf( pbl_errstr, PBL_ERRSTR_LEN,
                      "insert of duplicate item in hashtable\n" );
            pbl_errno = PBL_ERROR_EXISTS;
            return( -1 );
        }
    }

    item = pbl_malloc0( "pblHtInsert hashitem", sizeof( pbl_hashitem_t ) );
    if( !item )
    {
        return( -1 );
    }

    item->key = pbl_memdup( "pblHtInsert item->key", key, keylen );
    if( !item->key )
    {
        PBL_FREE( item );
        return( -1 );
    }
    item->keylen = keylen;
    item->data = dataptr;

    /*
     * link the item
     */
    PBL_LIST_APPEND( bucket->head, bucket->tail, item, bucketnext, bucketprev );
    PBL_LIST_APPEND( ht->head, ht->tail, item, next, prev );

    ht->current = item;
    return( 0 );
}
/**
 * Removes all of the mappings from this map and frees the map's memory from heap.
 *
 * For hash maps this method has a time complexity of O(N).
 * For tree maps this method has a time complexity of O(N * Log N).
 *
 * @return void
 */
void pblMapFree( /*                                              */
PblMap * map /**                                 The map to free */
)
{
    pblMapClear( map );
    pblSetFree( map->entrySet );
    PBL_FREE(map);
}
Beispiel #9
0
int pblHtDelete(
pblHashTable_t * h        /** hash table to delete */
)
{
    pbl_hashtable_t  * ht = ( pbl_hashtable_t * )h;

    if( ht->head )
    {
        pbl_errno = PBL_ERROR_EXISTS;
        return( -1 );
    }

    PBL_FREE( ht->buckets );
    PBL_FREE( ht );

    return( 0 );
}
/**
 * Removes all of the mappings from this map. The map will be empty after this call returns.
 *
 * <B>Note:</B> The memory of the entries cleared is freed.
 *
 * For hash maps this method has a time complexity of O(N).
 * For tree maps this method has a time complexity of O(N * Log N).
 *
 * @return void
 */
void pblMapClear( /*                                               */
PblMap * map /**                                  The map to clear */
)
{
    void * ptr;
    while( pblSetSize( map->entrySet ) > 0 )
    {
        ptr = pblSetRemove( map->entrySet );
        PBL_FREE(ptr);
    }
}
/**
 * Removes the mapping for this key from this map if it is present.
 *
 * More formally, if this map contains a mapping from a key k to a value v such that
 * (key==null ? k==null : memcmp( key, k, keyLength ) == 0,
 * that mapping is removed.
 * (The map can contain at most one such mapping.)
 *
 * Returns the previous value associated with key,
 * NULL if there was no mapping for key
 * or (void*)-1 in case of an error.
 *
 * Note: If a valid pointer to a value is returned, the value returned is
 * malloced on the heap. It is the caller's responsibility to free that memory
 * once it is no longer needed.
 *
 * For hash maps this method has a time complexity of O(1).
 * For tree maps this method has a time complexity of O(Log N).
 *
 * @return void * retptr != (void*)-1: The previously associated value.
 * @return void * retptr == (void*)-1: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_MEMORY - Out of memory.
 */
void * pblMapRemove( /*                                             */
PblMap * map, /**                            The map to remove from */
void * key, /**                    Key whose association is removed */
size_t keyLength, /**                             Length of the key */
size_t * valueLengthPtr /**       Out: Length of the value returned */
)
{
    PblMapEntry * mapEntry;
    void * retptr = NULL;
    PblMapKey mapKey;

    mapKey.tag = PBL_MAP_KEY_TAG;
    mapKey.keyLength = keyLength;
    mapKey.key = key;

    mapEntry = (PblMapEntry *)pblSetGetElement( map->entrySet, &mapKey );
    if( !mapEntry )
    {
        if( valueLengthPtr )
        {
            *valueLengthPtr = 0;
        }
        return NULL;
    }

    if( mapEntry->valueLength > 0 )
    {
        retptr = pbl_memdup( "pblMapRemove", mapEntry->buffer
                + mapEntry->keyLength, mapEntry->valueLength );
    }
    else
    {
        retptr = pbl_malloc0( "pblMapRemove0", 1 );
    }
    if( !retptr )
    {
        if( valueLengthPtr )
        {
            *valueLengthPtr = 0;
        }
        return (void*)-1;
    }

    if( valueLengthPtr )
    {
        *valueLengthPtr = mapEntry->valueLength;
    }

    pblSetRemoveElement( map->entrySet, mapEntry );

    PBL_FREE( mapEntry );

    return retptr;
}
Beispiel #12
0
/**
 * Removes all of the elements from the priority queue.
 *
 * <B>Note:</B> No memory of the elements themselves is freed.
 *
 * This function has a time complexity of O(N),
 * with N being the number of elements in the priority queue.
 *
 * @return void
 */
void pblPriorityQueueClear( /*                  */
PblPriorityQueue * queue /** The queue to clear */
)
{
	int index;

	// Loop over the heap and free the entries allocated
	// by pblPriorityQueueAddLast()
	//
	for (index = pblHeapSize((PblHeap *) queue) - 1; index >= 0; index--)
	{
		void * ptr = pblHeapGet((PblHeap *) queue, index);
		if (ptr != (void*) -1)
		{
			PBL_FREE(ptr);
		}
	}
	pblHeapClear((PblHeap *) queue);
}
/**
 * Creates a new hash map.
 *
 * This method has a time complexity of O(1).
 *
 * @return PblMap * retPtr != NULL: A pointer to the new map.
 * @return PblMap * retPtr == NULL: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_MEMORY - Out of memory.
 */
PblMap * pblMapNewHashMap( void )
{
    PblMap * pblMap = (PblMap *)pbl_malloc0( "pblMapNewHashMap", sizeof(PblMap) );
    if( !pblMap )
    {
        return NULL;
    }

    pblMap->entrySet = pblSetNewHashSet();
    if( !pblMap->entrySet )
    {
        PBL_FREE( pblMap );
        return NULL;
    }

    pblSetSetCompareFunction( pblMap->entrySet, pblMapEntryCompareFunction );
    pblSetSetHashValueFunction( pblMap->entrySet, pblMapEntryHashValue );

    return pblMap;
}
Beispiel #14
0
/**
 * Removes the element at the specified position from the
 * priority queue, maintaining the heap condition of the queue.
 *
 * This function has a time complexity of O(Log N),
 * with N being the number of elements in the queue.
 *
 * @return void* retptr != (void*)-1: The element removed.
 * @return void* retptr == (void*)-1: An error see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_BOUNDS - Index is out of range (index < 0 || index >= size()).
 */
void * pblPriorityQueueRemoveAt( /*                                       */
PblPriorityQueue * queue, /** The queue to use                            */
int index, /** The index at which the element is to be removed            */
int * priority /** On return contains the priority of the element removed */
)
{
	void * retptr;
	PblPriorityQueueEntry *entry = pblHeapRemoveAt((PblHeap *) queue, index);
	if (entry == (PblPriorityQueueEntry *) -1)
	{
		return (void*) -1;
	}

	retptr = entry->element;
	if (priority)
	{
		*priority = entry->priority;
	}

	PBL_FREE(entry);

	return retptr;
}
/**
 * Frees the memory used by the iterator.
 *
 * This method has a time complexity of O(1).
 *
 * Must be called once the iterator is no longer needed.
 */
void pblIteratorFree(
PblIterator * iterator /** The iterator to free */
)
{
    PBL_FREE(iterator);
}
/**
 * Removes from the underlying list or tree set the last element returned by the iterator.
 *
 * This method can be called only once per call to next or previous.
 * It can be made only if pblIteratorAdd() has not been called after the last call to next or previous.
 *
 * For array lists this method has a time complexity of O(N),
 * with N being the number of elements in the underlying list.
 *
 * For linked lists and hash sets this method has a time complexity of O(1).
 *
 * For tree sets this method has a time complexity of O(Log N),
 * with N being the number of elements in the underlying collection.
 *
 * @return int rc >= 0: The size of the collection.
 * @return int rc <  0: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_NOT_ALLOWED - The the next or previous method has not yet been called,
 *                         or the remove method has already been called after the last call to the next or previous method.
 *
 * <BR>PBL_ERROR_CONCURRENT_MODIFICATION - The underlying list or tree set was modified concurrently.
 * <BR>PBL_ERROR_PARAM_LIST              - The underlying collection is neither a list nor a tree set.
 */
int pblIteratorRemove(
PblIterator * iterator /** The iterator to remove the next element from */
)
{
    if( iterator->changeCounter != iterator->collection->changeCounter )
    {
        pbl_errno = PBL_ERROR_CONCURRENT_MODIFICATION;
        return -1;
    }

    if( PBL_SET_IS_TREE_SET( iterator->collection ) )
    {
        PblTreeIterator * treeIterator = (PblTreeIterator *)iterator;

        if( !treeIterator->current )
        {
            pbl_errno = PBL_ERROR_NOT_ALLOWED;
            return -1;
        }
        else
        {
            if( treeIterator->next == treeIterator->current )
            {
                treeIterator->next = pblTreeNodeNext( treeIterator->next );
            }
            else if( treeIterator->prev == treeIterator->current )
            {
                treeIterator->prev = pblTreeNodePrevious( treeIterator->prev );
            }

            pblSetRemoveElement( (PblSet*)treeIterator->collection,
                                 treeIterator->current->element );
        }
    }
    else if( PBL_LIST_IS_LINKED_LIST( iterator->collection ) )
    {
        if( !iterator->current )
        {
            pbl_errno = PBL_ERROR_NOT_ALLOWED;
            return -1;
        }
        else
        {
            PblLinkedList * linkedList = (PblLinkedList *)iterator->collection;
            PblLinkedNode * nodeToFree = iterator->current;

            if( iterator->next == iterator->current )
            {
                iterator->next = iterator->next->next;
            }
            else if( iterator->prev == iterator->current )
            {
                iterator->prev = iterator->prev->prev;
            }

            PBL_LIST_UNLINK( linkedList->head, linkedList->tail, nodeToFree, next, prev );
            linkedList->genericList.size--;
            linkedList->genericList.changeCounter++;

            PBL_FREE( nodeToFree );
        }
    }
    else if( PBL_LIST_IS_ARRAY_LIST( iterator->collection ) )
    {
        if( iterator->lastIndexReturned < 0 )
        {
            pbl_errno = PBL_ERROR_NOT_ALLOWED;
            return -1;
        }

        if( pblArrayListRemoveAt( (PblArrayList*)iterator->collection,
                                  iterator->lastIndexReturned ) == (void*)-1 )
        {
            return -1;
        }
    }
    else
    {
        pbl_errno = PBL_ERROR_PARAM_LIST;
        return -1;
    }

    if( iterator->lastIndexReturned < iterator->index )
    {
        iterator->index--;
    }

    iterator->current = NULL;
    iterator->lastIndexReturned = -1;

    iterator->changeCounter = iterator->collection->changeCounter;

    return iterator->collection->size;
}
Beispiel #17
0
/*
 * Test frame for the map library
 *
 * this test frame calls the map library,
 * it does not have any parameters, it is meant for
 * debugging the map library
 */
int pblMap_TestFrame( int argc, char * argv[ ] )
{
    PblMap * map;
    int rc;

    char * data;

    map = pblMapNewTreeMap();
    fprintf( stdout, "pblMapNewTreeMap() map = %p\n", map );

    rc = pblMapIsEmpty( map );
    fprintf( stdout, "pblMapIsEmpty( map ) rc = %d\n", rc );

    rc = pblMapAddStrStr( map, "123", "123_1" );
    fprintf( stdout, "pblMapAddStrStr( map, 123, 123_1 ) rc = %d\n", rc );

    rc = pblMapContainsKeyStr( map, "123" );
    fprintf( stdout, "pblMapContainsKeyStr( map, 123 ) rc = %d\n", rc );

    rc = pblMapAddStrStr( map, "123", "123_2" );
    fprintf( stdout, "pblMapAddStrStr( map, 123, 123_2 ) rc = %d\n", rc );

    rc = pblMapContainsKeyStr( map, "123" );
    fprintf( stdout, "pblMapContainsKeyStr( map, 123 ) rc = %d\n", rc );

    rc = pblMapAddStrStr( map, "124", "124" );
    fprintf( stdout, "pblMapAddStrStr( map, 124, 124 ) rc = %d\n", rc );

    rc = pblMapContainsKeyStr( map, "124" );
    fprintf( stdout, "pblMapContainsKeyStr( map, 124 ) rc = %d\n", rc );

    rc = pblMapContainsKeyStr( map, "not there" );
    fprintf( stdout, "pblMapContainsKeyStr( map, not there ) rc = %d\n", rc );

    rc = pblMapContainsValueStr( map, "124" );
    fprintf( stdout, "pblMapContainsValueStr( map, 124 ) rc = %d\n", rc );

    rc = pblMapContainsValueStr( map, "not there" );
    fprintf( stdout, "pblMapContainsValueStr( map, not there ) rc = %d\n", rc );

    data = (char*)pblMapGetStr( map, "123" );
    fprintf( stdout, "pblMapGetStr( map, 123 ) data = %s\n",
             data );

    data = (char*)pblMapGetStr( map, "124" );
    fprintf( stdout, "pblMapGetStr( map, 124 ) data = %s\n",
    		data );

    data = (char*)pblMapGetStr( map, "not there" );
    fprintf( stdout,
             "pblMapGetStr( map, not there ) data = %p\n",
             data );

    data = (char*)pblMapPutStrStr( map, "123", "123_3" );
    fprintf(
             stdout,
             "pblMapPutStrStr( map, 123, 123_3 ) data = %s\n",
             data );
    PBL_FREE(data);

    data = (char*)pblMapGetStr( map, "123" );
    fprintf( stdout, "pblMapGetStr( map, 123 ) data = %s\n",
    		data );

    data = (char*)pblMapPutStrStr( map, "125", "125" );
    fprintf( stdout,
             "pblMapPutStrStr( map, 125, 125 ) data = %p\n",
             data );
    PBL_FREE(data);

    data = (char*)pblMapRemoveStr( map, "125" );
    fprintf( stdout,
             "pblMapRemoveStr( map, 125 ) data = %s\n",
             data );
	PBL_FREE(data);

    data = (char*)pblMapRemoveStr( map, "not there" );
    fprintf( stdout,
             "pblMapRemoveStr( map, not there ) data = %p\n",
             data );

    rc = pblMapSize( map );
    fprintf( stdout, "pblMapSize( map ) rc = %d\n", rc );

    rc = pblMapIsEmpty( map );
    fprintf( stdout, "pblMapIsEmpty( map ) rc = %d\n", rc );

    pblMapFree( map );
    fprintf( stdout, "pblMapFree( map ) \n" );

    return rc;
}
/**
 * Associates the specified value with the specified key in this map.
 *
 * If the map previously contained a mapping for the key, the old value is replaced by the specified value.
 * (A map m is said to contain a mapping for a key k if and only if pblMapContainsKey(k) would return true.)
 *
 * Returns the previous value associated with key, NULL if there was no mapping for key
 * or (void*)-1 in case of an error.
 *
 * Note: If a valid pointer to a value is returned, the value returned is
 * malloced on the heap. It is the caller's responsibility to free that memory
 * once it is no longer needed.
 *
 * For hash maps this method has a time complexity of O(1).
 * For tree maps this method has a time complexity of O(Log N).
 *
 * @return void * retptr != (void*)-1: The previously associated value.
 * @return void * retptr == NULL: There was no previously associated value.
 * @return void * retptr == (void*)-1: An error, see pbl_errno:
 *
 * <BR>PBL_ERROR_OUT_OF_MEMORY - Out of memory.
 * <BR>PBL_ERROR_OUT_OF_BOUNDS - Maximum capacity of the hash set exceeded.
 */
void * pblMapPut( /*                                                   */
PblMap * map, /**                                    The map to add to */
void * key, /**                               Key to add a mapping for */
size_t keyLength, /**                                Length of the key */
void * value, /**                             Value of the new mapping */
size_t valueLength, /**                            Length of the value */
size_t * valueLengthPtr /**          Out: Length of the value returned */
)
{
    int rc;
    PblMapEntry * mapEntry;
    PblMapEntry * newEntry =
            pblMapEntryNew( key, keyLength, value, valueLength );
    if( !newEntry )
    {
        return (void*)-1;
    }

    mapEntry = (PblMapEntry *)pblSetReplaceElement( map->entrySet, newEntry );
    if( mapEntry )
    {
        void * retptr;

        if( mapEntry->valueLength > 0 )
        {
            retptr = pbl_memdup( "pblMapPut", mapEntry->buffer
                    + mapEntry->keyLength, mapEntry->valueLength );
        }
        else
        {
            retptr = pbl_malloc0( "pblMapPut0", 1 );
        }
        if( !retptr )
        {
            if( valueLengthPtr )
            {
                *valueLengthPtr = 0;
            }
            pblSetReplaceElement( map->entrySet, mapEntry );
            PBL_FREE( newEntry );
            return (void*)-1;
        }

        if( valueLengthPtr )
        {
            *valueLengthPtr = mapEntry->valueLength;
        }
        PBL_FREE( mapEntry );
        return retptr;
    }

    if( valueLengthPtr )
    {
        *valueLengthPtr = 0;
    }

    rc = pblSetAdd( map->entrySet, newEntry );
    if( rc < 0 )
    {
        PBL_FREE(newEntry);
        return (void*)-1;
    }

    return NULL;
}