0024271: Provide Boolean operations for NCollection_Map
authorkgv <kgv@opencascade.com>
Thu, 24 Oct 2013 08:12:42 +0000 (12:12 +0400)
committerbugmaster <bugmaster@opencascade.com>
Thu, 24 Oct 2013 08:13:28 +0000 (12:13 +0400)
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

src/NCollection/NCollection_BaseCollection.hxx
src/NCollection/NCollection_BaseMap.hxx
src/NCollection/NCollection_DataMap.hxx
src/NCollection/NCollection_DoubleMap.hxx
src/NCollection/NCollection_IndexedDataMap.hxx
src/NCollection/NCollection_IndexedMap.hxx
src/NCollection/NCollection_Map.hxx
src/QABugs/QABugs_19.cxx
tests/bugs/fclasses/bug24271 [new file with mode: 0644]

index 017a729..cb29fee 100755 (executable)
@@ -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 TheItemType> 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;
index 722f7f0..8bf3cea 100755 (executable)
@@ -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;
index 6271039..0b5c222 100755 (executable)
@@ -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)
   { 
index 22a0dea..187b358 100755 (executable)
@@ -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)
   { 
index 413ddcf..badb899 100755 (executable)
@@ -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)
index a93859d..12f8c5e 100755 (executable)
@@ -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)
   { 
index 3e8347e..915ce0d 100755 (executable)
 // 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 <NCollection_BaseCollection.hxx>
 #include <NCollection_BaseMap.hxx>
+#include <NCollection_DataMap.hxx>
 #include <NCollection_TListNode.hxx>
 
 #include <NCollection_DefaultHasher.hxx>
@@ -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 -----------
 
index 7d30c41..58cd291 100755 (executable)
@@ -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 <QABugs.hxx>
 
 #include <Draw_Interpretor.hxx>
@@ -46,7 +45,7 @@
 #include <BRepPrimAPI_MakeBox.hxx>
 #include <BRepPrimAPI_MakeSphere.hxx>
 #include <BRepAlgo_Cut.hxx>
-
+#include <NCollection_Map.hxx>
 #include <TCollection_HAsciiString.hxx>
 
 #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<Standard_Integer> aMapLeft;
+  for (Standard_Integer aKeyIter = aLeftLower; aKeyIter <= aLeftUpper; ++aKeyIter)
+  {
+    aMapLeft.Add (aKeyIter);
+  }
+
+  NCollection_Map<Standard_Integer> 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<Standard_Integer> 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<Standard_Integer> 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<Standard_Integer> 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<Standard_Integer> 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<Standard_Integer> 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<Standard_Integer> 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<Standard_Integer> 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 (file)
index 0000000..b7fc1fc
--- /dev/null
@@ -0,0 +1,11 @@
+puts "================"
+puts "OCC24271"
+puts "================"
+puts ""
+#######################################################################
+# validate boolean operations on NCollection_Map
+#######################################################################
+
+pload QAcommands
+
+OCC24271