• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdeedu
  • Sitemap
  • Contact Us
 

kig

object_hierarchy.cc

Go to the documentation of this file.
00001 // Copyright (C)  2003  Dominique Devriese <devriese@kde.org>
00002 
00003 // This program is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU General Public License
00005 // as published by the Free Software Foundation; either version 2
00006 // of the License, or (at your option) any later version.
00007 
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00016 // 02110-1301, USA.
00017 
00018 #include "object_hierarchy.h"
00019 
00020 #include "../objects/object_holder.h"
00021 #include "../objects/other_type.h"
00022 #include "../objects/object_imp.h"
00023 #include "../objects/object_imp_factory.h"
00024 #include "../objects/object_type_factory.h"
00025 #include "../objects/bogus_imp.h"
00026 #include "../objects/transform_types.h"
00027 #include "../objects/object_type.h"
00028 
00029 #include <kglobal.h>
00030 #include <qdom.h>
00031 
00032 class ObjectHierarchy::Node
00033 {
00034 public:
00035   enum { ID_PushStack, ID_ApplyType, ID_FetchProp };
00036   virtual int id() const = 0;
00037 
00038   virtual ~Node();
00039   virtual Node* copy() const = 0;
00040 
00041   virtual void apply( std::vector<const ObjectImp*>& stack, int loc,
00042                       const KigDocument& ) const = 0;
00043 
00044   virtual void apply( std::vector<ObjectCalcer*>& stack, int loc ) const = 0;
00045 
00046   // this function is used to check whether the final objects depend
00047   // on the given objects.  The dependsstack contains a set of
00048   // booleans telling which parts of the hierarchy certainly depend on
00049   // the given objects.  In this function, the node should check
00050   // whether any of its parents have true set, and if so, set its own
00051   // value to true.
00052   virtual void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const = 0;
00053   // this function is used to check whether the given objects are all
00054   // used by one or more of the final objects.  The usedstack contains
00055   // a set of booleans telling which parts of the hierarchy are
00056   // certainly ancestors of the final objects.  In this function, the
00057   // node should set all of its parents' booleans to true.
00058   virtual void checkArgumentsUsed( std::vector<bool>& usedstack ) const = 0;
00059 };
00060 
00061 ObjectHierarchy::Node::~Node()
00062 {
00063 }
00064 
00065 class PushStackNode
00066   : public ObjectHierarchy::Node
00067 {
00068   ObjectImp* mimp;
00069 public:
00070   PushStackNode( ObjectImp* imp ) : mimp( imp ) {}
00071   ~PushStackNode();
00072 
00073   const ObjectImp* imp() const { return mimp; }
00074 
00075   int id() const;
00076   Node* copy() const;
00077   void apply( std::vector<const ObjectImp*>& stack,
00078               int loc, const KigDocument& ) const;
00079   void apply( std::vector<ObjectCalcer*>& stack, int loc ) const;
00080 
00081   void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const;
00082   void checkArgumentsUsed( std::vector<bool>& usedstack ) const;
00083 };
00084 
00085 void PushStackNode::checkArgumentsUsed( std::vector<bool>& ) const
00086 {
00087 }
00088 
00089 void PushStackNode::apply( std::vector<ObjectCalcer*>& stack, int loc ) const
00090 {
00091   stack[loc] = new ObjectConstCalcer( mimp->copy() );
00092 }
00093 
00094 void PushStackNode::checkDependsOnGiven( std::vector<bool>&, int ) const {
00095   // pushstacknode depends on nothing..
00096   return;
00097 }
00098 
00099 int PushStackNode::id() const { return ID_PushStack; }
00100 
00101 PushStackNode::~PushStackNode()
00102 {
00103   delete mimp;
00104 }
00105 
00106 ObjectHierarchy::Node* PushStackNode::copy() const
00107 {
00108   return new PushStackNode( mimp->copy() );
00109 }
00110 
00111 void PushStackNode::apply( std::vector<const ObjectImp*>& stack,
00112                            int loc, const KigDocument& ) const
00113 {
00114   stack[loc] = mimp->copy();
00115 }
00116 
00117 class ApplyTypeNode
00118   : public ObjectHierarchy::Node
00119 {
00120   const ObjectType* mtype;
00121   std::vector<int> mparents;
00122 public:
00123   ApplyTypeNode( const ObjectType* type, const std::vector<int>& parents )
00124     : mtype( type ), mparents( parents ) {}
00125   ~ApplyTypeNode();
00126   Node* copy() const;
00127 
00128   const ObjectType* type() const { return mtype; }
00129   const std::vector<int>& parents() const { return mparents; }
00130 
00131   int id() const;
00132   void apply( std::vector<const ObjectImp*>& stack,
00133               int loc, const KigDocument& ) const;
00134   void apply( std::vector<ObjectCalcer*>& stack, int loc ) const;
00135 
00136   void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const;
00137   void checkArgumentsUsed( std::vector<bool>& usedstack ) const;
00138 };
00139 
00140 int ApplyTypeNode::id() const { return ID_ApplyType; }
00141 
00142 void ApplyTypeNode::checkArgumentsUsed( std::vector<bool>& usedstack ) const
00143 {
00144   for ( uint i = 0; i < mparents.size(); ++i )
00145   {
00146     usedstack[mparents[i]] = true;
00147   }
00148 }
00149 
00150 void ApplyTypeNode::checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const
00151 {
00152   bool result = false;
00153   for ( uint i = 0; i < mparents.size(); ++i )
00154     if ( dependsstack[mparents[i]] == true ) result = true;
00155   dependsstack[loc] = result;
00156 }
00157 
00158 ApplyTypeNode::~ApplyTypeNode()
00159 {
00160 }
00161 
00162 ObjectHierarchy::Node* ApplyTypeNode::copy() const
00163 {
00164   return new ApplyTypeNode( mtype, mparents );
00165 }
00166 
00167 void ApplyTypeNode::apply( std::vector<ObjectCalcer*>& stack, int loc ) const
00168 {
00169   std::vector<ObjectCalcer*> parents;
00170   for ( uint i = 0; i < mparents.size(); ++i )
00171     parents.push_back( stack[ mparents[i] ] );
00172   stack[loc] = new ObjectTypeCalcer( mtype, parents );
00173 }
00174 
00175 void ApplyTypeNode::apply( std::vector<const ObjectImp*>& stack,
00176                            int loc, const KigDocument& doc ) const
00177 {
00178   Args args;
00179   for ( uint i = 0; i < mparents.size(); ++i )
00180     args.push_back( stack[mparents[i]] );
00181   args = mtype->sortArgs( args );
00182   stack[loc] = mtype->calc( args, doc );
00183 }
00184 
00185 class FetchPropertyNode
00186   : public ObjectHierarchy::Node
00187 {
00188   mutable int mpropgid;
00189   int mparent;
00190   const QByteArray mname;
00191 public:
00192   // propgid is a cache of the global id of property "name",
00193   // just as it is in PropertyObject.  We
00194   // don't want to ever save this value, since we cannot guarantee it
00195   // remains consistent if we add properties some place..
00196   FetchPropertyNode( const int parent, const QByteArray& name, const int propgid = -1 )
00197     : mpropgid( propgid ), mparent( parent ), mname( name ) {}
00198   ~FetchPropertyNode();
00199   Node* copy() const;
00200 
00201   void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const;
00202   void checkArgumentsUsed( std::vector<bool>& usedstack ) const;
00203   int parent() const { return mparent; }
00204   const QByteArray& propinternalname() const { return mname; }
00205 
00206   int id() const;
00207   void apply( std::vector<const ObjectImp*>& stack,
00208               int loc, const KigDocument& ) const;
00209   void apply( std::vector<ObjectCalcer*>& stack, int loc ) const;
00210 };
00211 
00212 FetchPropertyNode::~FetchPropertyNode()
00213 {
00214 }
00215 
00216 void FetchPropertyNode::checkArgumentsUsed( std::vector<bool>& usedstack ) const
00217 {
00218   usedstack[mparent] = true;
00219 }
00220 
00221 void FetchPropertyNode::checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const
00222 {
00223   dependsstack[loc] = dependsstack[mparent];
00224 }
00225 
00226 ObjectHierarchy::Node* FetchPropertyNode::copy() const
00227 {
00228   return new FetchPropertyNode( mparent, mname, mpropgid );
00229 }
00230 
00231 int FetchPropertyNode::id() const
00232 {
00233   return ID_FetchProp;
00234 }
00235 
00236 void FetchPropertyNode::apply( std::vector<const ObjectImp*>& stack,
00237                                int loc, const KigDocument& d ) const
00238 {
00239   assert( stack[mparent] );
00240   if ( mpropgid == -1 ) mpropgid = stack[mparent]->getPropGid( mname );
00241   if ( mpropgid != -1 )
00242     stack[loc] = stack[mparent]->property(
00243            stack[mparent]->getPropLid( mpropgid ), d );
00244   else
00245     stack[loc] = new InvalidImp();
00246 }
00247 
00248 void FetchPropertyNode::apply( std::vector<ObjectCalcer*>& stack, int loc ) const
00249 {
00250   if ( mpropgid == -1 )
00251     mpropgid = stack[mparent]->imp()->getPropGid( mname );
00252   assert( mpropgid != -1 );
00253   stack[loc] = new ObjectPropertyCalcer( stack[mparent], mpropgid, false );
00254 }
00255 
00256 std::vector<ObjectImp*> ObjectHierarchy::calc( const Args& a, const KigDocument& doc ) const
00257 {
00258   assert( a.size() == mnumberofargs );
00259   for ( uint i = 0; i < a.size(); ++i )
00260     assert( a[i]->inherits( margrequirements[i] ) );
00261 
00262   std::vector<const ObjectImp*> stack;
00263   stack.resize( mnodes.size() + mnumberofargs, 0 );
00264   std::copy( a.begin(), a.end(), stack.begin() );
00265   for( uint i = 0; i < mnodes.size(); ++i )
00266   {
00267     mnodes[i]->apply( stack, mnumberofargs + i, doc );
00268   };
00269   for ( uint i = mnumberofargs; i < stack.size() - mnumberofresults; ++i )
00270     delete stack[i];
00271   if ( stack.size() < mnumberofargs + mnumberofresults )
00272   {
00273     std::vector<ObjectImp*> ret;
00274     ret.push_back( new InvalidImp );
00275     return ret;
00276   }
00277   else
00278   {
00279     std::vector<ObjectImp*> ret;
00280     for ( uint i = stack.size() - mnumberofresults; i < stack.size(); ++i )
00281       ret.push_back( const_cast<ObjectImp*>( stack[i] ) );
00282     return ret;
00283   };
00284 }
00285 
00286 int ObjectHierarchy::visit( const ObjectCalcer* o, std::map<const ObjectCalcer*, int>& seenmap,
00287                             bool needed, bool neededatend )
00288 {
00289   using namespace std;
00290 
00291   std::map<const ObjectCalcer*, int>::iterator smi = seenmap.find( o );
00292   if ( smi != seenmap.end() )
00293   {
00294     if ( neededatend )
00295     {
00296       // neededatend means that this object is one of the resultant
00297       // objects.  Therefore, its node has to appear at the end,
00298       // because that's where we expect it..  We therefore copy it
00299       // there using CopyObjectType..
00300       int ret = mnumberofargs + mnodes.size();
00301       std::vector<int> parents;
00302       parents.push_back( smi->second );
00303       mnodes.push_back( new ApplyTypeNode( CopyObjectType::instance(), parents ) );
00304       return ret;
00305     }
00306     else return smi->second;
00307   }
00308 
00309   std::vector<ObjectCalcer*> p( o->parents() );
00310   // we check if o descends from the given objects..
00311   bool descendsfromgiven = false;
00312   std::vector<int> parents;
00313   parents.resize( p.size(), -1 );
00314   for ( uint i = 0; i < p.size(); ++i )
00315   {
00316     int v = visit( p[i], seenmap, false );
00317     parents[i] = v;
00318     descendsfromgiven |= (v != -1);
00319   };
00320 
00321   if ( ! descendsfromgiven && ! ( needed && o->imp()->isCache() ) )
00322   {
00323     if ( needed )
00324     {
00325       assert( ! o->imp()->isCache() );
00326       // o is an object that does not depend on the given objects, but
00327       // is needed by other objects, so we just have to just save its
00328       // current value here.
00329       Node* node = new PushStackNode( o->imp()->copy() );
00330       mnodes.push_back( node );
00331       int ret = mnodes.size() + mnumberofargs - 1;
00332       seenmap[o] = ret;
00333       return ret;
00334     }
00335     else
00336       return -1;
00337   };
00338 
00339   return storeObject( o, p, parents, seenmap );
00340 }
00341 
00342 ObjectHierarchy::~ObjectHierarchy()
00343 {
00344   for ( uint i = 0; i < mnodes.size(); ++i ) delete mnodes[i];
00345 }
00346 
00347 ObjectHierarchy::ObjectHierarchy( const ObjectHierarchy& h )
00348   : mnumberofargs( h.mnumberofargs ), mnumberofresults( h.mnumberofresults ),
00349     msaveinputtags( h.msaveinputtags ),
00350     margrequirements( h.margrequirements ), musetexts( h.musetexts ),
00351     mselectstatements( h.mselectstatements )
00352 {
00353   mnodes.reserve( h.mnodes.size() );
00354   for ( uint i = 0; i < h.mnodes.size(); ++i )
00355     mnodes.push_back( h.mnodes[i]->copy() );
00356 }
00357 
00358 ObjectHierarchy ObjectHierarchy::withFixedArgs( const Args& a ) const
00359 {
00360   assert( a.size() <= mnumberofargs );
00361   ObjectHierarchy ret( *this );
00362 
00363   ret.mnumberofargs -= a.size();
00364   ret.margrequirements.resize( ret.mnumberofargs );
00365 
00366   std::vector<Node*> newnodes( mnodes.size() + a.size() );
00367   std::vector<Node*>::iterator newnodesiter = newnodes.begin();
00368   for ( uint i = 0; i < a.size(); ++i )
00369   {
00370     assert( ! a[i]->isCache() );
00371     *newnodesiter++ = new PushStackNode( a[i]->copy() );
00372   };
00373   std::copy( ret.mnodes.begin(), ret.mnodes.end(), newnodesiter );
00374   ret.mnodes = newnodes;
00375 
00376   return ret;
00377 }
00378 
00379 void ObjectHierarchy::init( const std::vector<ObjectCalcer*>& from, const std::vector<ObjectCalcer*>& to )
00380 {
00381   msaveinputtags = false;
00382   mnumberofargs = from.size();
00383   mnumberofresults = to.size();
00384   margrequirements.resize( from.size(), ObjectImp::stype() );
00385   musetexts.resize( margrequirements.size(), "" );
00386   std::map<const ObjectCalcer*, int> seenmap;
00387   for ( uint i = 0; i < from.size(); ++i )
00388     seenmap[from[i]] = i;
00389   for ( std::vector<ObjectCalcer*>::const_iterator i = to.begin(); i != to.end(); ++i )
00390   {
00391     std::vector<ObjectCalcer*> parents = (*i)->parents();
00392     for ( std::vector<ObjectCalcer*>::const_iterator j = parents.begin();
00393           j != parents.end(); ++j )
00394       visit( *j, seenmap, true );
00395   }
00396   for ( std::vector<ObjectCalcer*>::const_iterator i = to.begin(); i != to.end(); ++i )
00397     visit( *i, seenmap, true, true );
00398 
00399   mselectstatements.resize( margrequirements.size(), "" );
00400 }
00401 
00402 ObjectHierarchy::ObjectHierarchy( const std::vector<ObjectCalcer*>& from, const ObjectCalcer* to )
00403 {
00404   std::vector<ObjectCalcer*> tov;
00405   tov.push_back( const_cast<ObjectCalcer*>( to ) );
00406   init( from, tov );
00407 }
00408 
00409 ObjectHierarchy::ObjectHierarchy( const std::vector<ObjectCalcer*>& from, const std::vector<ObjectCalcer*>& to )
00410 {
00411   init( from, to );
00412 }
00413 
00414 void ObjectHierarchy::serialize( QDomElement& parent, QDomDocument& doc ) const
00415 {
00416   int id = 1;
00417   for ( uint i = 0; i < mnumberofargs; ++i )
00418   {
00419     QDomElement e = doc.createElement( "input" );
00420     e.setAttribute( "id", id++ );
00421     e.setAttribute( "requirement", margrequirements[i]->internalName() );
00422     // we don't save these atm, since the user can't define them.
00423     // we only load them from builtin macro's.
00424     if ( msaveinputtags )
00425     {
00426       QDomElement ut = doc.createElement( "UseText" );
00427       ut.appendChild( doc.createTextNode( QString::fromLatin1(musetexts[i].c_str() ) ) );
00428       e.appendChild( ut );
00429       QDomElement ss = doc.createElement( "SelectStatement" );
00430       ss.appendChild( doc.createTextNode( QString::fromLatin1(mselectstatements[i].c_str() ) ) );
00431       e.appendChild( ss );
00432     }
00433     parent.appendChild( e );
00434   }
00435 
00436   for ( uint i = 0; i < mnodes.size(); ++i )
00437   {
00438     bool result = mnodes.size() - ( id - mnumberofargs - 1 ) <= mnumberofresults;
00439     QDomElement e = doc.createElement( result ? "result" : "intermediate" );
00440     e.setAttribute( "id", id++ );
00441 
00442     if ( mnodes[i]->id() == Node::ID_ApplyType )
00443     {
00444       const ApplyTypeNode* node = static_cast<const ApplyTypeNode*>( mnodes[i] );
00445       e.setAttribute( "action", "calc" );
00446       e.setAttribute( "type", QString::fromLatin1( node->type()->fullName() ) );
00447       for ( uint i = 0; i < node->parents().size(); ++i )
00448       {
00449         int parent = node->parents()[i] + 1;
00450         QDomElement arge = doc.createElement( "arg" );
00451         arge.appendChild( doc.createTextNode( QString::number( parent ) ) );
00452         e.appendChild( arge );
00453       };
00454     }
00455     else if ( mnodes[i]->id() == Node::ID_FetchProp )
00456     {
00457       const FetchPropertyNode* node = static_cast<const FetchPropertyNode*>( mnodes[i] );
00458       e.setAttribute( "action", "fetch-property" );
00459       e.setAttribute( "property", QString( node->propinternalname() ) );
00460       QDomElement arge = doc.createElement( "arg" );
00461       arge.appendChild( doc.createTextNode( QString::number( node->parent() + 1 ) ) );
00462       e.appendChild( arge );
00463     }
00464     else
00465     {
00466       assert( mnodes[i]->id() == ObjectHierarchy::Node::ID_PushStack );
00467       const PushStackNode* node = static_cast<const PushStackNode*>( mnodes[i] );
00468       e.setAttribute( "action", "push" );
00469       QString type = ObjectImpFactory::instance()->serialize( *node->imp(), e, doc );
00470       e.setAttribute( "type", type );
00471     };
00472 
00473     parent.appendChild( e );
00474   };
00475 }
00476 
00477 ObjectHierarchy::ObjectHierarchy()
00478   : mnumberofargs( 0 ), mnumberofresults( 0 ), msaveinputtags( false )
00479 {
00480 }
00481 
00482 ObjectHierarchy* ObjectHierarchy::buildSafeObjectHierarchy( const QDomElement& parent, QString& error )
00483 {
00484 #define KIG_GENERIC_PARSE_ERROR \
00485   { \
00486     error = i18n( "An error was encountered at line %1 in file %2.", \
00487               __LINE__, __FILE__ ); \
00488     return 0; \
00489   }
00490 
00491   ObjectHierarchy* obhi = new ObjectHierarchy();
00492 
00493   bool ok = true;
00494   QString tmp;
00495   QDomElement e = parent.firstChild().toElement();
00496   for (; !e.isNull(); e = e.nextSibling().toElement() )
00497   {
00498     if ( e.tagName() != "input" ) break;
00499 
00500     tmp = e.attribute( "id" );
00501     uint id = tmp.toInt( &ok );
00502     if ( !ok ) KIG_GENERIC_PARSE_ERROR;
00503 
00504     obhi->mnumberofargs = qMax( id, obhi->mnumberofargs );
00505 
00506     tmp = e.attribute( "requirement" );
00507     const ObjectImpType* req = ObjectImpType::typeFromInternalName( tmp.toLatin1() );
00508     if ( req == 0 ) req = ObjectImp::stype(); // sucks, i know..
00509     obhi->margrequirements.resize( obhi->mnumberofargs, ObjectImp::stype() );
00510     obhi->musetexts.resize( obhi->mnumberofargs, "" );
00511     obhi->mselectstatements.resize( obhi->mnumberofargs, "" );
00512     obhi->margrequirements[id - 1] = req;
00513     obhi->musetexts[id - 1] = req->selectStatement();
00514     QDomElement esub = e.firstChild().toElement();
00515     for ( ; !esub.isNull(); esub = esub.nextSibling().toElement() )
00516     {
00517       if ( esub.tagName() == "UseText" )
00518       {
00519         obhi->msaveinputtags = true;
00520         obhi->musetexts[id - 1] = esub.text().toLatin1().data();
00521       }
00522       else if ( esub.tagName() == "SelectStatement" )
00523       {
00524         obhi->msaveinputtags = true;
00525         obhi->mselectstatements[id - 1] = esub.text().toLatin1().data();
00526       }
00527       else
00528       {
00529         // broken file ? ignore...
00530       }
00531     }
00532   }
00533   for (; !e.isNull(); e = e.nextSibling().toElement() )
00534   {
00535     bool result = e.tagName() == "result";
00536     if ( result ) ++obhi->mnumberofresults;
00537 
00538     tmp = e.attribute( "id" );
00539     int id = tmp.toInt( &ok );
00540     if ( !ok ) KIG_GENERIC_PARSE_ERROR;
00541 
00542     tmp = e.attribute( "action" );
00543     Node* newnode = 0;
00544     if ( tmp == "calc" )
00545     {
00546       // ApplyTypeNode
00547       QByteArray typen = e.attribute( "type" ).toLatin1();
00548       const ObjectType* type = ObjectTypeFactory::instance()->find( typen );
00549       if ( ! type )
00550       {
00551         error = i18n( "This Kig file uses an object of type \"%1\", "
00552                       "which this Kig version does not support. "
00553                       "Perhaps you have compiled Kig without support "
00554                       "for this object type, "
00555                       "or perhaps you are using an older Kig version.", QString( typen ) );
00556         return 0;
00557       }
00558 
00559       std::vector<int> parents;
00560       for ( QDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() )
00561       {
00562         QDomElement q = p.toElement();
00563         if ( q.isNull() ) KIG_GENERIC_PARSE_ERROR; // see above
00564         if ( q.tagName() != "arg" ) KIG_GENERIC_PARSE_ERROR;
00565         int pid = q.text().toInt(&ok );
00566         if ( !ok ) KIG_GENERIC_PARSE_ERROR;
00567         parents.push_back( pid - 1 );
00568       };
00569       newnode = new ApplyTypeNode( type, parents );
00570     }
00571     else if ( tmp == "fetch-property" )
00572     {
00573       // FetchPropertyNode
00574       QByteArray propname = e.attribute( "property" ).toLatin1();
00575       QDomElement arge = e.firstChild().toElement();
00576       int parent = arge.text().toInt( &ok );
00577       if ( !ok ) KIG_GENERIC_PARSE_ERROR;
00578       newnode = new FetchPropertyNode( parent - 1, propname );
00579     }
00580     else
00581     {
00582       // PushStackNode
00583       if ( e.attribute( "action" ) != "push" ) KIG_GENERIC_PARSE_ERROR;
00584       QString typen = e.attribute( "type" );
00585       if ( typen.isNull() ) KIG_GENERIC_PARSE_ERROR;
00586       ObjectImp* imp = ObjectImpFactory::instance()->deserialize( typen, e, error );
00587       if ( ( ! imp ) && !error.isEmpty() ) return 0;
00588       newnode = new PushStackNode( imp );
00589     };
00590     obhi->mnodes.resize( qMax( size_t(id - obhi->mnumberofargs), obhi->mnodes.size() ) );
00591     obhi->mnodes[id - obhi->mnumberofargs - 1] = newnode;
00592   };
00593 
00594   // if we are here, all went fine
00595   return obhi;
00596 }
00597 
00598 ArgsParser ObjectHierarchy::argParser() const
00599 {
00600   std::vector<ArgsParser::spec> specs;
00601   for ( uint i = 0; i < margrequirements.size(); ++i )
00602   {
00603     const ObjectImpType* req = margrequirements[i];
00604     ArgsParser::spec spec;
00605     spec.type = req;
00606     spec.usetext = musetexts[i];
00607     spec.selectstat = mselectstatements[i];
00608     specs.push_back( spec );
00609   };
00610   return ArgsParser( specs );
00611 }
00612 
00613 std::vector<ObjectCalcer*> ObjectHierarchy::buildObjects( const std::vector<ObjectCalcer*>& os, const KigDocument& doc ) const
00614 {
00615   assert( os.size() == mnumberofargs );
00616   for ( uint i = 0; i < os.size(); ++i )
00617     assert( os[i]->imp()->inherits( margrequirements[i] ) );
00618 
00619   std::vector<ObjectCalcer*> stack;
00620   stack.resize( mnodes.size() + mnumberofargs, 0 );
00621   std::copy( os.begin(), os.end(), stack.begin() );
00622 
00623   for( uint i = 0; i < mnodes.size(); ++i )
00624   {
00625     mnodes[i]->apply( stack, mnumberofargs + i );
00626     stack[mnumberofargs + i]->calc( doc );
00627   };
00628 
00629   std::vector<ObjectCalcer*> ret( stack.end() - mnumberofresults, stack.end() );
00630 
00631   return ret;
00632 }
00633 
00634 const ObjectImpType* ObjectHierarchy::idOfLastResult() const
00635 {
00636   const Node* n = mnodes.back();
00637   if ( n->id() == Node::ID_PushStack )
00638     return static_cast<const PushStackNode*>( n )->imp()->type();
00639   else if ( n->id() == Node::ID_FetchProp )
00640     return ObjectImp::stype();
00641   else
00642     return static_cast<const ApplyTypeNode*>( n )->type()->resultId();
00643 }
00644 
00645 ObjectHierarchy ObjectHierarchy::transformFinalObject( const Transformation& t ) const
00646 {
00647   assert( mnumberofresults == 1 );
00648   ObjectHierarchy ret( *this );
00649   ret.mnodes.push_back( new PushStackNode( new TransformationImp( t ) ) );
00650 
00651   std::vector<int> parents;
00652   parents.push_back( ret.mnodes.size() - 1);
00653   parents.push_back( ret.mnodes.size() );
00654   const ObjectType* type = ApplyTransformationObjectType::instance();
00655   ret.mnodes.push_back( new ApplyTypeNode( type, parents ) );
00656   return ret;
00657 }
00658 
00659 bool operator==( const ObjectHierarchy& lhs, const ObjectHierarchy& rhs )
00660 {
00661   if ( ! ( lhs.mnumberofargs == rhs.mnumberofargs &&
00662            lhs.mnumberofresults == rhs.mnumberofresults &&
00663            lhs.margrequirements == rhs.margrequirements &&
00664            lhs.mnodes.size() == rhs.mnodes.size() ) )
00665     return false;
00666 
00667   // this isn't entirely correct, but it will do, because we don't
00668   // really want to know whether the hierarchies are different, but
00669   // whether rhs has changed with regard to lhs..
00670   for ( uint i = 0; i < lhs.mnodes.size(); ++i )
00671     if ( lhs.mnodes[i] != lhs.mnodes[i] )
00672       return false;
00673 
00674   return true;
00675 }
00676 
00677 bool ObjectHierarchy::resultDoesNotDependOnGiven() const
00678 {
00679   std::vector<bool> dependsstack( mnodes.size() + mnumberofargs, false );
00680 
00681   for ( uint i = 0; i < mnumberofargs; ++i )
00682     dependsstack[i] = true;
00683   for ( uint i = 0; i < mnodes.size(); ++i )
00684     mnodes[i]->checkDependsOnGiven( dependsstack, i + mnumberofargs );
00685   for ( uint i = dependsstack.size() - mnumberofresults; i < dependsstack.size(); ++i )
00686     if ( !dependsstack[i] )
00687       return true;
00688   return false;
00689 }
00690 
00691 // returns the "minimum" of a and b ( in the partially ordered set of
00692 // ObjectImpType's, using the inherits member function as comparison,
00693 // if you for some reason like this sort of non-sense ;) ).  This
00694 // basically means: return the type that inherits the other type,
00695 // because if another type inherits the lowermost type, then it will
00696 // also inherit the other..
00697 const ObjectImpType* lowermost( const ObjectImpType* a, const ObjectImpType* b )
00698 {
00699   if ( a->inherits( b ) ) return a;
00700   assert( b->inherits( a ) );
00701   return b;
00702 }
00703 
00704 // this function is part of the visit procedure really.  It is
00705 // factored out, because it recurses for cache ObjectImp's.  What this
00706 // does is, it makes sure that object o is calcable, by putting
00707 // appropriate Node's in mnodes..  po is o->parents() and pl contains
00708 // the location of objects that are already in mnodes and -1
00709 // otherwise..  -1 means we have to store their ObjectImp, unless
00710 // they're cache ObjectImp's etc.
00711 int ObjectHierarchy::storeObject( const ObjectCalcer* o, const std::vector<ObjectCalcer*>& po, std::vector<int>& pl,
00712                                   std::map<const ObjectCalcer*, int>& seenmap )
00713 {
00714   for ( uint i = 0; i < po.size(); ++i )
00715   {
00716     if ( pl[i] == -1 )
00717     {
00718       // we can't store cache ObjectImp's..
00719       if ( po[i]->imp()->isCache() )
00720       {
00721         pl[i] = visit( po[i], seenmap, true, false );
00722       }
00723       else
00724       {
00725         Node* argnode = new PushStackNode( po[i]->imp()->copy() );
00726         mnodes.push_back( argnode );
00727         int argloc = mnumberofargs + mnodes.size() - 1;
00728         seenmap[po[i]] = argloc;
00729         pl[i] = argloc;
00730       };
00731     }
00732     else if ( (uint) pl[i] < mnumberofargs )
00733     {
00734       ObjectCalcer* parent = o->parents()[i];
00735       std::vector<ObjectCalcer*> opl = o->parents();
00736 
00737       margrequirements[pl[i]] =
00738         lowermost( margrequirements[pl[i]],
00739                    o->impRequirement( parent, opl ) );
00740       musetexts[pl[i]] = margrequirements[pl[i]]->selectStatement();
00741     };
00742   };
00743   if ( dynamic_cast<const ObjectTypeCalcer*>( o ) )
00744     mnodes.push_back( new ApplyTypeNode( static_cast<const ObjectTypeCalcer*>( o )->type(), pl ) );
00745   else if ( dynamic_cast<const ObjectPropertyCalcer*>( o ) )
00746   {
00747     assert( pl.size() == 1 );
00748     int parent = pl.front();
00749     ObjectCalcer* op = po.front();
00750     assert( op );
00751     int propgid = static_cast<const ObjectPropertyCalcer*>( o )->propGid();
00752 //    assert( propid < op->imp()->propertiesInternalNames().size() );
00753 //    mnodes.push_back( new FetchPropertyNode( parent, op->imp()->propertiesInternalNames()[propid], propgid ) );
00754     mnodes.push_back( new FetchPropertyNode( parent, op->imp()->getPropName( propgid ), propgid ) );
00755   }
00756   else
00757     assert( false );
00758   seenmap[o] = mnumberofargs + mnodes.size() - 1;
00759   return mnumberofargs + mnodes.size() - 1;
00760 }
00761 
00762 ObjectHierarchy::ObjectHierarchy( const ObjectCalcer* from, const ObjectCalcer* to )
00763 {
00764   std::vector<ObjectCalcer*> fromv;
00765   fromv.push_back( const_cast<ObjectCalcer*>( from ) );
00766   std::vector<ObjectCalcer*> tov;
00767   tov.push_back( const_cast<ObjectCalcer*>( to ) );
00768   init( fromv, tov );
00769 }
00770 
00771 bool ObjectHierarchy::allGivenObjectsUsed() const
00772 {
00773   std::vector<bool> usedstack( mnodes.size() + mnumberofargs, false );
00774   for ( uint i = mnodes.size() - mnumberofresults; i < mnodes.size(); ++i )
00775     usedstack[i + mnumberofargs] = true;
00776   for ( int i = mnodes.size() - 1; i >= 0; --i )
00777     if ( usedstack[i + mnumberofargs] )
00778       mnodes[i]->checkArgumentsUsed( usedstack );
00779   for ( uint i = 0; i < mnumberofargs; ++i )
00780     if ( ! usedstack[i] ) return false;
00781   return true;
00782 }
00783 

kig

Skip menu "kig"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

kdeedu

Skip menu "kdeedu"
  • kalzium
  • kanagram
  • kig
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  •   docs
  •   src
  • parley
Generated for kdeedu by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal