/** * 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; }
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 ); }
/** * 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 ); }
/** * 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; }
/** * 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; }
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); }
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; }
/** * 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; }
/** * 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; }
/* * 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; }