/*----------------------------------------------------------- * Name: LL_RemoveFn() * Created: Fri Sep 2 03:43:24 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: removes an item from the list, * destroying it with function fn */ void LL_RemoveFn(LINKED_LIST *ll, DATA_PTR data, LL_DestroyProc destroy) { if (ll->attr & LL_Intrusive) { if (NextP(ll, data)) PrevP(ll, NextP(ll, data)) = PrevP(ll, data); else ll->tail.data = PrevP(ll, data); if (PrevP(ll, data)) NextP(ll, PrevP(ll, data)) = NextP(ll, data); else ll->head.data = NextP(ll, data); } else { /* Container */ LL_CONTAINER *cont; LLMacro_GetContainer(ll, cont, data); if (!cont) { return; } if (ll->last == cont) { /* last can no longer point to this item */ if (cont->prev) ll->last = cont->prev; else ll->last = cont->next; } if (cont->next) cont->next->prev = cont->prev; else ll->tail.cont = cont->prev; if (cont->prev) cont->prev->next = cont->next; else ll->head.cont = cont->next; irrd_free(cont); } ll->count--; if (destroy) { (destroy)(data); } }
/*----------------------------------------------------------- * Name: LList_GetNext() * Created: Fri Sep 2 20:22:52 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: gets the next item on a list */ DATA_PTR LList_GetNext(LINKED_LIST *ll, DATA_PTR data) { DATA_PTR ret; if (ll->attr & LL_Intrusive) { if (data) { ret = NextP(ll, data); } else { ret = ll->head.data; } } else { LL_CONTAINER *cont = NULL; if (data) { LLMacro_GetContainer(ll, cont, data); ll->last = cont->next; if (cont->next) ret = cont->next->data; else ret = NULL; } else { ll->last = ll->head.cont; if (ll->head.cont) ret = ll->head.cont->data; else ret = NULL; } } return(ret); }
/*----------------------------------------------------------- * Name: LL_InsertAfter() * Created: Fri Sep 2 01:51:07 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: inserts a data element after another elt. * before is the item "before me" or * the item which i am to follow * i.e. i am the item after BEFORE */ DATA_PTR LL_InsertAfter(LINKED_LIST *ll, DATA_PTR data, DATA_PTR before) { if (ll->attr & LL_Intrusive) { DATA_PTR after; if (before) { after = NextP(ll, before); } else { /* if !before */ after = ll->head.data; } LLMacro_IntrPlaceBetween(ll, data, before, after); } else { /* Container */ LL_CONTAINER *after_cont, *before_cont, *cont; cont = irrd_malloc(sizeof(LL_CONTAINER)); if (!cont) { return(NULL); } if (before) { LLMacro_GetContainer(ll, before_cont, before); after_cont = before_cont->next; } else { after_cont = ll->head.cont; before_cont = NULL; } cont->data = data; LLMacro_ContPlaceBetween(ll, cont, before_cont, after_cont); ll->last = cont; } ll->count++; return(data); }
/*----------------------------------------------------------- * Name: HASH_ClearFn() * Created: Thu Sep 8 14:56:40 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: clears all items from a hash table */ void HASH_ClearFn(HASH_TABLE* h, HASH_DestroyProc destroy) { int index; #ifdef HASH_DEBUG if (!h) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_Clear()"); } return; } #endif if (h->attr & HASH_Intrusive) { DATA_PTR data; for (index = 0; index < h->size; index++) { /* Run thru all the indicies */ while ((data = h->array.data[index])) { /* each item on list */ h->array.data[index] = NextP(h, data); #ifdef HASH_DEBUG NextP(h, data) = NULL; #endif if (destroy) { (destroy)(data); } } } } else { HASH_CONTAINER *cont; for (index = 0; index < h->size; index++) { /* Run thru all the indicies */ while ((cont = h->array.cont[index])) { /* each item on list */ h->array.cont[index] = cont->next; if (destroy) { (destroy)(cont->data); } #ifdef HASH_DEBUG cont->next = NULL; cont->data = NULL; #endif Delete(cont); } } } h->count = 0; #ifdef HASH_DEBUG if (h->attr & HASH_ReportChange) { printf("HASH TABLE: 0x%.8x Clear(0x%.8x)\n", h, destroy); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif }
/*----------------------------------------------------------- * Name: HASH_ToArray() * Created: Thu Sep 8 23:49:47 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: reallocates array and coverts the hash table into it */ DATA_PTR *HASH_ToArray(HASH_TABLE *h, DATA_PTR *array, unsigned *size) { unsigned index; unsigned array_index = 0; #ifdef HASH_DEBUG if (!h) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_ToArray()"); } } #endif if (!array) { array = NewArray(DATA_PTR, h->count); if (!array) { if (HASH_Handler) { (HASH_Handler)(h, HASH_MemoryErr, "HASH_ToArray()"); } return(NULL); } } if (h->attr & HASH_Intrusive) { DATA_PTR data; for (index = 0; index < h->size; index++) { for (data = h->array.data[index]; data; data = NextP(h, data)) { array[array_index++] = data; } } } else { HASH_CONTAINER *cont; for (index = 0; index < h->size; index++) { for (cont = h->array.cont[index]; cont; cont = cont->next) { array[array_index++] = cont->data; } } } #ifdef HASH_DEBUG if (h->attr & HASH_ReportAccess) { printf("HASH TABLE: 0x%.8x ToArray(0x%.8x, %u) count\n", h, array, h->count); } #endif if (size) *size = h->count; #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif return(array); }
/*----------------------------------------------------------- * Name: HASH_Lookup() * Created: Thu Sep 8 20:23:56 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: looks up an item in the hash table */ DATA_PTR HASH_Lookup(HASH_TABLE* h, DATA_PTR key) { unsigned index; DATA_PTR data; #ifdef HASH_DEBUG if (!h || !key) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_Lookup()"); } return(NULL); } #endif index = (h->hash)(key, h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_Lookup()"); } return(NULL); } #endif if (h->attr & HASH_Intrusive) { for (data = h->array.data[index]; data; data = NextP(h, data)) { if ((h->lookup)(KeyP(h, data), key)) break; } } else { HASH_CONTAINER *cont; for (cont = h->array.cont[index]; cont; cont = cont->next) { if ((h->lookup)(KeyP(h, cont->data), key)) break; } if (cont) data = cont->data; else data = NULL; } #ifdef HASH_DEBUG if (h->attr & HASH_ReportAccess) { if (data) printf("HASH TABLE: 0x%.8x Lookup(0x%.8x) = 0x%.8x\n", h, key, data); else printf("HASH TABLE: 0x%.8x Lookup(0x%.8x) = NULL\n", h, key); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif return(data); }
/*----------------------------------------------------------- * Name: HASH_ProcessPlus() * Created: Thu Sep 8 20:42:48 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: process a hash table with second argument */ void HASH_ProcessPlus(HASH_TABLE *h, HASH_ProcessPlusProc fn, DATA_PTR arg2) { unsigned index; #ifdef HASH_DEBUG if (!h || !fn) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_ProcessPlus()"); } return; } if (h->attr & HASH_ReportAccess) { printf("HASH TABLE: 0x%.8x ProcessPlus(0x%.8x, 0x%.8x) started\n", h, fn, arg2); } #endif if (h->attr & HASH_Intrusive) { DATA_PTR data; for (index = 0; index < h->size; index++) { for (data = h->array.data[index]; data; data = NextP(h, data)) { (fn)(data, arg2); } } } else { HASH_CONTAINER *cont; for (index = 0; index < h->size; index++) { for (cont = h->array.cont[index]; cont; cont = cont->next) { (fn)(cont->data, arg2); } } } #ifdef HASH_DEBUG if (h->attr & HASH_ReportAccess) { printf("HASH TABLE: 0x%.8x ProcessPlus(0x%.8x, 0x%.8x) complete\n", h, fn, arg2); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif }
/*----------------------------------------------------------- * Name: HASH_ToLinkedList() * Created: Fri Sep 9 00:01:14 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: converts a hash table to a linked list */ LINKED_LIST *HASH_ToLinkedList(HASH_TABLE *h, LINKED_LIST *ll) { unsigned index; #ifdef HASH_DEBUG if (!h) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_ToLinkedList()"); } } #endif if (!ll) ll = LL_Create(0); if (h->attr & HASH_Intrusive) { DATA_PTR data; for (index = 0; index < h->size; index++) { for (data = h->array.data[index]; data; data = NextP(h, data)) { LL_Add(ll, data); } } } else { HASH_CONTAINER *cont; for (index = 0; index < h->size; index++) { for (cont = h->array.cont[index]; cont; cont = cont->next) { LL_Add(ll, cont->data); } } } #ifdef HASH_DEBUG if (h->attr & HASH_ReportAccess) { printf("HASH TABLE: 0x%.8x ToLinkedList(0x%.8x) complete\n", h, ll); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif return(ll); }
/*----------------------------------------------------------- * Name: HASH_ReHash() * Created: Thu Sep 8 17:09:25 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: re-hashes an item, due to change in key. */ void HASH_ReHash(HASH_TABLE *h, DATA_PTR data, DATA_PTR old_key) { unsigned index; DATA_PTR key; #ifdef HASH_DEBUG if (!h || !data || !old_key) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_ReHash()"); } return; } #endif key = KeyP(h, data); #ifdef HASH_DEBUG if (!key) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_ReHash()"); } return; } #endif index = (h->hash)(old_key, h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_ReHash()"); } return; } #endif if (h->attr & HASH_Intrusive) { DATA_PTR prev, tmp; for (tmp = h->array.data[index], prev = NULL; tmp && tmp != data; prev = tmp, tmp = NextP(h, tmp)); #ifdef HASH_DEBUG if (tmp) { if (HASH_Handler) { (HASH_Handler)(h, HASH_NoMember, "HASH_ReHash()"); } return; } #endif if (prev) { NextP(h, prev) = NextP(h, data); } else { h->array.data[index] = NextP(h, data); } NextP(h, data) = NULL; index = (h->hash)(key, h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_ReHash()"); } return; } #endif if (h->array.data[index]) NextP(h, data) = h->array.data[index]; h->array.data[index] = data; } else { HASH_CONTAINER *prev, *tmp; for (tmp = h->array.cont[index], prev = NULL; tmp && tmp->data != data; prev = tmp, tmp = tmp->next); #ifdef HASH_DEBUG if (tmp) { if (HASH_Handler) { (HASH_Handler)(h, HASH_NoMember, "HASH_Remove()"); } return; } #endif if (prev) { prev->next = tmp->next; } else { h->array.cont[index] = tmp->next; } tmp->next = NULL; index = (h->hash)(key, h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_Remove()"); } return; } #endif if (h->array.cont[index]) tmp->next = h->array.cont[index]; h->array.cont[index] = tmp; } #ifdef HASH_DEBUG if (h->attr & HASH_ReportChange) { printf("HASH TABLE: 0x%.8x ReHash(0x%.8x, 0x%.8x, 0x%.8x)\n", h, data, old_key, key); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif }
/*----------------------------------------------------------- * Name: HASH_RemoveByKeyFn() * Created: Thu Sep 8 16:11:12 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: removes an item from a hash table given key <key> */ void HASH_RemoveByKeyFn(HASH_TABLE *h, DATA_PTR key, HASH_DestroyProc destroy) { unsigned index; DATA_PTR data; #ifdef HASH_DEBUG if (!h || !key) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_RemoveByKey()"); } return; } #endif index = (h->hash)(key, h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_RemoveByKey()"); } return; } #endif if (h->attr & HASH_Intrusive) { DATA_PTR prev; for (data = h->array.data[index], prev = NULL; data; prev = data, data = NextP(h, data)) { if ((h->lookup)(KeyP(h, data), key)) break; /* found it */ } #ifdef HASH_DEBUG if (!data) { if (HASH_Handler) { (HASH_Handler)(h, HASH_NoMember, "HASH_RemoveByKey()"); } return; } #endif if (prev) { NextP(h, prev) = NextP(h, data); } else { h->array.data[index] = NextP(h, data); } #ifdef HASH_DEBUG NextP(h, data) = NULL; #endif if (destroy) { (destroy)(data); } } else { HASH_CONTAINER *cont, *prev; for (cont = h->array.cont[index], prev = NULL; cont; prev = cont, cont = cont->next) { if ((h->lookup)(KeyP(h, cont->data), key)) break; /* Found it */ } #ifdef HASH_DEBUG if (!cont) { if (HASH_Handler) { (HASH_Handler)(h, HASH_NoMember, "HASH_Remove()"); } return; } #endif if (!cont) /* JW 6/1/98 fix for case when item not found */ return; if (prev) { prev->next = cont->next; } else { h->array.cont[index] = cont->next; } data = cont->data; if (destroy) { (destroy)(cont->data); } #ifdef HASH_DEBUG cont->next = NULL; cont->data = NULL; #endif Delete(cont); } h->count--; #ifdef HASH_DEBUG if (h->attr & HASH_ReportChange) { printf("HASH TABLE: 0x%.8x RemoveByKey(0x%.8x, 0x%.8x) %u => 0x%.8x, count = %u\n", h, key, destroy, index, data, h->count); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif }
/*----------------------------------------------------------- * Name: HASH_RemoveFn() * Created: Thu Sep 8 16:11:12 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: removes an item from a hash table given key <key> */ void HASH_RemoveFn(HASH_TABLE *h, DATA_PTR data, HASH_DestroyProc destroy) { unsigned index; #ifdef HASH_DEBUG if (!h || !data) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_Remove()"); } return; } #endif index = (h->hash)(KeyP(h, data), h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_Remove()"); } return; } #endif if (h->attr & HASH_Intrusive) { DATA_PTR tmp, prev; /* Find Prev */ for (tmp = h->array.data[index], prev = NULL; tmp; prev = tmp, tmp = NextP(h, tmp)) { if (tmp == data) break; } #ifdef HASH_DEBUG if (!tmp) { if (HASH_Handler) { (HASH_Handler)(h, HASH_NoMember, "HASH_Remove()"); } return; } #endif if (prev) { NextP(h, prev) = NextP(h, data); } else { h->array.data[index] = NextP(h, data); } #ifdef HASH_DEBUG NextP(h, data) = NULL; #endif if (destroy) { (destroy)(data); } } else { HASH_CONTAINER *cont, *prev; for (cont = h->array.cont[index], prev = NULL; cont; prev = cont, cont = cont->next) { if (cont->data == data) break; } #ifdef HASH_DEBUG if (!cont) { if (HASH_Handler) { (HASH_Handler)(h, HASH_NoMember, "HASH_Remove()"); } return; } #endif if (prev) { prev->next = cont->next; } else { h->array.cont[index] = cont->next; } if (destroy) { (destroy)(cont->data); } #ifdef HASH_DEBUG cont->next = NULL; cont->data = NULL; #endif Delete(cont); } h->count--; #ifdef HASH_DEBUG if (h->attr & HASH_ReportChange) { printf("HASH TABLE: 0x%.8x Remove(0x%.8x, 0x%.8x) count = %u\n", h, data, destroy, h->count); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif }
/*----------------------------------------------------------- * Name: HASH_Insert() * Created: Thu Sep 8 15:37:07 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: insert an item into a table */ DATA_PTR HASH_Insert(HASH_TABLE* h, DATA_PTR data) { DATA_PTR key; unsigned index; #ifdef HASH_DEBUG if (!h || !data) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_Insert()"); } return(NULL); } #endif key = KeyP(h, data); #ifdef HASH_DEBUG if (!key) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_Insert()"); } return(NULL); } #endif /* check if we are going to have to re-hash the entire thing (dynamic) */ if ((h->resize) && (h->count >= (h->resize)*(h->size))) { /* we must resize */ unsigned new_size = h->size*2; HASH_ChangeSize(h, new_size); } index = (h->hash)(key, h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_Insert()"); } return(NULL); } #endif if (h->attr & HASH_Intrusive) { NextP(h, data) = h->array.data[index]; h->array.data[index] = data; } else { HASH_CONTAINER *cont = New(HASH_CONTAINER); if (!cont) { if (HASH_Handler) { (HASH_Handler)(h, HASH_MemoryErr, "HASH_Insert()"); } return(NULL); } cont->data = data; cont->next = h->array.cont[index]; h->array.cont[index] = cont; } h->count++; #ifdef HASH_DEBUG if (h->attr & HASH_ReportChange) { printf("HASH TABLE: 0x%.8x Insert(0x%.8x, 0x%.8x) (%u) count = %u\n", h, data, key, index, h->count); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif return(data); }
/*----------------------------------------------------------- * Name: HASH_ChangeSize() * Created: Mon Sep 26 20:09:16 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: modifies the size of the hash table to x */ void HASH_ChangeSize(HASH_TABLE *h, unsigned size) { unsigned index; #ifdef HASH_DEBUG if (!h || !size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_ChangeSize()"); } } if (h->attr & HASH_ReportChange) { printf("HASH TABLE: 0x%.8x Resizing to %u slots\n", h, size); } #endif if (h->attr & HASH_Intrusive) { DATA_PTR *array = NewArray(DATA_PTR, size); DATA_PTR moving; unsigned old; if (!array) { if (HASH_Handler) { (HASH_Handler)(h, HASH_MemoryErr, "HASH_ChangeSize()"); } return; } else { for (old = 0; old < h->size; old++) { while ((moving = h->array.data[old])) { h->array.data[old] = NextP(h, moving); index = (h->hash)(KeyP(h, moving), size); #ifdef HASH_DEBUG if (index >= size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_ChangeSize()"); } return; } #endif NextP(h, moving) = array[index]; array[index] = moving; } } Delete(h->array.data); h->array.data = array; } } else { HASH_CONTAINER **array = NewArray(HASH_CONTAINER*, size); HASH_CONTAINER *moving; unsigned old; if (!array) { if (HASH_Handler) { (HASH_Handler)(h, HASH_MemoryErr, "HASH_ChangeSize()"); } return; } else { for (old = 0; old < h->size; old++) { while ((moving = h->array.cont[old])) { h->array.cont[old] = moving->next; index = (h->hash)(KeyP(h, moving->data), size); #ifdef HASH_DEBUG if (index >= size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_ChangeSize()"); } return; } #endif moving->next = array[index]; array[index] = moving; } } Delete(h->array.cont); h->array.cont = array; } } h->size = size; }
/*----------------------------------------------------------- * Name: HASH_GetNext() * Created: Thu Sep 8 20:46:38 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: iteration support for hash tables * Modified to have last_cont in HASH_TABLE, instead of static. * still we CAN NOT do HASH_Iterate on the same hash_table, though. */ DATA_PTR HASH_GetNext(HASH_TABLE *h, DATA_PTR current) { unsigned index; DATA_PTR data; HASH_CONTAINER *cont = NULL; #ifdef HASH_DEBUG if (!h) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_Iterate()"); } return(NULL); } #endif if (!current) { /* Find first item */ for (index = 0; ((index < h->size) && (!(h->array.data[index]))); index++); if (index < h->size) { if (h->attr & HASH_Intrusive) { data = h->array.data[index]; } else { cont = h->array.cont[index]; data = cont->data; } } else { data = NULL; /* table is empty */ } } else { if (h->attr & HASH_Intrusive) { data = NextP(h, current); if (!data) { /* current was last one on last_index */ index = (h->hash)(KeyP(h, current), h->size); #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_Iterate()"); } return(NULL); } #endif for (index++; ((index < h->size) && (!(h->array.data[index]))); index++); if (index < h->size) data = h->array.data[index]; else data = NULL; /* current was last one in table */ } } else { #if 0 HASH_CONTAINER *cont; #endif if ((h->last_cont) && (h->last_cont->data == current)) cont = h->last_cont; else { /* LAST_CONTAINER is messed up ?? */ index = (h->hash)(KeyP(h, current), h->size); /* get index of current and find its cont */ #ifdef HASH_DEBUG if (index >= h->size) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadIndex, "HASH_Iterate()"); } return(NULL); } #endif for (cont = h->array.cont[index]; ((cont) && (cont->data != current)); cont = cont->next); } #ifdef HASH_DEBUG if (!cont) { /* failed to find current's container must have been deleted!!!! */ if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_Iterate()"); } return(NULL); } #endif if (!cont->next) { /* current was last one in index */ index = (h->hash)(KeyP(h, cont->data), h->size); for (index++; ((index < h->size) && (!(h->array.cont[index]))); index++); if (index < h->size) cont = h->array.cont[index]; else cont = NULL; /* current is the absolute LAST */ } else { cont = cont->next; } if (cont) data = cont->data; else data = NULL; } } h->last_cont = cont; #ifdef HASH_DEBUG if (h->attr & HASH_ReportAccess) { printf("HASH TABLE: 0x%.8x Iterate() currently at 0x%.8x\n", h, data); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif return(data); }