#include "munga.h" #pragma hdrstop #include "table.h" #include "node.h" #define VERIFY_INDEX(x) Verify(0 <= (x) && (x) < numItems) // //########################################################################### // TABLEENTRY //########################################################################### // TableEntry::TableEntry( Table *table, Plug *plug ): Link(table, plug) { } TableEntry::~TableEntry() { Table *table = Cast_Object(Table*, socket); IteratorPosition index; // //-------------------------------------- // Find the link in the table and remove //-------------------------------------- // index = table->SearchForTableEntry(this); table->RemoveNthTableEntry(index); // //-------------------------------------------- // Notify iterators that link is being deleted //-------------------------------------------- // table->SendIteratorMemo(PlugRemoved, &index); // //------------------------------------------ // Remove this link from any plug references //------------------------------------------ // ReleaseFromPlug(); // //------------------------------------------------------------- // Tell the node to release this link. Note that this link // is not referenced by the plug or the chain at this point in // time. //------------------------------------------------------------- // if (table->GetReleaseNode() != NULL) { Check(table->GetReleaseNode()); table->GetReleaseNode()->ReleaseLinkHandler(table, plug); } } // //########################################################################### // TABLE //########################################################################### // // //########################################################################### // Table //########################################################################### // Table::Table( Node *node, Logical has_unique_entries ): SortedSocket(node, has_unique_entries) { array = NULL; numItems = 0; } // //########################################################################### // ~Table //########################################################################### // Table::~Table() { SetReleaseNode(NULL); while (numItems > 0) { Check_Pointer(array); Check(array[0]); Unregister_Object(array[0]); delete array[0]; } Verify(numItems == 0); Verify(array == NULL); } // //########################################################################### // TestInstance //########################################################################### // Logical Table::TestInstance() const { SortedSocket::TestInstance(); if (numItems > 0 || array != NULL) { Verify(numItems > 0); Check_Pointer(array); } return True; } // //########################################################################### // AddImplementation //########################################################################### // void Table::AddImplementation(Plug *plug) { AddValueImplementation(plug, NULL); } // //########################################################################### // AddValueImplementation //########################################################################### // void Table::AddValueImplementation( Plug *plug, const void *value ) { TableEntry *link; /* * Verify that value has not been added */ Verify(HasUniqueEntries() ? (SearchForValue(value) == TableNullIndex) : (Logical)True); /* * Make new table entry */ link = MakeTableEntry(plug, value); Register_Object(link); /* * Add, sort and send memo to iterators to update references */ AddTableEntry(link); SortTableEntries(); SendIteratorMemo(PlugAdded, link); } // //########################################################################### // FindImplementation //########################################################################### // Plug* Table::FindImplementation( const void *value ) { IteratorPosition index; if ((index = SearchForValue(value)) != TableNullIndex) { Check_Pointer(array); VERIFY_INDEX(index); Check(array[index]); return array[index]->GetPlug(); } return NULL; } // //########################################################################### // MakeTableEntry //########################################################################### // TableEntry* Table::MakeTableEntry( Plug*, const void* ) { Fail("Table::MakeTableEntry - Should never reach here"); return NULL; } // //########################################################################### // CompareTableEntries //########################################################################### // int Table::CompareTableEntries( TableEntry*, TableEntry* ) { Fail("Table::CompareTableEntries - Should never reach here"); return 0; } // //########################################################################### // CompareValueToTableEntry //########################################################################### // int Table::CompareValueToTableEntry( const void*, TableEntry* ) { Fail("Table::CompareValueToTableEntry - Should never reach here"); return 0; } // //########################################################################### // AddTableEntry //########################################################################### // void Table::AddTableEntry( TableEntry *link ) { Check(link); #if 0 numItems++; if (array == NULL) { array = (TableEntry**)malloc(sizeof(TableEntry*)); Register_Pointer(array); } else { Unregister_Pointer(array); array = (TableEntry**)realloc(array, numItems * sizeof(TableEntry*)); Register_Pointer(array); } #else CollectionSize new_num_items = numItems+1; if (array == NULL) { Verify(new_num_items == 1); array = new TableEntry*[new_num_items]; Register_Pointer(array); } else { TableEntry **new_array = new TableEntry*[new_num_items]; Register_Pointer(new_array); Mem_Copy( new_array, array, numItems * sizeof(TableEntry*), new_num_items * sizeof(TableEntry*) ); Unregister_Pointer(array); delete[] array; array = new_array; } numItems = new_num_items; #endif Check_Pointer(array); array[numItems - 1] = link; } // //########################################################################### // SortTableEntries //########################################################################### // void Table::SortTableEntries() { size_t i, j; TableEntry *temp; for (i = 1; i < numItems; i++) { Check_Pointer(array); Verify(i < numItems); temp = array[i]; j = i; Verify(j-1 < numItems); while (CompareTableEntries(array[j-1], temp) > 0) { Verify(j < numItems); Verify(j-1 < numItems); array[j] = array[j-1]; j--; if (j < 1) break; } Verify(j < numItems); array[j] = temp; } } // //########################################################################### // SearchForValue //########################################################################### // IteratorPosition Table::SearchForValue( const void *value ) { size_t n = numItems; size_t i = 0, j; IteratorPosition k; while (i < n) { j = (i + n - 1) >> 1; Check_Pointer(array); Verify(j < numItems); if ((k = CompareValueToTableEntry(value, array[j])) == 0) return j; if (k < 0) n = j; else i = j + 1; } return TableNullIndex; } // //########################################################################### // SearchForTableEntry //########################################################################### // IteratorPosition Table::SearchForTableEntry( TableEntry *link ) { CollectionSize i; for (i = 0; i < numItems; i++) { Check_Pointer(array); VERIFY_INDEX(i); if (array[i] == link) return i; } return TableNullIndex; } // //########################################################################### // RemoveNthTableEntry //########################################################################### // void Table::RemoveNthTableEntry( CollectionSize index ) { char *itemPtr, *lastItem; size_t width; Check_Pointer(array); VERIFY_INDEX(index); /* * Find the location of the item */ itemPtr = (char*)&array[index]; Check_Pointer(itemPtr); /* * Remove the item from the array */ width = sizeof(void*); lastItem = (char*)array + (numItems - 1) * width; if (itemPtr < lastItem) { memmove(itemPtr, itemPtr + width, (size_t)(lastItem - itemPtr)); } /* * Resize the array */ #if 0 numItems--; if (numItems == 0) { Unregister_Pointer(array); free(array); array = NULL; } else { Unregister_Pointer(array); array = (TableEntry**)realloc(array, numItems * sizeof(TableEntry*)); Register_Pointer(array); } #else CollectionSize new_num_items = numItems-1; if (new_num_items == 0) { Unregister_Pointer(array); delete[] array; array = NULL; } else { TableEntry **new_array = new TableEntry*[new_num_items]; Register_Pointer(new_array); Mem_Copy( new_array, array, new_num_items * sizeof(TableEntry*), new_num_items * sizeof(TableEntry*) ); Unregister_Pointer(array); delete[] array; array = new_array; } numItems = new_num_items; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~ TableIterator inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~ #if DEBUG_LEVEL>0 TableEntry* TableIterator::NthEntry( CollectionSize index ) { Check_Pointer(array); Verify(0 <= index && index < numItems); Check(array[index]); return array[index]; } #endif // //########################################################################### // TableIterator //########################################################################### // TableIterator::TableIterator(Table *table): SortedIterator(table) { array = table->array; numItems = table->numItems; if (array != NULL) currentPosition = 0; else currentPosition = TableNullIndex; } // //########################################################################### //########################################################################### // TableIterator::~TableIterator() { } // //########################################################################### // TestInstance //########################################################################### // Logical TableIterator::TestInstance() const { SortedIterator::TestInstance(); if (array != NULL) { Check_Pointer(array); Verify(0 < numItems); Verify(currentPosition < numItems); } return True; } // //########################################################################### // First //########################################################################### // void TableIterator::First() { if (array != NULL) currentPosition = 0; } // //########################################################################### // Last //########################################################################### // void TableIterator::Last() { if (array != NULL) currentPosition = numItems - 1; } // //########################################################################### // Next //########################################################################### // void TableIterator::Next() { IncrementPosition(); } // //########################################################################### // Previous //########################################################################### // void TableIterator::Previous() { DecrementPosition(); } // //########################################################################### // ReadAndNextImplementation //########################################################################### // void *TableIterator::ReadAndNextImplementation() { if (currentPosition != TableNullIndex) { Plug *plug; plug = NthEntry(currentPosition)->GetPlug(); IncrementPosition(); return plug; } return NULL; } // //########################################################################### // ReadAndPreviousImplementation //########################################################################### // void *TableIterator::ReadAndPreviousImplementation() { if (currentPosition != TableNullIndex) { Plug *plug; plug = NthEntry(currentPosition)->GetPlug(); DecrementPosition(); return plug; } return NULL; } // //########################################################################### // GetCurrentImplementation //########################################################################### // void *TableIterator::GetCurrentImplementation() { if (currentPosition != TableNullIndex) { return NthEntry(currentPosition)->GetPlug(); } return NULL; } // //########################################################################### // GetSize //########################################################################### // CollectionSize TableIterator::GetSize() { return numItems; } // //########################################################################### // GetNthImplementation //########################################################################### // void *TableIterator::GetNthImplementation( CollectionSize index ) { if (index < numItems) { return NthEntry(currentPosition = index)->GetPlug(); } return NULL; } // //########################################################################### // Remove //########################################################################### // void TableIterator::Remove() { if (currentPosition != TableNullIndex) { Unregister_Object(NthEntry(currentPosition)); delete NthEntry(currentPosition); } } // //########################################################################### // FindImplementation //########################################################################### // Plug *TableIterator::FindImplementation( const void *value ) { IteratorPosition index; Table *table = Cast_Object(Table*, socket); if ((index = table->SearchForValue(value)) != TableNullIndex) { if (!table->HasUniqueEntries()) { while ( index-1 >= 0 && table->CompareTableEntries(NthEntry(index-1), NthEntry(index)) == 0 ) { index--; } } return (NthEntry(currentPosition = index)->GetPlug()); } currentPosition = TableNullIndex; return NULL; } // //########################################################################### // ReceiveMemo //########################################################################### // void TableIterator::ReceiveMemo( IteratorMemo memo, void *content ) { switch (memo) { case PlugAdded: { Table *table = Cast_Object(Table*, socket); Check(table); array = table->array; numItems = table->numItems; // // If a plug is added before or at the current position then // the current position should be incremented one forward, // otherwise, no action is necessary // TableEntry *link; IteratorPosition index; link = Cast_Object(TableEntry*, content); index = table->SearchForTableEntry(link); VERIFY_INDEX(index); if (index <= currentPosition) { currentPosition++; } Verify(TableNullIndex <= currentPosition && currentPosition < numItems); } break; case PlugRemoved: { Table *table = Cast_Object(Table*, socket); Check(table); array = table->array; numItems = table->numItems; // // If a plug is removed before the current position then decrement // the current position, else if the current position is at the end // of the table then decrement the counter // IteratorPosition index; Check_Pointer(content); index = *(IteratorPosition*)content; if (index < currentPosition) { currentPosition--; } else if (numItems <= currentPosition) { currentPosition--; } Verify(TableNullIndex <= currentPosition && currentPosition < numItems); } break; #if 0 { IteratorPosition index; Check_Pointer(content); index = *(IteratorPosition*)content; array = Cast_Object(Table*, socket)->array; numItems = Cast_Object(Table*, socket)->numItems; /* * Decrement counter, if at 0 this will automatically become * TableNullIndex */ if (index < currentPosition) { currentPosition--; } else if (numItems <= currentPosition) { currentPosition--; } Verify(TableNullIndex <= currentPosition && currentPosition < numItems); break; } #endif } } #if defined(TEST_CLASS) # include "table.tcp" #endif