ISIS Core Library 0.7.2 (api 3.0.0)

/scr/tee1/isis/lib/Core/CoreUtils/propmap.hpp

Go to the documentation of this file.
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