Image Component Library (ICL)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
ConfigFile.h
Go to the documentation of this file.
00001 /********************************************************************
00002 **                Image Component Library (ICL)                    **
00003 **                                                                 **
00004 ** Copyright (C) 2006-2013 CITEC, University of Bielefeld          **
00005 **                         Neuroinformatics Group                  **
00006 ** Website: www.iclcv.org and                                      **
00007 **          http://opensource.cit-ec.de/projects/icl               **
00008 **                                                                 **
00009 ** File   : ICLUtils/src/ICLUtils/ConfigFile.h                     **
00010 ** Module : ICLUtils                                               **
00011 ** Authors: Christof Elbrechter                                    **
00012 **                                                                 **
00013 **                                                                 **
00014 ** GNU LESSER GENERAL PUBLIC LICENSE                               **
00015 ** This file may be used under the terms of the GNU Lesser General **
00016 ** Public License version 3.0 as published by the                  **
00017 **                                                                 **
00018 ** Free Software Foundation and appearing in the file LICENSE.LGPL **
00019 ** included in the packaging of this file.  Please review the      **
00020 ** following information to ensure the license requirements will   **
00021 ** be met: http://www.gnu.org/licenses/lgpl-3.0.txt                **
00022 **                                                                 **
00023 ** The development of this software was supported by the           **
00024 ** Excellence Cluster EXC 277 Cognitive Interaction Technology.    **
00025 ** The Excellence Cluster EXC 277 is a grant of the Deutsche       **
00026 ** Forschungsgemeinschaft (DFG) in the context of the German       **
00027 ** Excellence Initiative.                                          **
00028 **                                                                 **
00029 ********************************************************************/
00030 
00031 #pragma once
00032 
00033 #include <ICLUtils/CompatMacros.h>
00034 #include <ICLUtils/StringUtils.h> 
00035 #include <ICLUtils/Exception.h>
00036 #include <ICLUtils/Lockable.h>
00037 #include <ICLUtils/SmartPtr.h>
00038 #include <map>
00039 #include <typeinfo>
00040 
00042 namespace pugi{
00043   class xml_document;
00044 }
00048 namespace icl{
00049   namespace utils{
00051     struct ICLUtils_API XMLDocumentDelOp{ static void delete_func(pugi::xml_document *h); };
00054 
00055 
00171     class ICLUtils_API ConfigFile : public Lockable{
00172   
00173       public:
00174       friend class ConfigFileGUI;
00175       
00177       struct EntryNotFoundException : public ICLException{
00178         EntryNotFoundException(const std::string &entryName):
00179         ICLException("Entry " + entryName+" could not be found!"){}
00180         virtual ~EntryNotFoundException() throw(){}
00181       };
00182       
00184       struct InvalidTypeException : public ICLException{
00185         InvalidTypeException(const std::string &entryName, const std::string &typeName):
00186         ICLException("Invalid type " + typeName + " (entry " + entryName + ")"){};
00187         virtual ~InvalidTypeException() throw() {}
00188       };
00189   
00191       struct UnregisteredTypeException : public ICLException{
00192         UnregisteredTypeException(const std::string &rttiID):
00193         ICLException("type with RTTI ID " + rttiID + " is not registered"){}
00194         ~UnregisteredTypeException() throw(){}
00195       };
00196   
00197       private:
00198       
00200       struct Maps{
00202         std::map<std::string,std::string> typeMap;
00203         
00205         std::map<std::string,std::string> typeMapReverse;
00206       };
00207       
00209       static Maps *getMapsInstance();
00210       
00212       static Maps &getMapsInstanceRef() { return *getMapsInstance(); }
00213 #if 0
00214       static std::map<std::string,std::string> s_typeMap;
00215       static std::map<std::string,std::string> s_typeMapReverse;
00216 #endif
00217 
00219       template<class T>
00220       static const std::string &get_type_name() throw (UnregisteredTypeException){
00221         static const std::string &rttiID = get_rtti_type_id<T>();
00222         if(!type_registered_by_rtti(rttiID)) throw UnregisteredTypeException(rttiID);
00223         static const std::string &name = getMapsInstanceRef().typeMap[rttiID];
00224         return name;
00225       }
00226   
00228       template<class T>
00229       static inline const std::string &get_rtti_type_id(){
00230         static std::string NAME = typeid(T).name();
00231         return NAME;
00232       }
00233   
00235       template<class T>
00236       inline bool check_type(const std::string &id) const throw (EntryNotFoundException,UnregisteredTypeException){
00237         return check_type_internal(id,get_rtti_type_id<T>());
00238       }
00239   
00241       bool check_type_internal(const std::string &id, const std::string &rttiTypeID) const 
00242       throw (EntryNotFoundException,UnregisteredTypeException);
00243   
00245       static bool type_registered_by_rtti(const std::string &rttiID){
00246         Maps &maps = getMapsInstanceRef();
00247         return (maps.typeMap.find(rttiID) != maps.typeMap.end());
00248       }
00249       
00250       public:
00251   
00254 #define REGISTER_CONFIG_FILE_TYPE(T) ::icl::utils::ConfigFile::register_type<T>(#T)
00255 
00256   
00258 
00284       template<class T>
00285       static void register_type(const std::string &id){
00286         Maps &maps = getMapsInstanceRef();
00287         std::string rtti = get_rtti_type_id<T>();
00288         maps.typeMap[rtti] = id;
00289         maps.typeMapReverse[id] = rtti;
00290 #if 0
00291         s_typeMap[get_rtti_type_id<T>()] = id;
00292         s_typeMapReverse[id] = get_rtti_type_id<T>();
00293 #endif
00294       }
00295       
00297 
00305       ConfigFile();
00306       
00308 
00311       ConfigFile(const std::string &filename) throw(FileNotFoundException,InvalidFileFormatException,UnregisteredTypeException);
00312       
00314 
00315       ConfigFile(pugi::xml_document *handle) throw (UnregisteredTypeException);
00316 
00318 
00320       ConfigFile(std::istream &stream) throw(FileNotFoundException,InvalidFileFormatException,UnregisteredTypeException);
00321       
00323 
00324       void load(const std::string &filename) throw(FileNotFoundException,InvalidFileFormatException,UnregisteredTypeException);
00325   
00327       void save(const std::string &filename) const;
00328       
00330       void setPrefix(const std::string &defaultPrefix) const;
00331       
00333       const std::string &getPrefix() const;
00334   
00336 
00337       class Data{
00338         std::string id; 
00339         ConfigFile *cf; 
00340         
00342         Data(const std::string &id, ConfigFile &cf);
00343         public:
00344         
00346         friend class ConfigFile;
00347         
00349 
00351         template<class T> 
00352         operator T() const throw (InvalidTypeException,EntryNotFoundException){
00353           return cf->get<T>(id);
00354         }
00355         
00357 
00358         template<class T>
00359         T as() const throw (InvalidTypeException,EntryNotFoundException){
00360           return cf->get<T>(id);
00361         }
00362   
00364 
00365         Data &operator=(const Data &d){
00366           cf = d.cf;
00367           id = d.id;
00368           return *this;
00369         }
00370         
00372 
00377         template<class T>
00378         Data &operator=(const T &t) throw (UnregisteredTypeException,InvalidTypeException,EntryNotFoundException){
00379           cf->set(id,t);
00380           return *this;
00381         }
00382       };
00383   
00384      
00386       /* This function can be used for reading as well as for writing ConfigFile entries
00387          the returned utitlity structure of type Data defers creation of a new
00388          ConfigFile entry until actually a value is assigned to it.
00389       **/
00390       Data operator [](const std::string &id);
00391       
00393 
00394       const Data operator[](const std::string &id) const throw (EntryNotFoundException);
00395         
00397 
00398       std::vector<Data> find(const std::string &regex);
00399       
00401 
00403       const std::vector<Data> find(const std::string &regex) const{
00404         return const_cast<ConfigFile*>(this)->find(regex);
00405       }
00406       
00408 
00434       template<class T>
00435       void set(const std::string &id, const T &val) throw (UnregisteredTypeException){
00436         set_internal(id,str(val),get_rtti_type_id<T>());
00437       }
00438       
00440 
00450       template<class T>
00451       inline T get(const std::string &idIn) const throw (EntryNotFoundException,InvalidTypeException,UnregisteredTypeException){
00452         if(!contains(idIn)) throw EntryNotFoundException(m_sDefaultPrefix+idIn);
00453         if(!check_type<T>(idIn)) throw InvalidTypeException(m_sDefaultPrefix+idIn,get_type_name<T>());
00454         return parse<T>(m_entries.find(m_sDefaultPrefix+idIn)->second.value);
00455       }
00456       
00458 
00460       template<class T>
00461       inline T get(const std::string &idIn,const T &def) const throw (InvalidTypeException,UnregisteredTypeException){
00462         if(!contains(idIn)) return def;
00463         if(!check_type<T>(idIn)) throw InvalidTypeException(m_sDefaultPrefix+idIn,get_type_name<T>());
00464         return parse<T>(m_entries.find(m_sDefaultPrefix+idIn)->second.value);
00465       }
00466   
00468       static void loadConfig(const std::string &filename);
00469   
00471       static void loadConfig(const ConfigFile &configFile);
00472       
00474       static const ConfigFile &getConfig(){ return s_oConfig; }
00475   
00477       template<class T>
00478       static inline T sget(const std::string &id) throw (EntryNotFoundException,InvalidTypeException){
00479         return getConfig().get<T>(id);
00480       }
00481       
00483       template<class T>
00484       static inline T sget(const std::string &id,const T &def) throw (InvalidTypeException){
00485         return getConfig().get<T>(id,def);
00486       }
00487       
00489       void listContents() const;
00490   
00492       bool contains(const std::string &id) const;
00493   
00495 
00496       struct KeyRestriction{
00497         inline KeyRestriction():
00498           hasRange(false),hasValues(false){}
00499         inline KeyRestriction(double min, double max):
00500           hasRange(true),hasValues(false){
00501             this->min = min;
00502             this->max = max;
00503         }
00504         inline KeyRestriction(const std::string &values):
00505           values(values),hasRange(false),hasValues(true){}
00506         ICLUtils_API std::string toString() const;
00507   
00508         double min,max;
00509         std::string values;
00510   
00511         bool hasRange;
00512         bool hasValues;
00513       };
00514       
00516 
00518       void setRestriction(const std::string &id, const KeyRestriction &r) throw (EntryNotFoundException);
00519   
00521 
00522       const KeyRestriction *getRestriction(const std::string &id) const throw (EntryNotFoundException);
00523   
00525       struct Entry{
00526         std::string id;           
00527         std::string value;        
00528         std::string rttiType;     
00529         SmartPtr<KeyRestriction> restr;  
00530   
00532         const std::string &getTypeName() const { return getMapsInstanceRef().typeMap[rttiType]; }
00533   
00535         std::string getRelID() const {
00536           const std::string &pfx = parent->getPrefix();
00537           if(!pfx.length()) return id;
00538           else return id.substr(pfx.length());
00539         }
00540         ConfigFile *parent; // parent ConfigFile (used to obtain current prefix)
00541       };
00542   
00544       typedef std::map<std::string,Entry>::const_iterator const_iterator;
00545       
00547       const_iterator begin() const{ return m_entries.begin(); }
00548       
00550       const_iterator end() const{ return m_entries.end(); }
00551       
00553       const std::vector<const Entry*> getEntryList(bool relToPrefix=false) const{
00554         std::vector<const Entry*> v;
00555         for(const_iterator it =begin();it != end(); ++it){
00556           v.push_back(&it->second);
00557         }
00558         return v;
00559       }
00560       
00562       void clear();
00563       
00565 
00568       const pugi::xml_document *getHandle() const { return m_doc.get(); }
00569       
00570       private:
00571       
00573       void load_internal();
00574       
00576       Entry &get_entry_internal(const std::string &id) throw (EntryNotFoundException);
00577   
00579       const Entry &get_entry_internal(const std::string &id) const throw (EntryNotFoundException);
00580   
00582       void set_internal(const std::string &id, const std::string &val, const std::string &type) throw (UnregisteredTypeException);
00583   
00585       static void add_to_doc(pugi::xml_document &h,const std::string &id,const std::string &type, 
00586                              const std::string &value,const KeyRestriction *restr=0);
00587        
00589       mutable SmartPtrBase<pugi::xml_document,XMLDocumentDelOp> m_doc;
00590       
00592       static ConfigFile s_oConfig;
00593       
00594   
00596       mutable std::string m_sDefaultPrefix;
00597   
00598   
00600       std::map<std::string,Entry> m_entries;
00601   
00603       friend ICLUtils_API std::ostream &operator<<(std::ostream&, const ConfigFile&);
00604     };
00605     
00606     
00608     ICLUtils_API std::ostream &operator<<(std::ostream &s, const ConfigFile &cf);
00609   
00611     template<> inline ConfigFile::Data &ConfigFile::Data::operator=(char * const &t)
00612     throw (UnregisteredTypeException,InvalidTypeException,EntryNotFoundException){
00613       return ConfigFile::Data::operator=(std::string(t));
00614     }
00615     template<> inline ConfigFile::Data &ConfigFile::Data::operator=(const char * const &t)
00616     throw (UnregisteredTypeException,InvalidTypeException,EntryNotFoundException){
00617       return ConfigFile::Data::operator=(std::string(t));
00618     }
00621   } // namespace utils
00622 }
00623 
00624 
00625 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines