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.GPL  **
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/StringUtils.h> 
00034 #include <ICLUtils/Exception.h>
00035 #include <ICLUtils/Lockable.h>
00036 #include <ICLUtils/SmartPtr.h>
00037 #include <map>
00038 #include <typeinfo>
00039 
00041 namespace pugi{
00042   class xml_document;
00043 }
00047 namespace icl{
00048   namespace utils{
00050     struct XMLDocumentDelOp{ static void delete_func(pugi::xml_document *h); };
00053 
00054 
00170     class ConfigFile : public Lockable{
00171   
00172       public:
00173       friend class ConfigFileGUI;
00174       
00176       struct EntryNotFoundException : public ICLException{
00177         EntryNotFoundException(const std::string &entryName):
00178         ICLException("Entry " + entryName+" could not be found!"){}
00179         virtual ~EntryNotFoundException() throw(){}
00180       };
00181       
00183       struct InvalidTypeException : public ICLException{
00184         InvalidTypeException(const std::string &entryName, const std::string &typeName):
00185         ICLException("Invalid type " + typeName + " (entry " + entryName + ")"){};
00186         virtual ~InvalidTypeException() throw() {}
00187       };
00188   
00190       struct UnregisteredTypeException : public ICLException{
00191         UnregisteredTypeException(const std::string &rttiID):
00192         ICLException("type with RTTI ID " + rttiID + " is not registered"){}
00193         ~UnregisteredTypeException() throw(){}
00194       };
00195   
00196       private:
00197       
00199       struct Maps{
00201         std::map<std::string,std::string> typeMap;
00202         
00204         std::map<std::string,std::string> typeMapReverse;
00205       };
00206       
00208       static Maps *getMapsInstance();
00209       
00211       static Maps &getMapsInstanceRef() { return *getMapsInstance(); }
00212 #if 0
00213       static std::map<std::string,std::string> s_typeMap;
00214       static std::map<std::string,std::string> s_typeMapReverse;
00215 #endif
00216 
00218       template<class T>
00219       static const std::string &get_type_name() throw (UnregisteredTypeException){
00220         static const std::string &rttiID = get_rtti_type_id<T>();
00221         if(!type_registered_by_rtti(rttiID)) throw UnregisteredTypeException(rttiID);
00222         static const std::string &name = getMapsInstanceRef().typeMap[rttiID];
00223         return name;
00224       }
00225   
00227       template<class T>
00228       static inline const std::string &get_rtti_type_id(){
00229         static std::string NAME = typeid(T).name();
00230         return NAME;
00231       }
00232   
00234       template<class T>
00235       inline bool check_type(const std::string &id) const throw (EntryNotFoundException,UnregisteredTypeException){
00236         return check_type_internal(id,get_rtti_type_id<T>());
00237       }
00238   
00240       bool check_type_internal(const std::string &id, const std::string &rttiTypeID) const 
00241       throw (EntryNotFoundException,UnregisteredTypeException);
00242   
00244       static bool type_registered_by_rtti(const std::string &rttiID){
00245         Maps &maps = getMapsInstanceRef();
00246         return (maps.typeMap.find(rttiID) != maps.typeMap.end());
00247       }
00248       
00249       public:
00250   
00253 #define REGISTER_CONFIG_FILE_TYPE(T) ::icl::utils::ConfigFile::register_type<T>(#T)
00254 
00255   
00257 
00283       template<class T>
00284       static void register_type(const std::string &id){
00285         Maps &maps = getMapsInstanceRef();
00286         std::string rtti = get_rtti_type_id<T>();
00287         maps.typeMap[rtti] = id;
00288         maps.typeMapReverse[id] = rtti;
00289 #if 0
00290         s_typeMap[get_rtti_type_id<T>()] = id;
00291         s_typeMapReverse[id] = get_rtti_type_id<T>();
00292 #endif
00293       }
00294       
00296 
00304       ConfigFile();
00305       
00307 
00310       ConfigFile(const std::string &filename) throw(FileNotFoundException,InvalidFileFormatException,UnregisteredTypeException);
00311       
00313 
00314       ConfigFile(pugi::xml_document *handle) throw (UnregisteredTypeException);
00315 
00317 
00319       ConfigFile(std::istream &stream) throw(FileNotFoundException,InvalidFileFormatException,UnregisteredTypeException);
00320       
00322 
00323       void load(const std::string &filename) throw(FileNotFoundException,InvalidFileFormatException,UnregisteredTypeException);
00324   
00326       void save(const std::string &filename) const;
00327       
00329       void setPrefix(const std::string &defaultPrefix) const;
00330       
00332       const std::string &getPrefix() const;
00333   
00335 
00336       class Data{
00337         std::string id; 
00338         ConfigFile *cf; 
00339         
00341         Data(const std::string &id, ConfigFile &cf);
00342         public:
00343         
00345         friend class ConfigFile;
00346         
00348 
00350         template<class T> 
00351         operator T() const throw (InvalidTypeException,EntryNotFoundException){
00352           return cf->get<T>(id);
00353         }
00354         
00356 
00357         template<class T>
00358         T as() const throw (InvalidTypeException,EntryNotFoundException){
00359           return cf->get<T>(id);
00360         }
00361   
00363 
00364         Data &operator=(const Data &d){
00365           cf = d.cf;
00366           id = d.id;
00367           return *this;
00368         }
00369         
00371 
00376         template<class T>
00377         Data &operator=(const T &t) throw (UnregisteredTypeException,InvalidTypeException,EntryNotFoundException){
00378           cf->set(id,t);
00379           return *this;
00380         }
00381       };
00382   
00383      
00385       /* This function can be used for reading as well as for writing ConfigFile entries
00386          the returned utitlity structure of type Data defers creation of a new
00387          ConfigFile entry until actually a value is assigned to it.
00388       **/
00389       Data operator [](const std::string &id);
00390       
00392 
00393       const Data operator[](const std::string &id) const throw (EntryNotFoundException);
00394         
00396 
00397       std::vector<Data> find(const std::string &regex);
00398       
00400 
00402       const std::vector<Data> find(const std::string &regex) const{
00403         return const_cast<ConfigFile*>(this)->find(regex);
00404       }
00405       
00407 
00433       template<class T>
00434       void set(const std::string &id, const T &val) throw (UnregisteredTypeException){
00435         set_internal(id,str(val),get_rtti_type_id<T>());
00436       }
00437       
00439 
00449       template<class T>
00450       inline T get(const std::string &idIn) const throw (EntryNotFoundException,InvalidTypeException,UnregisteredTypeException){
00451         if(!contains(idIn)) throw EntryNotFoundException(m_sDefaultPrefix+idIn);
00452         if(!check_type<T>(idIn)) throw InvalidTypeException(m_sDefaultPrefix+idIn,get_type_name<T>());
00453         return parse<T>(m_entries.find(m_sDefaultPrefix+idIn)->second.value);
00454       }
00455       
00457 
00459       template<class T>
00460       inline T get(const std::string &idIn,const T &def) const throw (InvalidTypeException,UnregisteredTypeException){
00461         if(!contains(idIn)) return def;
00462         if(!check_type<T>(idIn)) throw InvalidTypeException(m_sDefaultPrefix+idIn,get_type_name<T>());
00463         return parse<T>(m_entries.find(m_sDefaultPrefix+idIn)->second.value);
00464       }
00465   
00467       static void loadConfig(const std::string &filename);
00468   
00470       static void loadConfig(const ConfigFile &configFile);
00471       
00473       static const ConfigFile &getConfig(){ return s_oConfig; }
00474   
00476       template<class T>
00477       static inline T sget(const std::string &id) throw (EntryNotFoundException,InvalidTypeException){
00478         return getConfig().get<T>(id);
00479       }
00480       
00482       template<class T>
00483       static inline T sget(const std::string &id,const T &def) throw (InvalidTypeException){
00484         return getConfig().get<T>(id,def);
00485       }
00486       
00488       void listContents() const;
00489   
00491       bool contains(const std::string &id) const;
00492   
00494 
00495       struct KeyRestriction{
00496         inline KeyRestriction():
00497           hasRange(false),hasValues(false){}
00498         inline KeyRestriction(double min, double max):
00499           min(min),max(max),hasRange(true),hasValues(false){}
00500         inline KeyRestriction(const std::string &values):
00501           values(values),hasRange(false),hasValues(true){}
00502         std::string toString() const;
00503   
00504         double min,max;
00505         std::string values;
00506   
00507         bool hasRange;
00508         bool hasValues;
00509       };
00510       
00512 
00514       void setRestriction(const std::string &id, const KeyRestriction &r) throw (EntryNotFoundException);
00515   
00517 
00518       const KeyRestriction *getRestriction(const std::string &id) const throw (EntryNotFoundException);
00519   
00521       struct Entry{
00522         std::string id;           
00523         std::string value;        
00524         std::string rttiType;     
00525         SmartPtr<KeyRestriction> restr;  
00526   
00528         const std::string &getTypeName() const { return getMapsInstanceRef().typeMap[rttiType]; }
00529   
00531         std::string getRelID() const {
00532           const std::string &pfx = parent->getPrefix();
00533           if(!pfx.length()) return id;
00534           else return id.substr(pfx.length());
00535         }
00536         ConfigFile *parent; // parent ConfigFile (used to obtain current prefix)
00537       };
00538   
00540       typedef std::map<std::string,Entry>::const_iterator const_iterator;
00541       
00543       const_iterator begin() const{ return m_entries.begin(); }
00544       
00546       const_iterator end() const{ return m_entries.end(); }
00547       
00549       const std::vector<const Entry*> getEntryList(bool relToPrefix=false) const{
00550         std::vector<const Entry*> v;
00551         for(const_iterator it =begin();it != end(); ++it){
00552           v.push_back(&it->second);
00553         }
00554         return v;
00555       }
00556       
00558       void clear();
00559       
00561 
00564       const pugi::xml_document *getHandle() const { return m_doc.get(); }
00565       
00566       private:
00567       
00569       void load_internal();
00570       
00572       Entry &get_entry_internal(const std::string &id) throw (EntryNotFoundException);
00573   
00575       const Entry &get_entry_internal(const std::string &id) const throw (EntryNotFoundException);
00576   
00578       void set_internal(const std::string &id, const std::string &val, const std::string &type) throw (UnregisteredTypeException);
00579   
00581       static void add_to_doc(pugi::xml_document &h,const std::string &id,const std::string &type, 
00582                              const std::string &value,const KeyRestriction *restr=0);
00583        
00585       mutable SmartPtrBase<pugi::xml_document,XMLDocumentDelOp> m_doc;
00586       
00588       static ConfigFile s_oConfig;
00589       
00590   
00592       mutable std::string m_sDefaultPrefix;
00593   
00594   
00596       std::map<std::string,Entry> m_entries;
00597   
00599       friend std::ostream &operator<<(std::ostream&,const ConfigFile&);
00600     };
00601     
00602     
00604     std::ostream &operator<<(std::ostream &s, const ConfigFile &cf);
00605   
00607     template<> inline ConfigFile::Data &ConfigFile::Data::operator=(char * const &t) 
00608     throw (UnregisteredTypeException,InvalidTypeException,EntryNotFoundException){
00609       return ConfigFile::Data::operator=(std::string(t));
00610     }
00611     template<> inline ConfigFile::Data &ConfigFile::Data::operator=(const char * const &t) 
00612     throw (UnregisteredTypeException,InvalidTypeException,EntryNotFoundException){
00613       return ConfigFile::Data::operator=(std::string(t));
00614     }
00617   } // namespace utils
00618 }
00619 
00620 
00621 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines