// Classe Dynamic Variable List (DVList) de PEIDA // R. Ansari 1997 // LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA #include "machdefs.h" #include #include #include "dvlist.h" #include "strutil.h" namespace SOPHYA { //++ // Class DVList // Lib BaseTools // include dvlist.h // // Cette classe permet de gérer une ensemble de variables (ou paramètres) // pouvant être définies dynamiquement à l'execution. Le nom des // variables ne doit pas contenir de blancs ("") et est // limité à 64 caractères maximum. Cette classe // offre la possibilité de sauvegarder l'ensemble // des variables (Nom, Type, Valeur) dans un fichier, ou de // recréer l'objet DVList et l'ensemble de ses variables à // partir d'un fichier (Objet PPersist). Une zone commentaire (max=320 c.) // est associée à chaque objet DVList, accessible à travers // la méthode "Comment()". Les objets de cette classe sont // en particulier destinés à être inclus dans d'autres objets // PPersist plus complexes. La classe DVList gère des // variables de type entier ("int_8"), réél double précision ("r_8") // et de type chaine de caracteres ("string, char*", maxi 30 caracteres ). // Une classe intermédiaire (*MuTyV*) est utilisée pour représenter une // variable et fournit les services de conversion entre les différents types. //-- //-- //++ // Links Parents // PPersist //-- static MuTyV ddvdum(-9.e19); /*! \class DVList \ingroup BaseTools This class can be used to construct list of values associated with names. Variables names should not contain space characters and is limited to 64 characters. The DVList class uses \b SOPHYA::MuTyV objects to hold values of type string, integer (\b int_8) or float (\b r_8) or time/date (TimeStamp). A comment string can be associated with each variable name. A global comment string can be attached to the DVList object. DVList objects can conveniently be used to represent FITS headers. The class \b SOPHYA::ObjFileIO handles serialisation for DVList. (See SOPHYA::PPersist ). \sa SOPHYA::ObjFileIO \sa SOPHYA::MuTyV \code // ------- Using DVList objects ------ DVList dvl; dvl("toto") = 14; // Integer type value (=14) named toto dvl("titi") = 25.5; // float type value (=25.5) named titi dvl("tata") = "Bonjour !"; // string type value (="Bonjour !") named tata // Upper and lower case letters are distinguished dvl("hello") = 88; dvl("Hello") = 77.77; dvl("ToDay") = TimeStamp(); dvl.Comment() = "DVList test object, with values named hello, Hello "; // Saving the dvl object into a PPF file POutStream os("dvl.ppf"); os << dvl; // later on ... DVList dvlr; PInStream is("dvl.ppf"); is << dvlr; int k = dvlr["toto"] ; // k = 14 r_8 b = dvlr["titi"] ; // b = 25.5 string s = dvlr["tata"] ; // s = "Bonjour !" int m = dvlr["hello"] ; // m = 88 \endcode */ //++ // Titre Constructeurs //-- //++ // DVList() // Constructeur par défaut // DVList(DVList& cfd) // Constructeur par copie. Le nouvel objet est une copie complète de "cfd" // DVList(char* flnm) // Constructeur avec initialisation à partir du contenu du fichier (PPF) // "flnm". Le fichier doit avoir été créé par la méthode "Write()" //-- /* --Methode-- */ /*! Default constructor */ DVList::DVList() { comment = ""; } /* --Methode-- */ /*! copy constructor */ DVList::DVList(const DVList& dvl) { Merge(dvl); } /* --Methode-- */ /*! Copy constructor - Object initialized using the PPF file \b flnm */ DVList::DVList(const char *flnm) { PInPersist s(flnm); ObjFileIO fiodvl(this); fiodvl.Read(s); } /* --Methode-- */ DVList::~DVList() { } //++ // Titre Gestion des variables et opérateurs //-- //++ // void Clear() // Supprime la définition de toutes les variables de l'objet. // DVList& Merge(const DVList& lv) // Fusionne l'objet avec la liste des variables de l'objet "lv" // DVList& operator= (const DVList& cofr) // Remplace la liste des variables de l'objet par celle de l'objet "cofr". //-- /* --Methode-- */ /*! Copy operator - Replaces the variables list with the list from \b dvl */ DVList& DVList::operator= (const DVList& dvl) { Clear(); return(Merge(dvl)); } /* --Methode-- */ /*! Resets the object and clears the variable list and global comment */ void DVList::Clear() { mvlist.erase(mvlist.begin(), mvlist.end()); comment = ""; } /* --Methode-- */ /*! Appends the values from the object \b dvl to the objects list */ DVList& DVList::Merge(const DVList& dvl) { ValList::const_iterator it; for(it = dvl.mvlist.begin(); it != dvl.mvlist.end(); it++) { switch ((*it).second.elval.Type()) { case MuTyV::MTVInteger : SetI((*it).first, (*it).second.elval.GetIntPart()); break; case MuTyV::MTVFloat : SetD((*it).first, (*it).second.elval.GetRealPart()); break; case MuTyV::MTVComplex : SetZ((*it).first, complex((*it).second.elval.GetRealPart(), (*it).second.elval.GetImagPart())); break; case MuTyV::MTVString : SetS((*it).first, *((*it).second.elval.GetStringPointer())); break; default : break; } SetComment((*it).first, (*it).second.elcomm); } comment = comment + "\n" + dvl.comment; return(*this); } //++ // int_8 GetI(string const& key, int_8 def=-1) // r_8 GetD(string const& key, r_8 def=-9.e19) // string GetS(string const& key, const char* def="") // Retourne la valeur de la variable de nom "key" et de type entier, réél, // chaine de caracteres. // Si la variable n'existe pas, la valeur par défaut "def" est renvoyée. // string GetComment(string const& key) // Retourne le commentaire associé à la variable de nom "key". //-- /* --Methode-- */ /*! Returns the value corresponding to name \b key, converted to integer Default value \b def is returned if name \b key not found */ int_8 DVList::GetI(string const& key, int_8 def) const { ValList::const_iterator it = mvlist.find(key); if (it == mvlist.end()) return(def); return( (int_8)((*it).second.elval) ); } /* --Methode-- */ /*! Returns the value corresponding to name \b key, converted to double Default value \b def is returned if name \b key not found */ r_8 DVList::GetD(string const& key, r_8 def) const { ValList::const_iterator it = mvlist.find(key); if (it == mvlist.end()) return(def); return( (r_8)((*it).second.elval) ); } /* --Methode-- */ /*! Returns the value corresponding to name \b key, converted to complex Default value \b def is returned if name \b key not found */ complex DVList::GetZ(string const& key, complex def) const { ValList::const_iterator it = mvlist.find(key); if (it == mvlist.end()) return(def); /* Appel explicite de l'operateur de conversion suite a la suggestion de M. Reinecke, Reza 31/7/2002 #if defined(__GNUG__) complex z; z = (*it).second.elval; return(z); #else return( (complex)(*it).second.elval ); #endif --- Appel explicite de l'operateur de conversion sur l'objet MuTyV */ return( (*it).second.elval.operator complex() ); } /* --Methode-- */ /*! Returns the value corresponding to name \b key, converted to string Default value \b def is returned if name \b key not found */ string DVList::GetS(string const& key, const char* def) const { ValList::const_iterator it = mvlist.find(key); if (it == mvlist.end()) return(def); return( (string)((*it).second.elval) ); } /* --Methode-- */ /*! Returns the comment associated with name \b key */ string DVList::GetComment(string const& key) const { ValList::const_iterator it = mvlist.find(key); if (it == mvlist.end()) return(""); return((*it).second.elcomm); } //++ // void SetI(string const& key, int_8 val) // void SetD(string const& key, r_8 val) // void SetZ(string const& key, complex val) // void SetS(string const& key, const char* val) // void SetS(string const& key, string val) // Crée la variable de nom "key", de type entier, double, complexe, string et // lui attribue la valeur "val". Si une variable du même nom existe, // sa valeur et eventuellement son type sont modifiés. Les noms de // variables ne doivent pas contenir de caractères spéciaux, // en particulier pas de CR/LF. // void SetComment(string const& key, string const& comm) // Modifie le commentaire associé à la variable de nom "key", si // celle-ci existe. Le texte du commentaire ne doit pas contenir // de caractères spéciaux, et en particulier pas de CR/LF. //-- /* --Methode-- */ /*! Removes the definition and value associated with the name \b key. Return \c true if the \b key is found in the list, \c false otherwise. */ bool DVList::DeleteKey(string const& key) { ValList::iterator it = mvlist.find(key); if (it == mvlist.end()) return(false); mvlist.erase(it); return(true); } /* --Methode-- */ /*! Return \c true if the \b key is found in the list, \c false otherwise. */ bool DVList::HasKey(string const& key) const { ValList::const_iterator it = mvlist.find(key); if (it == mvlist.end()) return(false); return(true); } /* --Methode-- */ /*! Appends or sets the integer value \b val in the list with name \b key */ void DVList::SetI(string const& key, int_8 val) { Get(key) = (int_8)val; } /* --Methode-- */ void DVList::SetD(string const& key, r_8 val) /*! Appends or sets the double value \b val in the list with name \b key */ { Get(key) = (r_8)val; } /* --Methode-- */ void DVList::SetZ(string const& key, complex val) /*! Appends or sets the complex value \b val in the list with name \b key */ { Get(key) = val; } /* --Methode-- */ /*! Appends or sets the string value \b val in the list with name \b key */ void DVList::SetS(string const& key, const char * val) { MuTyV div(val); Get(key) = div; } /* --Methode-- */ /*! Appends or sets the string value \b val in the list with name \b key */ void DVList::SetS(string const& key, string const& val) { MuTyV div(val); Get(key) = div; } /* --Methode-- */ /*! Appends or sets the TimeStamp value \b val in the list with name \b key */ void DVList::SetT(string const& key, TimeStamp const& val) { MuTyV div(val); Get(key) = div; } /* --Methode-- */ /*! Assigns the comment \b comm with the name \b key . Does nothing if the entry with name is not present in the list */ void DVList::SetComment(string const& key, string const& comm) { ValList::iterator it = mvlist.find(key); if (it == mvlist.end()) return; (*it).second.elcomm = comm; } //++ // MuTyV& Get(string const& key) // Renvoie une référence sur l'objet "MuTyV" de la liste avec le nom "key". // Si cet objet (variable) n'existe pas, il est créé. // MuTyV& operator() (string const& key) // MuTyV& operator[] (string const& key) // // Renvoie la variable de nom "key". Equivalent à "Get(key)". // string& Comment() // Renvoie une référence sur le champ commentaire de l'objet. //-- /* --Methode-- */ /*! Return the MuTyV value associated with name \b key . Integer 0 is returned if \b key is not present in the list */ MuTyV DVList::Get(string const& key) const { ValList::const_iterator it = mvlist.find(key); if (it == mvlist.end()) return(MuTyV( (int_8) 0)); else return((*it).second.elval); } /* --Methode-- */ /*! Return the MuTyV value associated with name \b key . Adds an entry of type integer in the list if \b key is not present in the list */ MuTyV& DVList::Get(string const& key) { size_t l = key.length(); if (l < 1) return(ddvdum); // dvlElement xxx = {(int_8)0 , ""}; marche pas sur mac/CW (!) - cf DY dvlElement xxx; xxx.elval = (int_8)0; xxx.elcomm = ""; ValList::iterator it = mvlist.find(key); if (it == mvlist.end()) mvlist[key] = xxx; it = mvlist.find(key); if (it == mvlist.end()) return(ddvdum); else return((*it).second.elval); } //++ // Titre Entrée-Sortie //-- //++ // void Print() // Imprime (sur "cout") la liste des variables et leurs valeurs. // void Print(ostream& os) // Imprime sur le flot "os" la liste des variables et leurs valeurs. // ostream& operator << (ostream& s, DVList& dvl) // sortie sur flot "s" (Appel a "Print(s)"). //-- /* --Methode-- */ /*! Prints a brief description of object on on the output stream \b os */ void DVList::Show(ostream& os) const { os << "DVList::Show() - NVar= " << (int)mvlist.size() << "\n"; os << comment << endl; } /* --Methode-- */ /*! Prints the list of variables on the output stream \b os */ void DVList::Print(ostream& os) const { os << "DVList::Print() - NVar= " << (int)mvlist.size() << "\n"; if (comment.length() > 0) os << comment << endl; char buff[1024]; TimeStamp ts; ValList::const_iterator it; for(it = mvlist.begin(); it != mvlist.end(); it++) { switch ((*it).second.elval.Type()) { case MuTyV::MTVInteger : sprintf(buff, "%s = %ld (int) %s\n", (*it).first.substr(0,64).c_str(), (long)((*it).second.elval.GetIntPart()), (*it).second.elcomm.substr(0,128).c_str()); break; case MuTyV::MTVFloat : sprintf(buff, "%s = %.20g (double) %s\n", (*it).first.substr(0,64).c_str(), (*it).second.elval.GetRealPart(), (*it).second.elcomm.substr(0,128).c_str()); break; case MuTyV::MTVComplex : sprintf(buff, "%s = %.20g %.20g i (complex) %s\n", (*it).first.substr(0,64).c_str(), (*it).second.elval.GetRealPart(), (*it).second.elval.GetImagPart(), (*it).second.elcomm.substr(0,128).c_str()); break; case MuTyV::MTVString : sprintf(buff, "%s = %s (string) %s\n", (*it).first.substr(0,64).c_str(), (*it).second.elval.GetStringPointer()->substr(0,800).c_str(), (*it).second.elcomm.substr(0,128).c_str()); break; case MuTyV::MTVTimeStamp : ts.Set((*it).second.elval.GetRealPart()); sprintf(buff, "%s = %s (TimeStamp) %s\n", (*it).first.substr(0,64).c_str(), ts.ToString().c_str(), (*it).second.elcomm.substr(0,128).c_str()); break; default : break; } os << (string)buff; } os << endl; } //++ // Titre Exemples // Utilisation des objets *MuTyV* : //| MuTyV mvu; // Declaration d'une variable //| mvu = 60; // mvu est de type entier (= 60) //| mvu = 66.6; // et double (= 66.6) maintenant ... //| MuTyV mvi(14); // On construit une variable entiere = 14 //| r_4 x = mvi; // x vaut 14.0 //| MuTyV mvd(44.4); // Variable double = 44.4 //| int k = mvd; // k vaut 44 //| MuTyV mvs("Bonjour, Ca va ?"); // Variable chaine de caracteres //| string s = mvs; // s vaut "Bonjour, Ca va ?" // Utilisation des *DVList* : //| DVList dvl; //| dvl("toto") = 14; //| dvl("titi") = 25.5; //| dvl("tata") = "Bonjour, Ca va ?"; // Majuscules et minuscules sont differenciees pour les noms, pas de blanc ... //| dvl("hello") = 88; //| dvl("Hello") = 77.77; //| dvl.Comment() = "Test d'objet DVList, avec variables hello, Hello "; //| dvl.Write("dvlist.ppf"); // Plus loin, ou dans un autre programme, on relit le fichier fabrique plus haut //| DVList dvlr("dvlist.ppf"); //| int k = dvlr["toto"] ; // k = 14 //| r_8 b = dvlr["titi"] ; // b = 25.5 //| string s = dvlr["tata"] ; // s = "Bonjour, Ca va ?" //| r_4 c = dvlr["Hello"] ; // c = 77.77 //| int l = dvlr["Hello"] ; // l = 77 //| int m = dvlr["hello"] ; // m = 88 //-- //---------------------------------------------------------- // Classe pour la gestion de persistance // ObjFileIO //---------------------------------------------------------- /* --Methode-- */ DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */ void ObjFileIO::WriteSelf(POutPersist& s) const { if (dobj == NULL) throw NullPtrError("ObjFileIO::WriteSelf() dobj=NULL"); char buf[1024]; string sfw; int lc = dobj->Comment().length(); // itab - 0 : Version, 1 : NVar, 2 : Comment length, 3 reserved uint_4 itab[4]; itab[0] = 2; // Version number = 2 itab[1] = dobj->Size(); itab[2] = lc; itab[3] = 0; s.Put(itab, 4); if (lc > 0) s.PutStr(dobj->Comment()); sfw = "\n----Variable-List---------------\n"; s.PutStr(sfw); DVList::ValList::const_iterator it; for(it = dobj->Begin(); it != dobj->End(); it++) { switch ((*it).second.elval.Type()) { case MuTyV::MTVInteger : sprintf(buf,"I %s %ld\n", (*it).first.substr(0,64).c_str(), (long)((*it).second.elval.GetIntPart()) ); sfw = buf; s.PutStr(sfw); break; case MuTyV::MTVFloat : sprintf(buf,"F %s %.20g\n", (*it).first.substr(0,64).c_str(), (*it).second.elval.GetRealPart() ); sfw = buf; s.PutStr(sfw); break; case MuTyV::MTVComplex : sprintf(buf,"Z %s %.20g %.20g\n", (*it).first.substr(0,64).c_str(), (*it).second.elval.GetRealPart(), (*it).second.elval.GetImagPart()); sfw = buf; s.PutStr(sfw); break; case MuTyV::MTVString : sprintf(buf,"S %s %s\n", (*it).first.substr(0,64).c_str(), (*it).second.elval.GetStringPointer()->substr(0,960).c_str() ); sfw = buf; s.PutStr(sfw); break; case MuTyV::MTVTimeStamp : sprintf(buf,"T %s %.20g\n", (*it).first.substr(0,64).c_str(), (*it).second.elval.GetRealPart() ); sfw = buf; s.PutStr(sfw); break; default : break; } // Ecriture eventuelle du commentaire associe if ((*it).second.elcomm.length() > 0) { sprintf(buf,"# %s", (*it).second.elcomm.substr(0,256).c_str()); sfw = buf; s.PutStr(sfw); } } sfw = "ZZZZZ--End-of-Variable-List------"; s.PutStr(sfw); } /* --Methode-- */ DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */ void ObjFileIO::ReadSelf(PInPersist& s) { char buf[1024]; string sfr; int_8 j,iv,k; r_8 dv, dvi; bool ok=true; buf[0] = '\0'; if (dobj == NULL) dobj = new DVList; else dobj->Clear(); // itab - 0 : Version, 1 : NVar, 2 : Comment length, 3 reserved uint_4 itab[4]; s.Get(itab, 4); if (itab[2] > 0) { // Il y a un champ commentaire a lire s.GetStr(sfr); dobj->Comment() = sfr; } s.GetStr(sfr); // Pour lire les "------- " string key=""; while(ok) { s.GetStr(sfr); strncpy(buf, sfr.c_str(), 1024); buf[1023] = '\0'; j = strlen(buf)-1; if ( (j >= 0) && (buf[j] == '\n') ) buf[j] = '\0'; if (strncmp(buf,"ZZZZZ",5) == 0) { ok=false; break; } if (buf[0] == '#') { dobj->SetComment(key, buf+2); continue; } j = posc(buf+2, ' ')+2; buf[j] = '\0'; switch (buf[0]) { case 'I' : iv = (int_8)atol(buf+j+1); key = buf+2; dobj->SetI(key, iv); break; case 'F' : dv = atof(buf+j+1); key = buf+2; dobj->SetD(key, dv); break; case 'Z' : k = posc(buf+j+1, ' ')+j+1; buf[k] = '\0'; dv = atof(buf+j+1); dvi = atof(buf+k+1); key = buf+2; dobj->SetZ(key, complex(dv, dvi)); break; case 'S' : key = buf+2; dobj->SetS(key, buf+j+1); break; case 'T' : dv = atof(buf+j+1); key = buf+2; dobj->SetT(key, TimeStamp(dv)); break; default : break; } } if (dobj->Size() != itab[1]) // Probleme !!! throw FileFormatExc("ObjFileIO::ReadSelf() Error in Nb. Variables !"); } #ifdef __CXX_PRAGMA_TEMPLATES__ #pragma define_template ObjFileIO #endif #if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES) template class ObjFileIO; #endif } // FIN namespace SOPHYA