Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/Serializer.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2002 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Serializer.cpp 1029 2004-02-11 20:45:54Z jungd $
00019   $Revision: 1.8 $
00020   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <base/Serializer>
00026 
00027 #include <base/Serializable>
00028 
00029 using base::Serializer;
00030 using base::Serializable;
00031 
00032 
00033 #ifdef DEBUG
00034 
00035 // comment out to inhibit serialization debugging
00036 //#define SDEBUG
00037 
00038 #endif
00039 
00040 
00041 Serializer::Serializer(SerializerType type) 
00042   : output(type==Output), follow(true), aborted(false),
00043       serializePointerRecursionDepth(0)
00044 {
00045   ptrs.push_back(0); // the null ptr is a special at index 0 (so nulls can be serialized)
00046   serialized.push_back(true);
00047 }
00048 
00049 Serializer::Serializer(SerializerType type, ref<VFile> archive) 
00050   : output(type==Output), follow(true), aborted(false),
00051       serializePointerRecursionDepth(0) 
00052 {
00053   ptrs.push_back(0); // the null ptr is a special at index 0 (so nulls can be serialized)
00054   serialized.push_back(true);
00055 }
00056 
00057 Serializer::Serializer(SerializerType type, std::ios& stream) 
00058   : output(type==Output), follow(true), aborted(false),
00059       serializePointerRecursionDepth(0)
00060 {
00061   ptrs.push_back(0); // the null ptr is a special at index 0 (so nulls can be serialized)
00062   serialized.push_back(true);
00063 }
00064 
00065 Serializer::~Serializer()
00066 {
00067  if (isOutput() && !aborted) {
00068     // check for objects that have been referenced during Output serialization
00069     //  but not serialized
00070     Int outstandingSerializationCount = 0;
00071     for(Int pi=0; pi<serialized.size(); pi++) 
00072       if (!serialized[pi]) 
00073         outstandingSerializationCount++;
00074     if (outstandingSerializationCount>0) {
00075       Logln("Serializer destruction with outstanding object serializations (objects referenced in the Output stream, but not serialized) - " << outstandingSerializationCount << " objects.");
00076     }
00077   }
00078 }
00079 
00080 
00081 bool Serializer::followReferences(bool follow)
00082 {
00083   if (!follow)
00084     depthAtFollowDisable = serializePointerRecursionDepth;
00085   bool oldfollow = this->follow;
00086   this->follow = follow;
00087   return oldfollow;
00088 }
00089 
00090 
00091 
00092 const String Serializer::inputToConstErrorString("cannot input to a const variable");
00093 
00094 
00095 Serializer& Serializer::serialize(Serializable& r, const String& memberName)
00096 {
00097   String typeName(typeid(r).name());
00098   preSerializeObject(typeName, ObjectType, memberName);
00099   r.serialize(*this);
00100   postSerializeObject(memberName);
00101   return *this;
00102 }
00103 
00104 
00105 
00106 Serializer& Serializer::operator()(Vector& v, const String& memberName)
00107 {
00108   comment(memberName);
00109   if(isOutput()) {
00110     operator()(v.size(),"dim");
00111   }
00112   else {
00113     Int dim;
00114     operator()(dim,"dim");
00115     v.resize(dim);
00116   }
00117 
00118   for(Int i=0; i<v.size(); i++)
00119     operator()(v[i]);
00120 
00121   return *this;
00122 }
00123 
00124 
00125 Serializer& Serializer::operator()(Matrix& m, const String& memberName)
00126 {
00127   comment(memberName);
00128   if(isOutput()) {
00129     operator()(m.size1(),"rows");
00130     operator()(m.size2(),"cols");
00131   }
00132   else {
00133     Int rows, cols;
00134     operator()(rows,"rows");
00135     operator()(cols,"cols");
00136     m.resize(rows,cols);
00137   }
00138 
00139   for(Int r=0; r<m.size1(); r++)
00140     for(Int c=0; c<m.size2(); c++)
00141       operator()(m(r,c));
00142 
00143   return *this;
00144 }
00145 
00146 
00147 
00148 inline Int Serializer::ptrIndex(Serializable* p)
00149 {
00150   for(Int i=ptrs.size()-1; i>0; i--)
00151     if (ptrs[i] == p) return i;
00152   if (ptrs[0] == p) return 0;
00153   return ptrs.size();
00154 }
00155 
00156 
00157 
00158 void Serializer::serializePointer(Serializable*& p, Serializable::SerializableInstantiator* i, const String& memberName, bool forceTypeSerialization)
00159 {
00160   serializePointerRecursionDepth++;
00161 
00162   if (output) { // Output
00163 
00164     Int pi = ptrIndex(p);
00165     if (pi == ptrs.size()) { 
00166       // wasn't found (reference to object not previously encountered)
00167 
00168       if (follow || (!follow && (serializePointerRecursionDepth==depthAtFollowDisable+1)) ) {
00169 #ifdef SDEBUG
00170         Debugln(Ser,String(serializePointerRecursionDepth,' ') << "serializing(out) obj(" << (p?String(instanceof(*p,Object)?dynamic_cast<Object*>(p)->className():"unknown"):"null") << ") [" << pi << "] first encounter");
00171 #endif
00172         // serialize type, index and object
00173         String typeName(typeid(*p).name());
00174         preSerializeObject(typeName,ReferencedObjectType, memberName, forceTypeSerialization);
00175         serializeReferenceIndex(pi); // output index
00176         ptrs.at(pi) = p;
00177         serialized.at(pi) = true;
00178         p->serialize(*this); // output object
00179         postSerializeObject(memberName);
00180       }
00181       else {
00182 #ifdef SDEBUG
00183         Debugln(Ser,String(serializePointerRecursionDepth,' ') << "serializing(out) ptr(" << (p?String(instanceof(*p,Object)?dynamic_cast<Object*>(p)->className():"unknown"):"null") << ") [" << pi << "] first encounter");
00184 #endif
00185         // serialize type and index only
00186         String typeName(typeid(*p).name());
00187         preSerializeObject(typeName,ObjectReferenceType, memberName, forceTypeSerialization);
00188         serializeReferenceIndex(pi); // output index
00189         ptrs.at(pi) = p;
00190         serialized.at(pi) = false;
00191         postSerializeObject(memberName);
00192       }
00193 
00194     }
00195     else { // already been encountered
00196 
00197       if ( (follow || (!follow && (serializePointerRecursionDepth==depthAtFollowDisable+1))) 
00198            && !serialized[pi]) { 
00199 #ifdef SDEBUG
00200         Debugln(Ser,String(serializePointerRecursionDepth,' ') << "serializing(out) obj(" << (p?String(instanceof(*p,Object)?dynamic_cast<Object*>(p)->className():"unknown"):"null") << ") [" << pi << "]");
00201 #endif
00202         // object wasn't serialized on previous encounters, must have been in
00203         //  non-follow mode.  Serialize it now.
00204         String typeName(typeid(*p).name());
00205         preSerializeObject(typeName,ReferencedObjectType, memberName, forceTypeSerialization);
00206         serializeReferenceIndex(pi); // output index
00207         serialized[pi] = true;
00208         p->serialize(*this); // output object
00209         postSerializeObject(memberName);
00210       }
00211       else { 
00212 #ifdef SDEBUG
00213         Debugln(Ser,String(serializePointerRecursionDepth,' ') << "serializing(out) ptr(" << (p?String(instanceof(*p,Object)?dynamic_cast<Object*>(p)->className():"unknown"):"null") << ") [" << pi << "]");
00214 #endif
00215         // never serialize in non-follow mode (just output index)
00216         //  (or if it's already been serialized)
00217         String typeName(typeid(*p).name());
00218         preSerializeObject(typeName,ObjectReferenceType, memberName, forceTypeSerialization);
00219         serializeReferenceIndex(pi); // output index
00220         postSerializeObject(memberName);
00221       }
00222     }
00223   }
00224   else { // Input
00225 
00226     String typeName;
00227     TypeModifier readTypeModifier = preSerializeObject(typeName,UnknownType, memberName, forceTypeSerialization);
00228 
00229     if (readTypeModifier == ReferencedObjectType) { // a referenced object
00230 
00231       // deserialize
00232       Int pi;
00233       serializeReferenceIndex(pi); // read index
00234 
00235       if (pi > ptrs.size())
00236         throw serialization_error(Exception("serialization input stream corrupted (object out of sequence)"));
00237       else {
00238         if (pi == ptrs.size()) { // haven't read object before, instantiate it now
00239           // create an instance to hold the new object, if necessary
00240           if (p==0) {
00241             if (i != 0)
00242               p = i->newSerializable();
00243             else { // dynamically lookup an instantiator
00244               try{
00245                 const Serializable::SerializableInstantiator& i(Serializable::getSerializableInstantiator(String(), typeName));
00246                 p = i.newSerializable();
00247               } catch (std::exception& e) { abort(e.what()); }
00248             }
00249           }
00250           Assert(p);
00251           
00252           if (!typeName.empty()) {
00253             if (typeName != base::className(typeid(*p)))
00254               throw serialization_error(Exception(String("read unexpected object type: ")+typeName+" expected "+base::className(typeid(*p))));
00255           }
00256 
00257 #ifdef SDEBUG
00258           Debugln(Ser,String(serializePointerRecursionDepth,' ') << "serializing(in) obj(" << (p?String(instanceof(*p,Object)?dynamic_cast<Object*>(p)->className():"unknown"):"null") << ") [" << pi << "]" << ((pi == ptrs.size())?" instantiated":"") );
00259 #endif
00260           ptrs.at(pi) = p;
00261         }
00262         else {
00263           // we've encountered the object before - which means it was instantiated
00264           //  but not serialized
00265           p = ptrs[pi];
00266         }
00267         
00268         p->serialize(*this); // input object
00269 
00270         postSerializeObject(memberName);
00271       }
00272     }
00273     else if (readTypeModifier == ObjectReferenceType) { // an object reference
00274 
00275       Int pi;
00276       serializeReferenceIndex(pi); // read index
00277 
00278       if (pi>ptrs.size())
00279         throw serialization_error(Exception("serialization input stream corrupted (reference to object not yet encountered)"));
00280       else {
00281         if (pi == ptrs.size()) { // index to unread object
00282           // create an object of the referenced type using the default constructor
00283           //  (we can't initialize/serialize it until it is encoundered in the stream)
00284           if (p==0) {
00285             if (i != 0)
00286               p = i->newSerializable();
00287             else { // dynamically lookup an instantiator
00288               try {
00289                 const Serializable::SerializableInstantiator& i(Serializable::getSerializableInstantiator(String(), typeName));
00290                 p = i.newSerializable();
00291               } catch (std::exception& e) { abort(e.what()); }
00292             }
00293           }
00294           Assert(p);
00295 
00296           if (!typeName.empty()) {
00297             if (typeName != base::className(typeid(*p)))
00298               throw serialization_error(Exception(String("read unexpected object reference type: ")+typeName+" expected "+base::className(typeid(*p))));
00299           }
00300 #ifdef SDEBUG
00301           Debugln(Ser,String(serializePointerRecursionDepth,' ') << "serializing(in) ptr(" << (p?String(instanceof(*p,Object)?dynamic_cast<Object*>(p)->className():"unknown"):"null") << ") [" << pi << "] instantiated" );
00302 #endif
00303           ptrs.at(pi) = p;
00304         }
00305         else { // backward reference to previously read object
00306           p = ptrs[pi];
00307           Assert(p);
00308 #ifdef SDEBUG
00309           Debugln(Ser,String(serializePointerRecursionDepth,' ') << "serializing(in) ptr(" << (p?String(instanceof(*p,Object)?dynamic_cast<Object*>(p)->className():"unknown"):"null") << ") [" << pi << "]" );
00310 #endif
00311 
00312         }
00313       }
00314 
00315       postSerializeObject(memberName);
00316 
00317     }
00318     else 
00319       throw serialization_error(Exception("serialization input stream corrupted (unknown reference type)"));
00320   }
00321 
00322   serializePointerRecursionDepth--;
00323 
00324 }
00325 
00326 
00327 void Serializer::abort(const String& exceptionString)
00328 { 
00329   if (!aborted) {
00330     aborted=true; 
00331     Logln(exceptionString);
00332     throw serialization_error(Exception(exceptionString)); 
00333   }
00334 }

Generated on Thu Jul 29 15:56:13 2004 for OpenSim by doxygen 1.3.6