From ab2db9a59ef4663f141b1a295e98f337a4e23023 Mon Sep 17 00:00:00 2001 From: kgv Date: Thu, 24 Oct 2013 12:12:42 +0400 Subject: [PATCH] 0024271: Provide Boolean operations for NCollection_Map NCollection_Map - add two maps content Exchange operation without data copying Add Exchange method to NCollection_DataMap, NCollection_DoubleMap, NCollection_IndexedDataMap, NCollection_IndexedMap Add NCollection_Map::IsEqual() method Corrections for gcc - use this->myAllocator --- .../NCollection_BaseCollection.hxx | 8 +- src/NCollection/NCollection_BaseMap.hxx | 11 + src/NCollection/NCollection_DataMap.hxx | 8 + src/NCollection/NCollection_DoubleMap.hxx | 9 +- .../NCollection_IndexedDataMap.hxx | 8 + src/NCollection/NCollection_IndexedMap.hxx | 9 +- src/NCollection/NCollection_Map.hxx | 280 +++++++++++++++++- src/QABugs/QABugs_19.cxx | 101 ++++++- tests/bugs/fclasses/bug24271 | 11 + 9 files changed, 439 insertions(+), 6 deletions(-) create mode 100644 tests/bugs/fclasses/bug24271 diff --git a/src/NCollection/NCollection_BaseCollection.hxx b/src/NCollection/NCollection_BaseCollection.hxx index 017a7290ab..cb29fee5c9 100755 --- a/src/NCollection/NCollection_BaseCollection.hxx +++ b/src/NCollection/NCollection_BaseCollection.hxx @@ -17,7 +17,6 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. - #ifndef NCollection_BaseCollection_HeaderFile #define NCollection_BaseCollection_HeaderFile @@ -115,6 +114,13 @@ template class NCollection_BaseCollection return myIterAllocator; } + //! Exchange allocators of two collections + void exchangeAllocators (NCollection_BaseCollection& theOther) + { + std::swap (myAllocator, theOther.myAllocator); + std::swap (myIterAllocator, theOther.myIterAllocator); + } + protected: // --------- PROTECTED FIELDS ----------- Handle(NCollection_BaseAllocator) myAllocator; diff --git a/src/NCollection/NCollection_BaseMap.hxx b/src/NCollection/NCollection_BaseMap.hxx index 722f7f05b0..8bf3cea27b 100755 --- a/src/NCollection/NCollection_BaseMap.hxx +++ b/src/NCollection/NCollection_BaseMap.hxx @@ -199,6 +199,17 @@ class NCollection_BaseMap Standard_EXPORT Standard_Integer NextPrimeForMap (const Standard_Integer N) const; + //! Exchange content of two maps without data copying + void exchangeMapsData (NCollection_BaseMap& theOther) + { + std::swap (myData1, theOther.myData1); + std::swap (myData2, theOther.myData2); + //std::swap (isDouble, theOther.isDouble); + std::swap (mySaturated, theOther.mySaturated); + std::swap (myNbBuckets, theOther.myNbBuckets); + std::swap (mySize, theOther.mySize); + } + protected: // --------- PROTECTED FIELDS ----------- NCollection_ListNode ** myData1; diff --git a/src/NCollection/NCollection_DataMap.hxx b/src/NCollection/NCollection_DataMap.hxx index 6271039d82..0b5c22213e 100755 --- a/src/NCollection/NCollection_DataMap.hxx +++ b/src/NCollection/NCollection_DataMap.hxx @@ -152,6 +152,14 @@ template < class TheKeyType, Standard_TypeMismatch::Raise ("NCollection_DataMap::Assign impossible"); } + //! Exchange the content of two maps without re-allocations. + //! Notice that allocators will be swapped as well! + void Exchange (NCollection_DataMap& theOther) + { + this->exchangeAllocators (theOther); + this->exchangeMapsData (theOther); + } + //! = another map NCollection_DataMap& operator= (const NCollection_DataMap& theOther) { diff --git a/src/NCollection/NCollection_DoubleMap.hxx b/src/NCollection/NCollection_DoubleMap.hxx index 22a0deafea..187b358789 100755 --- a/src/NCollection/NCollection_DoubleMap.hxx +++ b/src/NCollection/NCollection_DoubleMap.hxx @@ -17,7 +17,6 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. - #ifndef NCollection_DoubleMap_HeaderFile #define NCollection_DoubleMap_HeaderFile @@ -162,6 +161,14 @@ template < class TheKey1Type, Standard_TypeMismatch::Raise ("NCollection_DoubleMap::Assign impossible"); } + //! Exchange the content of two maps without re-allocations. + //! Notice that allocators will be swapped as well! + void Exchange (NCollection_DoubleMap& theOther) + { + this->exchangeAllocators (theOther); + this->exchangeMapsData (theOther); + } + //! = another map NCollection_DoubleMap& operator=(const NCollection_DoubleMap& theOther) { diff --git a/src/NCollection/NCollection_IndexedDataMap.hxx b/src/NCollection/NCollection_IndexedDataMap.hxx index 413ddcf1ed..badb899a89 100755 --- a/src/NCollection/NCollection_IndexedDataMap.hxx +++ b/src/NCollection/NCollection_IndexedDataMap.hxx @@ -165,6 +165,14 @@ template < class TheKeyType, Standard_TypeMismatch::Raise("NCollection_IndexedDataMap::Assign"); } + //! Exchange the content of two maps without re-allocations. + //! Notice that allocators will be swapped as well! + void Exchange (NCollection_IndexedDataMap& theOther) + { + this->exchangeAllocators (theOther); + this->exchangeMapsData (theOther); + } + //! = another map NCollection_IndexedDataMap& operator= (const NCollection_IndexedDataMap& theOther) diff --git a/src/NCollection/NCollection_IndexedMap.hxx b/src/NCollection/NCollection_IndexedMap.hxx index a93859d8d5..12f8c5ea6a 100755 --- a/src/NCollection/NCollection_IndexedMap.hxx +++ b/src/NCollection/NCollection_IndexedMap.hxx @@ -17,7 +17,6 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. - #ifndef NCollection_IndexedMap_HeaderFile #define NCollection_IndexedMap_HeaderFile @@ -157,6 +156,14 @@ template < class TheKeyType, Add(anIter.Value()); } + //! Exchange the content of two maps without re-allocations. + //! Notice that allocators will be swapped as well! + void Exchange (NCollection_IndexedMap& theOther) + { + this->exchangeAllocators (theOther); + this->exchangeMapsData (theOther); + } + //! = another map NCollection_IndexedMap& operator= (const NCollection_IndexedMap& theOther) { diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index 3e8347eb57..915ce0d672 100755 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -17,12 +17,12 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. - #ifndef NCollection_Map_HeaderFile #define NCollection_Map_HeaderFile #include #include +#include #include #include @@ -156,6 +156,14 @@ template < class TheKeyType, Add (anIter.Value()); } + //! Exchange the content of two maps without re-allocations. + //! Notice that allocators will be swapped as well! + void Exchange (NCollection_Map& theOther) + { + this->exchangeAllocators (theOther); + this->exchangeMapsData (theOther); + } + //! = another map NCollection_Map& operator= (const NCollection_Map& theOther) { @@ -313,6 +321,276 @@ template < class TheKeyType, virtual Standard_Integer Size(void) const { return Extent(); } + public: + //!@name Boolean operations with maps as sets of keys + //!@{ + + //! @return true if two maps contains exactly the same keys + Standard_Boolean IsEqual (const NCollection_Map& theOther) const + { + return Extent() == theOther.Extent() + && Contains (theOther); + } + + //! @return true if this map contains ALL keys of another map. + Standard_Boolean Contains (const NCollection_Map& theOther) const + { + if (this == &theOther + || theOther.IsEmpty()) + { + return Standard_True; + } + else if (Extent() < theOther.Extent()) + { + return Standard_False; + } + + for (Iterator anIter (theOther); anIter.More(); anIter.Next()) + { + if (!Contains (anIter.Key())) + { + return Standard_False; + } + } + + return Standard_True; + } + + //! Sets this Map to be the result of union (aka addition, fuse, merge, boolean OR) operation between two given Maps + //! The new Map contains the values that are contained either in the first map or in the second map or in both. + //! All previous content of this Map is cleared. + //! This map (result of the boolean operation) can also be passed as one of operands. + void Union (const NCollection_Map& theLeft, + const NCollection_Map& theRight) + { + if (&theLeft == &theRight) + { + Assign (theLeft); + return; + } + + if (this != &theLeft + && this != &theRight) + { + Clear(); + } + + if (this != &theLeft) + { + for (Iterator anIter (theLeft); anIter.More(); anIter.Next()) + { + Add (anIter.Key()); + } + } + if (this != &theRight) + { + for (Iterator anIter (theRight); anIter.More(); anIter.Next()) + { + Add (anIter.Key()); + } + } + } + + //! Apply to this Map the boolean operation union (aka addition, fuse, merge, boolean OR) with another (given) Map. + //! The result contains the values that were previously contained in this map or contained in the given (operand) map. + //! This algorithm is similar to method Union(). + //! Returns True if contents of this map is changed. + Standard_Boolean Unite (const NCollection_Map& theOther) + { + if (this == &theOther) + { + return Standard_False; + } + + const Standard_Integer anOldExtent = Extent(); + Union (*this, theOther); + return anOldExtent != Extent(); + } + + //! Sets this Map to be the result of intersection (aka multiplication, common, boolean AND) operation between two given Maps. + //! The new Map contains only the values that are contained in both map operands. + //! All previous content of this Map is cleared. + //! This same map (result of the boolean operation) can also be used as one of operands. + void Intersection (const NCollection_Map& theLeft, + const NCollection_Map& theRight) + { + if (&theLeft == &theRight) + { + Assign (theLeft); + return; + } + + if (this == &theLeft) + { + NCollection_Map aCopy (1, this->myAllocator); + Exchange (aCopy); + Intersection (aCopy, theRight); + return; + } + else if (this == &theRight) + { + NCollection_Map aCopy (1, this->myAllocator); + Exchange (aCopy); + Intersection (theLeft, aCopy); + return; + } + + Clear(); + if (theLeft.Extent() < theRight.Extent()) + { + for (Iterator anIter (theLeft); anIter.More(); anIter.Next()) + { + if (theRight.Contains (anIter.Key())) + { + Add (anIter.Key()); + } + } + } + else + { + for (Iterator anIter (theRight); anIter.More(); anIter.Next()) + { + if (theLeft.Contains (anIter.Key())) + { + Add (anIter.Key()); + } + } + } + } + + //! Apply to this Map the intersection operation (aka multiplication, common, boolean AND) with another (given) Map. + //! The result contains only the values that are contained in both this and the given maps. + //! This algorithm is similar to method Intersection(). + //! Returns True if contents of this map is changed. + Standard_Boolean Intersect (const NCollection_Map& theOther) + { + if (this == &theOther + || IsEmpty()) + { + return Standard_False; + } + + const Standard_Integer anOldExtent = Extent(); + Intersection (*this, theOther); + return anOldExtent != Extent(); + } + + //! Sets this Map to be the result of subtraction (aka set-theoretic difference, relative complement, + //! exclude, cut, boolean NOT) operation between two given Maps. + //! The new Map contains only the values that are contained in the first map operands and not contained in the second one. + //! All previous content of this Map is cleared. + void Subtraction (const NCollection_Map& theLeft, + const NCollection_Map& theRight) + { + if (this == &theLeft) + { + Subtract (theRight); + return; + } + else if (this == &theRight) + { + NCollection_Map aCopy (1, this->myAllocator); + Exchange (aCopy); + Subtraction (theLeft, aCopy); + return; + } + + Assign (theLeft); + Subtract (theRight); + } + + //! Apply to this Map the subtraction (aka set-theoretic difference, relative complement, + //! exclude, cut, boolean NOT) operation with another (given) Map. + //! The result contains only the values that were previously contained in this map and not contained in this map. + //! This algorithm is similar to method Subtract() with two operands. + //! Returns True if contents of this map is changed. + Standard_Boolean Subtract (const NCollection_Map& theOther) + { + if (this == &theOther) + { + if (IsEmpty()) + { + return Standard_False; + } + + Clear(); + return Standard_True; + } + + const Standard_Integer anOldExtent = Extent(); + for (Iterator anIter (theOther); anIter.More(); anIter.Next()) + { + Remove (anIter.Key()); + } + return anOldExtent != Extent(); + } + + //! Sets this Map to be the result of symmetric difference (aka exclusive disjunction, boolean XOR) operation between two given Maps. + //! The new Map contains the values that are contained only in the first or the second operand maps but not in both. + //! All previous content of this Map is cleared. This map (result of the boolean operation) can also be used as one of operands. + void Difference (const NCollection_Map& theLeft, + const NCollection_Map& theRight) + { + if (&theLeft == &theRight) + { + Clear(); + return; + } + else if (this == &theLeft) + { + NCollection_Map aCopy (1, this->myAllocator); + Exchange (aCopy); + Difference (aCopy, theRight); + return; + } + else if (this == &theRight) + { + NCollection_Map aCopy (1, this->myAllocator); + Exchange (aCopy); + Difference (theLeft, aCopy); + return; + } + + Clear(); + for (Iterator anIter (theLeft); anIter.More(); anIter.Next()) + { + if (!theRight.Contains (anIter.Key())) + { + Add (anIter.Key()); + } + } + for (Iterator anIter (theRight); anIter.More(); anIter.Next()) + { + if (!theLeft.Contains (anIter.Key())) + { + Add (anIter.Key()); + } + } + } + + //! Apply to this Map the symmetric difference (aka exclusive disjunction, boolean XOR) operation with another (given) Map. + //! The result contains the values that are contained only in this or the operand map, but not in both. + //! This algorithm is similar to method Difference(). + //! Returns True if contents of this map is changed. + Standard_Boolean Differ (const NCollection_Map& theOther) + { + if (this == &theOther) + { + if (IsEmpty()) + { + return Standard_False; + } + Clear(); + return Standard_True; + } + + const Standard_Integer anOldExtent = Extent(); + Difference (*this, theOther); + return anOldExtent != Extent(); + } + + //!@} + private: // ----------- PRIVATE METHODS ----------- diff --git a/src/QABugs/QABugs_19.cxx b/src/QABugs/QABugs_19.cxx index 7d30c41ece..58cd291d96 100755 --- a/src/QABugs/QABugs_19.cxx +++ b/src/QABugs/QABugs_19.cxx @@ -17,7 +17,6 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. - #include #include @@ -46,7 +45,7 @@ #include #include #include - +#include #include #define QCOMPARE(val1, val2) \ @@ -1297,6 +1296,103 @@ static Standard_Integer OCC24137 (Draw_Interpretor& theDI, Standard_Integer theN return 0; } +//! Check boolean operations on NCollection_Map +static Standard_Integer OCC24271 (Draw_Interpretor& di, + Standard_Integer /*theArgNb*/, + const char** /*theArgVec*/) +{ + // input data + const Standard_Integer aLeftLower = 1; + const Standard_Integer aLeftUpper = 10; + const Standard_Integer aRightLower = 5; + const Standard_Integer aRightUpper = 15; + + // define arguments + NCollection_Map aMapLeft; + for (Standard_Integer aKeyIter = aLeftLower; aKeyIter <= aLeftUpper; ++aKeyIter) + { + aMapLeft.Add (aKeyIter); + } + + NCollection_Map aMapRight; + for (Standard_Integer aKeyIter = aRightLower; aKeyIter <= aRightUpper; ++aKeyIter) + { + aMapRight.Add (aKeyIter); + } + + QCOMPARE (aMapLeft .Contains (aMapRight), Standard_False); + QCOMPARE (aMapRight.Contains (aMapLeft), Standard_False); + + // validate Union operation + NCollection_Map aMapUnion; + aMapUnion.Union (aMapLeft, aMapRight); + QCOMPARE (aMapUnion.Extent(), aRightUpper - aLeftLower + 1); + for (Standard_Integer aKeyIter = aLeftLower; aKeyIter <= aRightUpper; ++aKeyIter) + { + QCOMPARE (aMapUnion.Contains (aKeyIter), Standard_True); + } + + // validate Intersection operation + NCollection_Map aMapSect; + aMapSect.Intersection (aMapLeft, aMapRight); + QCOMPARE (aMapSect.Extent(), aLeftUpper - aRightLower + 1); + for (Standard_Integer aKeyIter = aRightLower; aKeyIter <= aLeftUpper; ++aKeyIter) + { + QCOMPARE (aMapSect.Contains (aKeyIter), Standard_True); + } + QCOMPARE (aMapLeft .Contains (aMapSect), Standard_True); + QCOMPARE (aMapRight.Contains (aMapSect), Standard_True); + + // validate Substruction operation + NCollection_Map aMapSubsLR; + aMapSubsLR.Subtraction (aMapLeft, aMapRight); + QCOMPARE (aMapSubsLR.Extent(), aRightLower - aLeftLower); + for (Standard_Integer aKeyIter = aLeftLower; aKeyIter < aRightLower; ++aKeyIter) + { + QCOMPARE (aMapSubsLR.Contains (aKeyIter), Standard_True); + } + + NCollection_Map aMapSubsRL; + aMapSubsRL.Subtraction (aMapRight, aMapLeft); + QCOMPARE (aMapSubsRL.Extent(), aRightUpper - aLeftUpper); + for (Standard_Integer aKeyIter = aLeftUpper + 1; aKeyIter < aRightUpper; ++aKeyIter) + { + QCOMPARE (aMapSubsRL.Contains (aKeyIter), Standard_True); + } + + // validate Difference operation + NCollection_Map aMapDiff; + aMapDiff.Difference (aMapLeft, aMapRight); + QCOMPARE (aMapDiff.Extent(), aRightLower - aLeftLower + aRightUpper - aLeftUpper); + for (Standard_Integer aKeyIter = aLeftLower; aKeyIter < aRightLower; ++aKeyIter) + { + QCOMPARE (aMapDiff.Contains (aKeyIter), Standard_True); + } + for (Standard_Integer aKeyIter = aLeftUpper + 1; aKeyIter < aRightUpper; ++aKeyIter) + { + QCOMPARE (aMapDiff.Contains (aKeyIter), Standard_True); + } + + // validate Exchange operation + NCollection_Map aMapSwap; + aMapSwap.Exchange (aMapSect); + for (Standard_Integer aKeyIter = aRightLower; aKeyIter <= aLeftUpper; ++aKeyIter) + { + QCOMPARE (aMapSwap.Contains (aKeyIter), Standard_True); + } + QCOMPARE (aMapSect.IsEmpty(), Standard_True); + aMapSwap.Add (34); + aMapSect.Add (43); + + NCollection_Map aMapCopy (aMapSwap); + QCOMPARE (aMapCopy.IsEqual (aMapSwap), Standard_True); + aMapCopy.Remove (34); + aMapCopy.Add (43); + QCOMPARE (aMapCopy.IsEqual (aMapSwap), Standard_False); + + return 0; +} + void QABugs::Commands_19(Draw_Interpretor& theCommands) { const char *group = "QABugs"; @@ -1318,5 +1414,6 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands) { theCommands.Add ("OCC11758", "OCC11758", __FILE__, OCC11758, group); theCommands.Add ("OCC24005", "OCC24005 result", __FILE__, OCC24005, group); theCommands.Add ("OCC24137", "OCC24137 face vertex U V [N]", __FILE__, OCC24137, group); + theCommands.Add ("OCC24271", "Boolean operations on NCollection_Map", __FILE__, OCC24271, group); return; } diff --git a/tests/bugs/fclasses/bug24271 b/tests/bugs/fclasses/bug24271 new file mode 100644 index 0000000000..b7fc1fc16c --- /dev/null +++ b/tests/bugs/fclasses/bug24271 @@ -0,0 +1,11 @@ +puts "================" +puts "OCC24271" +puts "================" +puts "" +####################################################################### +# validate boolean operations on NCollection_Map +####################################################################### + +pload QAcommands + +OCC24271