diff --git a/src/NCollection/NCollection_IndexedDataMap.hxx b/src/NCollection/NCollection_IndexedDataMap.hxx index 967324874f..72baad7265 100644 --- a/src/NCollection/NCollection_IndexedDataMap.hxx +++ b/src/NCollection/NCollection_IndexedDataMap.hxx @@ -70,7 +70,7 @@ class NCollection_IndexedDataMap : public NCollection_BaseMap TheKeyType& Key1 (void) { return myKey1; } //! Key2 - const Standard_Integer& Key2 (void) + Standard_Integer& Key2 (void) { return myKey2; } //! Next2 IndexedDataMapNode*& Next2 (void) @@ -345,6 +345,58 @@ class NCollection_IndexedDataMap : public NCollection_BaseMap myData1[iK1] = p; } + //! Swaps two elements with the given indices. + void Swap (const Standard_Integer theIndex1, + const Standard_Integer theIndex2) + { + Standard_OutOfRange_Raise_if (theIndex1 < 1 || theIndex1 > Extent() + || theIndex2 < 1 || theIndex2 > Extent(), "NCollection_IndexedDataMap::Swap"); + + if (theIndex1 == theIndex2) + { + return; + } + + const Standard_Integer aK1 = ::HashCode (theIndex1, NbBuckets()); + const Standard_Integer aK2 = ::HashCode (theIndex2, NbBuckets()); + + IndexedDataMapNode* aP1 = (IndexedDataMapNode*) myData2[aK1]; + IndexedDataMapNode* aP2 = (IndexedDataMapNode*) myData2[aK2]; + + if (aP1->Key2() == theIndex1) + { + myData2[aK1] = (IndexedDataMapNode *) aP1->Next2(); + } + else + { + IndexedDataMapNode* aQ = aP1; + for (aP1 = aQ->Next2(); aP1->Key2() != theIndex1; aQ = aP1, aP1 = aQ->Next2()) { } + + aQ->Next2() = aP1->Next2(); + } + + if (aP2->Key2() == theIndex2) + { + myData2[aK2] = (IndexedDataMapNode *) aP2->Next2(); + } + else + { + IndexedDataMapNode* aQ = aP2; + for (aP2 = aQ->Next2(); aP2->Key2() != theIndex2; aQ = aP2, aP2 = aQ->Next2()) { } + + aQ->Next2() = aP2->Next2(); + } + + std::swap (aP1->Key2(), + aP2->Key2()); + + aP1->Next2() = (IndexedDataMapNode*) myData2[aK2]; + myData2[aK2] = aP1; + + aP2->Next2() = (IndexedDataMapNode*) myData2[aK1]; + myData2[aK1] = aP2; + } + //! RemoveLast void RemoveLast (void) { diff --git a/src/NCollection/NCollection_IndexedMap.hxx b/src/NCollection/NCollection_IndexedMap.hxx index 4c8bfd78a2..29628b90aa 100644 --- a/src/NCollection/NCollection_IndexedMap.hxx +++ b/src/NCollection/NCollection_IndexedMap.hxx @@ -60,7 +60,7 @@ class NCollection_IndexedMap : public NCollection_BaseMap TheKeyType& Key1 (void) { return this->ChangeValue(); } //! Key2 - const Standard_Integer& Key2 (void) + Standard_Integer& Key2 (void) { return myKey2; } //! Next2 IndexedMapNode*& Next2 (void) @@ -314,6 +314,58 @@ class NCollection_IndexedMap : public NCollection_BaseMap myData1[iK1] = p; } + //! Swaps two elements with the given indices. + void Swap (const Standard_Integer theIndex1, + const Standard_Integer theIndex2) + { + Standard_OutOfRange_Raise_if (theIndex1 < 1 || theIndex1 > Extent() + || theIndex2 < 1 || theIndex2 > Extent(), "NCollection_IndexedMap::Swap"); + + if (theIndex1 == theIndex2) + { + return; + } + + const Standard_Integer aK1 = ::HashCode (theIndex1, NbBuckets()); + const Standard_Integer aK2 = ::HashCode (theIndex2, NbBuckets()); + + IndexedMapNode* aP1 = (IndexedMapNode*) myData2[aK1]; + IndexedMapNode* aP2 = (IndexedMapNode*) myData2[aK2]; + + if (aP1->Key2() == theIndex1) + { + myData2[aK1] = (IndexedMapNode *) aP1->Next2(); + } + else + { + IndexedMapNode* aQ = aP1; + for (aP1 = aQ->Next2(); aP1->Key2() != theIndex1; aQ = aP1, aP1 = aQ->Next2()) { } + + aQ->Next2() = aP1->Next2(); + } + + if (aP2->Key2() == theIndex2) + { + myData2[aK2] = (IndexedMapNode *) aP2->Next2(); + } + else + { + IndexedMapNode* aQ = aP2; + for (aP2 = aQ->Next2(); aP2->Key2() != theIndex2; aQ = aP2, aP2 = aQ->Next2()) { } + + aQ->Next2() = aP2->Next2(); + } + + std::swap (aP1->Key2(), + aP2->Key2()); + + aP1->Next2() = (IndexedMapNode*) myData2[aK2]; + myData2[aK2] = aP1; + + aP2->Next2() = (IndexedMapNode*) myData2[aK1]; + myData2[aK1] = aP2; + } + //! RemoveLast void RemoveLast (void) { diff --git a/src/QANCollection/QANCollection_Stl.cxx b/src/QANCollection/QANCollection_Stl.cxx index a4b94e2f92..adf58d19e6 100644 --- a/src/QANCollection/QANCollection_Stl.cxx +++ b/src/QANCollection/QANCollection_Stl.cxx @@ -1143,13 +1143,13 @@ static Standard_Integer QANTestNCollectionPerformance (Draw_Interpretor& di, Sta di << "\n" << "std::vector vs NCollection_Array1 (sort):" << "\n\n"; TestPerformanceRandomIterator, std::vector >(di); - + di << "\n" << "std::vector vs NCollection_Vector (sort):" << "\n\n"; TestPerformanceRandomIterator, std::vector >(di); - + di << "\n" << "std::vector vs NCollection_Array1 (replace):" << "\n\n"; TestPerformanceForwardIterator, std::vector >(di); - + di << "\n" << "std::vector vs NCollection_Vector (replace):" << "\n\n"; TestPerformanceForwardIterator, std::vector >(di); @@ -1167,7 +1167,193 @@ static Standard_Integer QANTestNCollectionPerformance (Draw_Interpretor& di, Sta di << "\n" << "std::set vs NCollection_IndexedMap (search):" << "\n\n"; TestPerformanceMapAccess, int>(di); - + + return 0; +} + +//======================================================================= +//function : QANTestNCollectionIndexedMap +//purpose : +//======================================================================= +static Standard_Integer QANTestNCollectionIndexedMap (Draw_Interpretor& di, Standard_Integer, const char**) +{ + OSD_Timer aTimer; + + std::vector aIndxs; + std::vector aItems; + NCollection_IndexedMap aIndxMap; + + const Standard_Integer aNbItems = 1000000; + + srand (1); + for (Standard_Integer anId = 1; anId <= aNbItems; ++anId) + { + const Standard_Integer aVal = anId * 2; + + aIndxs.push_back (anId); + aItems.push_back (aVal); + + aIndxMap.Add (aVal); + } + + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems; ++anId) + { + if (aIndxMap.FindIndex (aItems[anId]) != aIndxs[anId]) + { + std::cout << "failed FindIndex\n"; + } + + if (aIndxMap.FindKey (aIndxs[anId]) != aItems[anId]) + { + std::cout << "failed FindKey\n"; + } + } + aTimer.Stop(); + + const Standard_Real aTime1 = aTimer.ElapsedTime(); + + aTimer.Reset(); + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems / 30; ++anId) + { + const Standard_Integer anId2 = Min (aNbItems - 1, + static_cast (rand() / float (RAND_MAX) * aNbItems)); + + aIndxMap.Swap (aIndxs[anId], aIndxs[anId2]); + + std::swap (aIndxs[anId], aIndxs[anId2]); + } + aTimer.Stop(); + + const Standard_Real aTime2 = aTimer.ElapsedTime(); + + aTimer.Reset(); + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems; ++anId) + { + if (aIndxMap.FindIndex (aItems[anId]) != aIndxs[anId]) + { + std::cout << "failed FindIndex\n"; + } + + if (aIndxMap.FindKey (aIndxs[anId]) != aItems[anId]) + { + std::cout << "failed FindKey\n"; + } + } + aTimer.Stop(); + + const Standard_Real aTime3 = aTimer.ElapsedTime(); + + aTimer.Reset(); + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems; ++anId) + { + aIndxMap.RemoveLast(); + } + aTimer.Stop(); + + const Standard_Real aTime4 = aTimer.ElapsedTime(); + + di << "Search time 1: " << aTime1 << "\n" + << "Swapping time: " << aTime2 << "\n" + << "Search time 2: " << aTime3 << "\n" + << "Remove time: " << aTime4 << "\n"; + + return 0; +} + +//======================================================================= +//function : QANTestNCollectionIndexedDataMap +//purpose : +//======================================================================= +static Standard_Integer QANTestNCollectionIndexedDataMap (Draw_Interpretor& di, Standard_Integer, const char**) +{ + OSD_Timer aTimer; + + std::vector aIndxs; + std::vector aItems; + NCollection_IndexedDataMap aIndxMap; + + const Standard_Integer aNbItems = 1000000; + + srand (1); + for (Standard_Integer anId = 1; anId <= aNbItems; ++anId) + { + const Standard_Integer aVal = anId * 2; + + aIndxs.push_back (anId); + aItems.push_back (aVal); + + aIndxMap.Add (aVal, aVal * 2); + } + + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems; ++anId) + { + if (aIndxMap.FindIndex (aItems[anId]) != aIndxs[anId]) + { + std::cout << "failed FindIndex\n"; + } + + if (aIndxMap.FindKey (aIndxs[anId]) != aItems[anId]) + { + std::cout << "failed FindKey\n"; + } + } + aTimer.Stop(); + + const Standard_Real aTime1 = aTimer.ElapsedTime(); + + aTimer.Reset(); + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems / 30; ++anId) + { + const Standard_Integer anId2 = Min (aNbItems - 1, + static_cast (rand() / float (RAND_MAX) * aNbItems)); + + aIndxMap.Swap (aIndxs[anId], aIndxs[anId2]); + + std::swap (aIndxs[anId], aIndxs[anId2]); + } + aTimer.Stop(); + + const Standard_Real aTime2 = aTimer.ElapsedTime(); + + aTimer.Reset(); + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems; ++anId) + { + if (aIndxMap.FindIndex (aItems[anId]) != aIndxs[anId]) + { + std::cout << "failed FindIndex\n"; + } + + if (aIndxMap.FindKey (aIndxs[anId]) != aItems[anId]) + { + std::cout << "failed FindKey\n"; + } + } + aTimer.Stop(); + + const Standard_Real aTime3 = aTimer.ElapsedTime(); + + aTimer.Reset(); + aTimer.Start(); + for (Standard_Integer anId = 0; anId < aNbItems; ++anId) + { + aIndxMap.RemoveLast(); + } + aTimer.Stop(); + + const Standard_Real aTime4 = aTimer.ElapsedTime(); + + di << "Search time 1: " << aTime1 << "\n" + << "Swapping time: " << aTime2 << "\n" + << "Search time 2: " << aTime3 << "\n" + << "Remove time: " << aTime4 << "\n"; + return 0; } @@ -1239,5 +1425,17 @@ void QANCollection::CommandsStl (Draw_Interpretor& theCommands) QANTestNCollectionPerformance, aGroup); + theCommands.Add ("QANTestNCollectionIndexedMap", + "QANTestNCollectionIndexedMap", + __FILE__, + QANTestNCollectionIndexedMap, + aGroup); + + theCommands.Add ("QANTestNCollectionIndexedDataMap", + "QANTestNCollectionIndexedDataMap", + __FILE__, + QANTestNCollectionIndexedDataMap, + aGroup); + return; } diff --git a/tests/bugs/fclasses/bug24831 b/tests/bugs/fclasses/bug24831 new file mode 100644 index 0000000000..90d6d8de65 --- /dev/null +++ b/tests/bugs/fclasses/bug24831 @@ -0,0 +1,3 @@ +pload QAcommands + +QANTestStlIterators diff --git a/tests/perf/ncollection/A2 b/tests/perf/ncollection/A2 new file mode 100644 index 0000000000..e7286d0035 --- /dev/null +++ b/tests/perf/ncollection/A2 @@ -0,0 +1,41 @@ +pload QAcommands + +set info [QANTestNCollectionIndexedMap] + +set keys {} +set values {} +foreach line [split $info "\n"] { + set key [string trim [string range $line 0 [expr {[string first ":" $line] - 1}]]] + set value [string trim [string range $line [expr {[string first ":" $line] + 1}] [expr {[string length $line] - 1}]]] + if {[string length $key] != 0} { + if {[string length $value] != 0} { + lappend keys $key + lappend values $value + } + } +} + +if { [string compare $tcl_platform(platform) "windows"] != 0 } { + set check_values { 0.1540285 + 0.1286995 + 0.1607561 + 0.3624441 + } +} else { + set check_values { 0.018136771 + 0.008694706 + 0.019123649 + 0.784462745 + } +} + +set index 0 +foreach key $keys { + set value [lindex $values $index] + if { $value > [lindex $check_values $index] } { + puts "ERROR: performance of $key become worse" + } else { + puts "OK: performance of $key is OK" + } + incr index +} diff --git a/tests/perf/ncollection/A3 b/tests/perf/ncollection/A3 new file mode 100644 index 0000000000..8847bad490 --- /dev/null +++ b/tests/perf/ncollection/A3 @@ -0,0 +1,41 @@ +pload QAcommands + +set info [QANTestNCollectionIndexedDataMap] + +set keys {} +set values {} +foreach line [split $info "\n"] { + set key [string trim [string range $line 0 [expr {[string first ":" $line] - 1}]]] + set value [string trim [string range $line [expr {[string first ":" $line] + 1}] [expr {[string length $line] - 1}]]] + if {[string length $key] != 0} { + if {[string length $value] != 0} { + lappend keys $key + lappend values $value + } + } +} + +if { [string compare $tcl_platform(platform) "windows"] != 0 } { + set check_values { 0.1549615 + 0.1290805 + 0.1602191 + 0.3487175 + } +} else { + set check_values { 0.017762852 + 0.008435507 + 0.018746851 + 0.079263713 + } +} + +set index 0 +foreach key $keys { + set value [lindex $values $index] + if { $value > [lindex $check_values $index] } { + puts "ERROR: performance of $key become worse" + } else { + puts "OK: performance of $key is OK" + } + incr index +}