ISIS Core Library 0.7.2 (api 3.0.0)
|
00001 // 00002 // C++ Interface: propmap 00003 // 00004 // Description: 00005 // 00006 // 00007 // Author: Enrico Reimer<reimer@cbs.mpg.de>, (C) 2009 00008 // 00009 // Copyright: See COPYING file that comes with this distribution 00010 // 00011 // 00012 00013 #ifndef ISISPROPMAP_HPP 00014 #define ISISPROPMAP_HPP 00015 00016 #include <map> 00017 #include <string> 00018 00019 #include "common.hpp" 00020 #include "property.hpp" 00021 #include "log.hpp" 00022 #include "istring.hpp" 00023 #include <set> 00024 #include <algorithm> 00025 00026 namespace isis 00027 { 00028 namespace util 00029 { 00031 namespace _internal 00032 { 00033 class treeNode; //predeclare treeNode -- we'll need it in PropertyMap 00034 } 00036 00052 class PropertyMap : protected std::map<util::istring, _internal::treeNode> 00053 { 00054 public: 00056 typedef key_type KeyType; 00058 typedef std::set<KeyType, key_compare> KeyList; 00060 typedef std::map<KeyType, std::pair<PropertyValue, PropertyValue>, key_compare> DiffMap; 00062 typedef std::map<KeyType, PropertyValue> FlatMap; 00063 00065 struct PropPath: public std::list<KeyType> { 00066 PropPath() {} 00067 PropPath( const char *key ): std::list<KeyType>( util::stringToList<KeyType>( util::istring( key ), pathSeperator ) ) {} 00068 PropPath( const KeyType &key ): std::list<KeyType>( util::stringToList<KeyType>( key, pathSeperator ) ) {} 00069 PropPath( const std::list<KeyType> &path ): std::list<KeyType>( path ) {} 00070 }; 00071 private: 00072 typedef std::map<KeyType, mapped_type, key_compare> Container; 00073 typedef PropPath::const_iterator propPathIterator; 00074 00075 static const char pathSeperator = '/'; 00076 00078 // internal predicats 00081 struct trueP { bool operator()( const_reference ref )const;}; 00083 struct invalidP { bool operator()( const_reference ref )const;}; 00085 struct treeInvalidP { bool operator()( const_reference ref )const;}; 00087 struct listP { bool operator()( const_reference ref )const;}; 00088 00090 // internal functors 00092 template<class Predicate> struct walkTree; 00093 00095 // internal tool-backends 00098 void joinTree( const PropertyMap &other, bool overwrite, KeyType prefix, KeyList &rejects ); 00100 void diffTree( const PropertyMap &other, PropertyMap::DiffMap &ret, KeyType prefix ) const; 00101 00102 static mapped_type &fetchEntry( PropertyMap &root, const propPathIterator at, const propPathIterator pathEnd ); 00103 mapped_type &fetchEntry( const PropPath &path ); 00104 00105 static const mapped_type *findEntry( const util::PropertyMap &root, const propPathIterator at, const propPathIterator pathEnd ); 00106 const mapped_type *findEntry( const PropPath &path )const; 00107 00109 bool recursiveRemove( PropertyMap &root, const propPathIterator at, const propPathIterator pathEnd ); 00110 00111 protected: 00112 template<typename T> class NeededsList: public std::list<PropPath> 00113 { 00114 public: 00115 NeededsList() { 00116 const std::list< PropertyMap::KeyType > buff = util::stringToList<PropertyMap::KeyType>( T::neededProperties ); //@todo really bad voodoo 00117 assign( buff.begin(), buff.end() ); 00118 } 00119 void applyTo( PropertyMap &props ) { 00120 BOOST_FOREACH( const PropPath & ref, *this ) { 00121 props.addNeeded( ref ); 00122 } 00123 } 00124 }; 00126 // rw-backends 00128 00130 template<class Predicate> const KeyList genKeyList()const { 00131 KeyList k; 00132 std::for_each( begin(), end(), walkTree<Predicate>( k ) ); 00133 return k; 00134 } 00139 void addNeeded( const PropPath &path ); 00140 00146 void removeEqual( const PropertyMap &other, bool removeNeeded = false ); 00147 00160 void toCommonUnique( PropertyMap &common, std::set<KeyType> &uniques, bool init )const; 00161 00163 void makeFlatMap( FlatMap &out, KeyType key_prefix = "" )const; 00164 00171 const std::vector<PropertyValue> &propertyValueVec( const PropPath &path )const; 00172 00178 std::vector<PropertyValue> &propertyValueVec( const PropPath &path ); 00179 public: 00181 // constructors 00183 PropertyMap( const Container &src ); 00184 PropertyMap(); 00185 00186 bool operator==( const PropertyMap &src )const; 00187 00189 // Common rw-accessors 00191 00197 const PropertyValue &propertyValue( const PropPath &path )const; 00198 00204 PropertyValue &propertyValue( const PropPath &path ); 00205 00211 PropertyMap &branch( const PropPath &path ); 00212 00219 const PropertyMap &branch( const PropPath &path )const; 00220 00229 bool remove( const PropPath &path ); 00230 00237 bool remove( const PropertyMap &removeMap, bool keep_needed = false ); 00238 00245 bool remove( const KeyList &removeList, bool keep_needed = false ); 00246 00252 bool hasProperty( const PropPath &path )const; 00253 00261 KeyType find( KeyType key, bool allowProperty = true, bool allowBranch = false )const; 00262 00264 KeyList findLists()const; 00265 00271 bool hasBranch( const PropPath &path )const; 00272 00274 // tools 00276 00280 bool isValid()const; 00281 00283 bool isEmpty()const; 00284 00289 const KeyList getKeys()const; 00290 00295 const KeyList getMissing()const; 00296 00312 DiffMap getDifference( const PropertyMap &second )const; 00313 00320 PropertyMap::KeyList join( const PropertyMap &other, bool overwrite = false ); 00321 00331 bool transform( const PropPath &from, const PropPath &to, int dstID, bool delSource = true ); 00332 00342 template<typename DST> bool transform( const PropPath &from, const PropPath &to, bool delSource = true ) { 00343 checkType<DST>(); 00344 return transform( from, to, Value<DST>::staticID, delSource ); 00345 } 00346 00348 // Additional get/set - Functions 00350 //@todo make sure the type specific behaviour is as documented 00364 template<typename T> PropertyValue &setPropertyAs( const PropPath &path, const T &val ) { 00365 PropertyValue &ret = propertyValue( path ); 00366 00367 if( ret.isEmpty() ) { 00368 const bool needed = ret.isNeeded(); 00369 ( ret = val ).needed() = needed; 00370 } else if( ret.is<T>() ) { 00371 ret.castTo<T>() = val; 00372 } else { // don't overwrite already set properties with a different type 00373 LOG( Runtime, error ) << "Property " << MSubject( path ) << " is already set to " << MSubject( ret.toString( true ) ) << " won't override with " << MSubject( Value<T>( val ).toString( true ) ); 00374 } 00375 00376 return ret; 00377 } 00378 00389 template<typename T> T getPropertyAs( const PropPath &path )const; 00390 00400 bool rename( const PropPath &from, const PropPath &to ); 00401 00403 FlatMap getFlatMap( )const; 00404 00412 std::ostream &print( std::ostream &out, bool label = false )const; 00413 }; 00414 } 00415 } 00416 00417 namespace std //predeclare streaming output -- we'll need it in treeNode 00418 { 00420 template<typename charT, typename traits> 00421 basic_ostream<charT, traits>& operator<<( basic_ostream<charT, traits> &out, const isis::util::_internal::treeNode &s ); 00423 template<typename charT, typename traits> 00424 basic_ostream<charT, traits>& operator<<( basic_ostream<charT, traits> &out, const isis::util::PropertyMap &s ); 00425 } 00426 00427 00428 // OK, lets define treeNode 00429 namespace isis 00430 { 00431 namespace util 00432 { 00433 API_EXCLUDE_BEGIN 00435 namespace _internal 00436 { 00441 class treeNode 00442 { 00443 PropertyMap m_branch; 00444 std::vector<PropertyValue> m_leaf; 00445 public: 00446 treeNode(): m_leaf( 1 ) {} 00447 bool empty()const { 00448 return m_branch.isEmpty() && m_leaf[0].isEmpty(); 00449 } 00450 bool is_leaf()const { 00451 LOG_IF( ! ( m_branch.isEmpty() || m_leaf[0].isEmpty() ), Debug, error ) << "There is a non empty leaf at a branch. This should not be."; 00452 return m_branch.isEmpty(); 00453 } 00454 const PropertyMap &getBranch()const { 00455 return m_branch; 00456 } 00457 PropertyMap &getBranch() { 00458 return m_branch; 00459 } 00460 std::vector<PropertyValue> &getLeaf() { 00461 assert( is_leaf() ); 00462 return m_leaf; 00463 } 00464 const std::vector<PropertyValue> &getLeaf()const { 00465 assert( is_leaf() ); 00466 return m_leaf; 00467 } 00468 bool operator==( const treeNode &ref )const { 00469 return m_branch == ref.m_branch && m_leaf == ref.m_leaf; 00470 } 00471 void insert( const treeNode &ref ) { 00472 m_branch = ref.m_branch; 00473 m_leaf.resize( ref.m_leaf.size() ); 00474 std::vector<PropertyValue>::iterator dst = m_leaf.begin(); 00475 BOOST_FOREACH( std::vector<PropertyValue>::const_reference src, ref.m_leaf ) { 00476 const bool needed = dst->isNeeded(); 00477 ( *dst = src ).needed() = needed;; 00478 } 00479 } 00480 std::string toString()const { 00481 std::ostringstream o; 00482 o << *this; 00483 return o.str(); 00484 } 00485 }; 00486 } 00488 API_EXCLUDE_END 00489 00491 // and now we can define walkTree (needs treeNode to be defined) 00493 00495 template<class Predicate> struct PropertyMap::walkTree { 00496 KeyList &m_out; 00497 const KeyType m_prefix; 00498 walkTree( KeyList &out, const KeyType &prefix ): m_out( out ), m_prefix( prefix ) {} 00499 walkTree( KeyList &out ): m_out( out ) {} 00500 void operator()( const_reference ref ) const { 00501 const KeyType name = ( m_prefix != "" ? m_prefix + "/" : "" ) + ref.first; 00502 00503 if ( ref.second.is_leaf() ) { 00504 if ( Predicate()( ref ) ) 00505 m_out.insert( m_out.end(), name ); 00506 } else { 00507 const PropertyMap &sub = ref.second.getBranch(); 00508 std::for_each( sub.begin(), sub.end(), walkTree<Predicate>( m_out, name ) ); 00509 } 00510 } 00511 }; 00512 00513 // as well as PropertyMap::getProperty ... 00514 template<typename T> T PropertyMap::getPropertyAs( const PropPath &path ) const 00515 { 00516 const mapped_type *entry = findEntry( path ); 00517 00518 if( entry ) { 00519 const PropertyValue &ref = entry->getLeaf()[0]; 00520 00521 if( !ref.isEmpty() ) 00522 return ref.as<T>(); 00523 } 00524 00525 LOG( Debug, warning ) << "Returning " << Value<T>().toString( true ) << " because property " << path << " does not exist"; 00526 return T(); 00527 } 00528 00529 } 00530 } 00531 00532 // and finally define the streaming output for treeNode 00533 namespace std 00534 { 00536 template<typename charT, typename traits> 00537 basic_ostream<charT, traits>& operator<<( basic_ostream<charT, traits> &out, const isis::util::PropertyMap::PropPath &s ) 00538 { 00539 isis::util::listToOStream( s.begin(), s.end(), out, "/", "", "" ); 00540 return out; 00541 } 00543 template<typename charT, typename traits> 00544 basic_ostream<charT, traits>& operator<<( basic_ostream<charT, traits> &out, const isis::util::_internal::treeNode &s ) 00545 { 00546 if( s.is_leaf() ) { 00547 vector< isis::util::PropertyValue > vec = s.getLeaf(); 00548 isis::util::listToOStream( vec.begin(), vec.end(), out ); 00549 } else 00550 out << "[[Subtree with " << s.getBranch().getKeys().size() << " elements]]"; 00551 00552 return out; 00553 } 00555 template<typename charT, typename traits> 00556 basic_ostream<charT, traits>& operator<<( basic_ostream<charT, traits> &out, const isis::util::PropertyMap &s ) 00557 { 00558 isis::util::PropertyMap::FlatMap buff = s.getFlatMap(); 00559 isis::util::listToOStream( buff.begin(), buff.end(), out ); 00560 return out; 00561 } 00562 } 00563 00564 #endif