Image Component Library (ICL)
|
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 ®ex); 00398 00400 00402 const std::vector<Data> find(const std::string ®ex) 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