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.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 ®ex); 00399 00401 00403 const std::vector<Data> find(const std::string ®ex) 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