Salome HOME
0022301: [CEA] Problems with study dump in SMESH (PPGP large study)
authoreap <eap@opencascade.com>
Thu, 22 Aug 2013 12:06:57 +0000 (12:06 +0000)
committereap <eap@opencascade.com>
Thu, 22 Aug 2013 12:06:57 +0000 (12:06 +0000)
1) fix CheckObjectPresence() to check presence of not only published
objects but also of e.g. mesh editors etc.
2) Avoid adding empty strings cleared by CheckObjectPresence()
3) Optimize performance of search of myKeepAgrCmdsIDs in commands by
 - using _pyStringFamily
 - preventing addition of Groups to myKeepAgrCmdsIDs

src/SMESH_I/SMESH_2smeshpy.cxx
src/SMESH_I/SMESH_2smeshpy.hxx

index 60c0b2491a8bff050377059d5e62baf3a723e1e7..cf4bd90d3fbc128abc36f747488e446705d8c675 100644 (file)
@@ -198,8 +198,9 @@ namespace {
     }
     // check if an Object was created in the script
     _AString comment;
-    const _pyID& obj = cmd->GetObject();
-    if ( !obj.IsEmpty() && cmd->IsStudyEntry( obj ) && !presentObjects.count( obj ))
+    const _pyID&        obj = cmd->GetObject();
+    const bool isMethodCall = cmd->IsMethodCall();
+    if ( !obj.IsEmpty() && isMethodCall && !presentObjects.count( obj ) )
     {
       comment = "not created Object";
       theGen->ObjectCreationRemoved( obj );
@@ -218,6 +219,8 @@ namespace {
           comment += *id + " has not been yet created";
           break;
         }
+      // if ( idList.empty() && cmd->IsID( arg ) && !presentObjects.count( arg ))
+      //   comment += arg + " has not been yet created";
     }
     // treat result objects
     const _pyID& result = cmd->GetResultValue();
@@ -226,10 +229,14 @@ namespace {
       list< _pyID > idList = cmd->GetStudyEntries( result );
       list< _pyID >::iterator id = idList.begin();
       for ( ; id != idList.end(); ++id )
+      {
         if ( comment.IsEmpty() )
           presentObjects.insert( *id );
         else
           theGen->ObjectCreationRemoved( *id ); // objID.SetName( name ) is not needed
+      }
+      if ( idList.empty() && cmd->IsID( result ))
+        presentObjects.insert( result );
     }
     // comment the command
     if ( !comment.IsEmpty() )
@@ -513,6 +520,9 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
   // concat commands back into a script
   TCollection_AsciiString aScript, aPrevCmd;
   set<_pyID> createdObjects;
+  createdObjects.insert( "smeshBuilder" );
+  createdObjects.insert( "smesh" );
+  createdObjects.insert( "theStudy" );
   for ( cmd = theGen->GetCommands().begin(); cmd != theGen->GetCommands().end(); ++cmd )
   {
 #ifdef DUMP_CONVERSION
@@ -520,9 +530,11 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
 #endif
     if ( !(*cmd)->IsEmpty() && aPrevCmd != (*cmd)->GetString()) {
       CheckObjectPresence( *cmd, createdObjects );
-      aPrevCmd = (*cmd)->GetString();
-      aScript += "\n";
-      aScript += aPrevCmd;
+      if ( !(*cmd)->IsEmpty() ) {
+        aPrevCmd = (*cmd)->GetString();
+        aScript += "\n";
+        aScript += aPrevCmd;
+      }
     }
   }
   aScript += "\n";
@@ -631,14 +643,29 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   StructToList( aCommand );
 
   // not to erase _pySelfEraser's etc. used as args in some commands
-  std::list< _pyID >::const_iterator id = myKeepAgrCmdsIDs.begin();
-  for ( ; id != myKeepAgrCmdsIDs.end(); ++id )
-    if ( *id != objID && theCommand.Search( *id ) > id->Length() )
+  {
+#ifdef USE_STRING_FAMILY
+    _pyID objID;
+    if ( myKeepAgrCmdsIDs.IsIn( theCommand, objID ))
     {
-      Handle(_pyObject) obj = FindObject( *id );
+      Handle(_pyObject) obj = FindObject( objID );
       if ( !obj.IsNull() )
+      {
         obj->AddArgCmd( aCommand );
+        //cout << objID << " found in " << theCommand << endl;
+      }
     }
+#else
+    std::list< _pyID >::const_iterator id = myKeepAgrCmdsIDs.begin();
+    for ( ; id != myKeepAgrCmdsIDs.end(); ++id )
+      if ( *id != objID && theCommand.Search( *id ) > id->Length() )
+      {
+        Handle(_pyObject) obj = FindObject( *id );
+        if ( !obj.IsNull() )
+          obj->AddArgCmd( aCommand );
+      }
+#endif
+  }
 
   // Find an object to process theCommand
 
@@ -1208,6 +1235,8 @@ void _pyGen::Free()
   myHypos.clear();
 
   myFile2ExportedMesh.clear();
+
+  //myKeepAgrCmdsIDs.Print();
 }
 
 //================================================================================
@@ -3624,6 +3653,20 @@ const TCollection_AsciiString & _pyCommand::GetMethod()
   return myMeth;
 }
 
+//================================================================================
+/*!
+ * \brief Returns true if there are brackets after the method
+ */
+//================================================================================
+
+bool _pyCommand::IsMethodCall()
+{
+  if ( GetMethod().IsEmpty() )
+    return false;
+  const char* s = myString.ToCString() + GetBegPos( METHOD_IND ) + myMeth.Length() - 1;
+  return ( s[0] == '(' || s[1] == '(' );
+}
+
 //================================================================================
 /*!
  * \brief Return substring of python command looking like ResVal = Obj.Meth(Arg1,...)
@@ -3810,6 +3853,27 @@ bool _pyCommand::IsStudyEntry( const TCollection_AsciiString& str )
   return nbColons > 2 && str.Length()-nbColons > 2;
 }
 
+//================================================================================
+/*!
+ * \brief Returns true if the string looks like an object ID but not like a list,
+ *        string, command etc.
+ */
+//================================================================================
+
+bool _pyCommand::IsID( const TCollection_AsciiString& str )
+{
+  if ( str.Length() < 1 ) return false;
+
+  if ( isdigit( str.Value( 1 )))
+    return IsStudyEntry( str );
+
+  for ( int i = 1; i <= str.Length(); ++i )
+    if ( !isalnum( str.Value( i )) && !str.Value( i ) != '_' )
+      return false;
+
+  return true;
+}
+
 //================================================================================
 /*!
  * \brief Finds entries in a sting
@@ -4167,11 +4231,12 @@ void _pySelfEraser::Flush()
  */
 //================================================================================
 
-_pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd):
+_pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd, bool toKeepAgrCmds):
   _pyObject(theCreationCmd)
 {
   myMesh = ObjectToMesh( theGen->FindObject( theCreationCmd->GetObject() ));
-  theGen->KeepAgrCmds( GetID() ); // ask to fill myArgCmds
+  if ( toKeepAgrCmds )
+    theGen->KeepAgrCmds( GetID() ); // ask to fill myArgCmds
 }
 
 //================================================================================
@@ -4257,7 +4322,7 @@ void _pySubMesh::Flush()
 //================================================================================
 
 _pyGroup::_pyGroup(const Handle(_pyCommand)& theCreationCmd, const _pyID & id)
-  :_pySubMesh(theCreationCmd)
+  :_pySubMesh(theCreationCmd, /*toKeepAgrCmds=*/false)
 {
   if ( !id.IsEmpty() )
     setID( id );
@@ -4734,3 +4799,201 @@ _pyHypothesisReader::GetHypothesis(const _AString&           hypType,
   }
   return resHyp;
 }
+
+//================================================================================
+/*!
+ * \brief Adds an object ID to some family of IDs with a common prefix
+ *  \param [in] str - the object ID
+ *  \return bool - \c false if \a str does not have the same prefix as \a this family
+ *          (for internal usage)
+ */
+//================================================================================
+
+bool _pyStringFamily::Add( const char* str )
+{
+  if ( strncmp( str, _prefix.ToCString(), _prefix.Length() ) != 0 )
+    return false; // expected prefix is missing
+
+  str += _prefix.Length(); // skip _prefix
+
+  // try to add to some of child falimies
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  for ( ; itSub != _subFams.end(); ++itSub )
+    if ( itSub->Add( str ))
+      return true;
+
+  // no suitable family found - add str to _strings or create a new child family
+
+  // look for a proper place within sorted _strings
+  std::list< _AString >::iterator itStr = _strings.begin();
+  while ( itStr != _strings.end() && itStr->IsLess( str ))
+    ++itStr;
+  if ( itStr != _strings.end() && itStr->IsEqual( str ))
+    return true; // same ID already kept
+
+  const int minPrefixSize = 4;
+
+  // count "smaller" strings with the same prefix
+  std::list< _AString >::iterator itLess = itStr; --itLess;
+  int nbLess = 0;
+  for ( ; itLess != _strings.end(); --itLess )
+    if ( strncmp( str, itLess->ToCString(), minPrefixSize ) == 0 )
+      ++nbLess;
+    else
+      break;
+  ++itLess;
+  // count "greater" strings with the same prefix
+  std::list< _AString >::iterator itMore = itStr;
+  int nbMore = 0;
+  for ( ; itMore != _strings.end(); ++itMore )
+    if ( strncmp( str, itMore->ToCString(), minPrefixSize ) == 0 )
+      ++nbMore;
+    else
+      break;
+  --itMore;
+  if ( nbLess + nbMore > 1 ) // ------- ADD a NEW CHILD FAMILY -------------
+  {
+    // look for a maximal prefix length
+    // int lessPrefSize = 3, morePrefSize = 3;
+    // if ( nbLess > 0 )
+    //   while( itLess->ToCString()[ lessPrefSize ] == str[ lessPrefSize ]  )
+    //     ++lessPrefSize;
+    // if ( nbMore > 0 )
+    //   while ( itMore->ToCString()[ morePrefSize ] == str[ morePrefSize ] )
+    //     ++morePrefSize;
+    // int prefixSize = 3;
+    // if ( nbLess == 0 )
+    //   prefixSize = morePrefSize;
+    // else if ( nbMore == 0 )
+    //   prefixSize = lessPrefSize;
+    // else
+    //   prefixSize = Min( lessPrefSize, morePrefSize );
+    int prefixSize = minPrefixSize;
+    _AString newPrefix ( str, prefixSize );
+
+    // look for a proper place within _subFams sorted by _prefix
+    for ( itSub = _subFams.begin(); itSub != _subFams.end(); ++itSub )
+      if ( !itSub->_prefix.IsLess( newPrefix ))
+        break;
+
+    // add the new _pyStringFamily
+    itSub = _subFams.insert( itSub, _pyStringFamily());
+    _pyStringFamily& newSubFam = *itSub;
+    newSubFam._prefix = newPrefix;
+
+    // pass this->_strings to newSubFam._strings
+    for ( itStr = itLess; nbLess > 0; --nbLess, ++itStr )
+      newSubFam._strings.push_back( itStr->ToCString() + prefixSize );
+    newSubFam._strings.push_back( str + prefixSize );
+    for ( ; nbMore > 0; --nbMore, ++itStr )
+      newSubFam._strings.push_back( itStr->ToCString() + prefixSize );
+
+    _strings.erase( itLess, ++itMore );
+  }
+  else // to few string to make a family fot them
+  {
+    _strings.insert( itStr, str );
+  }
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief Finds an object ID in the command
+ *  \param [in] longStr - the command string
+ *  \param [out] subStr - the found object ID
+ *  \return bool - \c true if the object ID found
+ */
+//================================================================================
+
+bool _pyStringFamily::IsIn( const _AString& longStr, _AString& subStr )
+{
+  const char* s = longStr.ToCString();
+
+  // look in _subFams
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  int pos, len;
+  for ( ; itSub != _subFams.end(); ++itSub )
+  {
+    if (( pos = longStr.Search( itSub->_prefix )-1) > 6-1 ) // 6 = strlen("a=b.c(")
+      if (( len = itSub->isIn( s + pos + itSub->_prefix.Length() )) >= 0 )
+      {
+        subStr = _AString( s + pos, len + itSub->_prefix.Length() );
+        return true;
+      }
+  }
+  // look among _strings
+  std::list< _AString >::iterator itStr = _strings.begin();
+  for ( ; itStr != _strings.end(); ++itStr )
+    if ( longStr.Search( *itStr ) > itStr->Length() )
+    {
+      subStr = *itStr;
+      return true;
+    }
+  return false;
+}
+
+//================================================================================
+/*!
+ * \brief Return remainder length of the object ID after my _prefix
+ *  \param [in] str - remainder of the command after my _prefix
+ *  \return int - length of the object ID or -1 if not found
+ */
+//================================================================================
+
+int _pyStringFamily::isIn( const char* str )
+{
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  int len;
+  for ( ; itSub != _subFams.end(); ++itSub )
+  {
+    int cmp = strncmp( str, itSub->_prefix.ToCString(), itSub->_prefix.Length() );
+    if ( cmp == 0 )
+    {
+      if (( len = itSub->isIn( str + itSub->_prefix.Length() )) >= 0 )
+        return itSub->_prefix.Length() + len;
+    }
+    else if ( cmp > 0 )
+      break;
+  }
+  if ( !_strings.empty() )
+  {
+    std::list< _AString >::iterator itStr = _strings.begin();
+    bool firstEmpty = itStr->IsEmpty();
+    if ( firstEmpty )
+      ++itStr;
+    for ( ; itStr != _strings.end(); ++itStr )
+    {
+      int cmp = strncmp( str, itStr->ToCString(), itStr->Length() );
+      if ( cmp == 0 )
+        return itStr->Length();
+      else if ( cmp < 0 )
+        break;
+    }
+    if ( firstEmpty )
+      return 0;
+  }
+
+  return -1;
+}
+
+//================================================================================
+/*!
+ * \brief DEBUG
+ */
+//================================================================================
+
+void _pyStringFamily::Print( int level )
+{
+  cout << string( level, ' ' ) << "prefix = '" << _prefix << "' : ";
+  std::list< _AString >::iterator itStr = _strings.begin();
+  for ( ; itStr != _strings.end(); ++itStr )
+    cout << *itStr << " | ";
+  cout << endl;
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  for ( ; itSub != _subFams.end(); ++itSub )
+    itSub->Print( level + 1 );
+  if ( level == 0 )
+    cout << string( 70, '-' ) << endl;
+}
+
index f5550889b48673624e99c67f42662725dffcdf81..607136e2f73cd93bb371c3e85c2bff78f4bf36af 100644 (file)
@@ -42,6 +42,8 @@
 #include <SALOMEconfig.h>
 #include CORBA_CLIENT_HEADER(SALOMEDS)
 
+#define USE_STRING_FAMILY
+
 // ===========================================================================================
 /*!
  * This file was created in order to respond to requirement of bug PAL10494:
@@ -129,6 +131,7 @@ public:
   const _AString & GetMethod();
   const _AString & GetArg( int index );
   int GetNbArgs() { FindAllArgs(); return myArgs.Length(); }
+  bool IsMethodCall();
   bool MethodStartsFrom(const _AString& beg)
   { GetMethod(); return ( myMeth.Location( beg, 1, myMeth.Length() ) == 1 ); }
   void SetResultValue( const _AString& theResult )
@@ -144,6 +147,7 @@ public:
   static _AString GetWord( const _AString & theSring, int & theStartPos,
                            const bool theForward, const bool dotIsWord = false);
   static bool IsStudyEntry( const _AString& str );
+  static bool IsID( const _AString& str );
   static std::list< _pyID > GetStudyEntries( const _AString& str );
   void AddDependantCmd( Handle(_pyCommand) cmd, bool prepend = false)
   { if (prepend) myDependentCmds.push_front( cmd ); else myDependentCmds.push_back( cmd ); }
@@ -214,6 +218,26 @@ struct ExportedMeshData
   }
 };
 
+// -------------------------------------------------------------------------------------
+/*!
+ * \brief A container of strings groupped by prefix. It is used for a faster search of
+ *        objects requiring to KeepAgrCmds() in commands. A speed up is gained because
+ *        only a common prefix (e.g. "aArea") of many object IDs is searched in a command
+ *        and not every object ID
+ */
+// -------------------------------------------------------------------------------------
+class _pyStringFamily
+{
+  _AString                     _prefix;
+  std::list< _pyStringFamily > _subFams;
+  std::list< _AString >        _strings;
+  int isIn( const char* str );
+public:
+  bool Add( const char* str );
+  bool IsIn( const _AString& str, _AString& subStr );
+  void Print( int level = 0 );
+};
+
 // -------------------------------------------------------------------------------------
 /*!
  * \brief Class corresponding to SMESH_Gen. It holds info on existing
@@ -254,7 +278,11 @@ public:
   bool IsGeomObject(const _pyID& theObjID) const;
   bool IsNotPublished(const _pyID& theObjID) const;
   void ObjectCreationRemoved(const _pyID& theObjID);
+#ifdef USE_STRING_FAMILY
+  void KeepAgrCmds(const _pyID& theObjID) { myKeepAgrCmdsIDs.Add( theObjID.ToCString() ); }
+#else
   void KeepAgrCmds(const _pyID& theObjID) { myKeepAgrCmdsIDs.push_back( theObjID ); }
+#endif
   bool IsToKeepAllCommands() const { return myToKeepAllCommands; }
   void AddExportedMesh(const _AString& file, const ExportedMeshData& mesh )
   { myFile2ExportedMesh[ file ] = mesh; }
@@ -279,7 +307,11 @@ private:
   std::map< _pyID, Handle(_pyMeshEditor) >  myMeshEditors;
   std::map< _pyID, Handle(_pyObject) >      myObjects;
   std::map< _pyID, Handle(_pyHypothesis) >  myHypos;
+#ifdef USE_STRING_FAMILY
+  _pyStringFamily                           myKeepAgrCmdsIDs;
+#else
   std::list< _pyID >                        myKeepAgrCmdsIDs;
+#endif
   std::list< Handle(_pyCommand) >           myCommands;
   int                                       myNbCommands;
   Resource_DataMapOfAsciiStringAsciiString& myID2AccessorMethod;
@@ -555,7 +587,7 @@ class _pySubMesh:  public _pyObject
   Handle(_pyObject) myCreator;
   Handle(_pyMesh) myMesh;
 public:
-  _pySubMesh(const Handle(_pyCommand)& theCreationCmd);
+  _pySubMesh(const Handle(_pyCommand)& theCreationCmd, bool toKeepAgrCmds=true);
   virtual void Process( const Handle(_pyCommand)& theCommand);
   virtual void Flush();
   virtual Handle(_pyMesh) GetMesh() { return myMesh; }
@@ -592,7 +624,7 @@ DEFINE_STANDARD_HANDLE (_pyFilter, _pyObject);
  * \brief To convert creation of a group by filter
  */
 // -------------------------------------------------------------------------------------
-class _pyGroup:  public _pySubMesh
+class _pyGroup:  public _pySubMesh // use myMesh of _pySubMesh
 {
   Handle(_pyFilter) myFilter;
   bool              myCanClearCreationCmd;