ISIS Core Library 0.7.2 (api 3.0.0)

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

Go to the documentation of this file.
00001 //
00002 // C++ Implementation: propmap
00003 //
00004 // Description:
00005 //
00006 //
00007 // Author:  <Enrico Reimer>, (C) 2009
00008 //
00009 // Copyright: See COPYING file that comes with this distribution
00010 //
00011 //
00012 
00013 #include "propmap.hpp"
00014 #include <boost/foreach.hpp>
00015 
00016 namespace isis
00017 {
00018 namespace util
00019 {
00020 API_EXCLUDE_BEGIN
00022 namespace _internal
00023 {
00036 template<typename ForwardIterator, typename T, typename CMP> bool
00037 continousFind( ForwardIterator &current, const ForwardIterator end, const T &compare, CMP compOp )
00038 {
00039     //find the first iterator which is does not compare less
00040     current = std::lower_bound( current, end, compare, compOp );
00041 
00042     if ( current == end //if we're at the end
00043          || compOp( compare, *current ) //or compare is less than that iterator
00044        )
00045         return false;//we didn't find a match
00046     else
00047         return true;//not(current <> compare) makes compare == current
00048 }
00049 }
00051 API_EXCLUDE_END
00052 
00054 // Contructors
00056 
00057 PropertyMap::PropertyMap( const PropertyMap::Container &src ): Container( src ) {}
00058 
00059 bool PropertyMap::operator==( const PropertyMap &src )const
00060 {
00061     const Container &other = src, &me = *this;
00062     return me == other;
00063 }
00064 
00065 PropertyMap::PropertyMap() {}
00066 
00067 
00069 // The core tree traversal functions
00071 PropertyMap::mapped_type &PropertyMap::fetchEntry( const PropPath &path )
00072 {
00073     return fetchEntry( *this, path.begin(), path.end() );
00074 }
00079 PropertyMap::mapped_type &PropertyMap::fetchEntry(
00080     PropertyMap &root,
00081     const PropertyMap::propPathIterator at, const PropertyMap::propPathIterator pathEnd )
00082 {
00083     PropPath::const_iterator next = at;
00084     next++;
00085     Container &rootRef = root;
00086     iterator found = static_cast<Container &>( root ).find( *at );
00087 
00088     if ( next != pathEnd ) {//we are not at the end of the path (a proposed leaf in the PropMap)
00089         if ( found != root.end() ) {//and we found the entry
00090             mapped_type &ref = found->second;
00091             LOG_IF( ref.is_leaf(), Runtime, error )
00092                     << MSubject( found->first ) << " is a leaf, but was requested as a branch in "
00093                     << MSubject( listToString( at, pathEnd, "/" ) );
00094             return fetchEntry( ref.getBranch(), next, pathEnd ); //continue there
00095         } else { // if we should create a sub-map
00096             //insert a empty branch (aka PropMap) at "*at" (and fetch the reference of that)
00097             LOG( Debug, verbose_info ) << "Creating an empty branch " << *at << " trough fetching";
00098             return fetchEntry( rootRef[*at].getBranch(), next, pathEnd ); // and continue there
00099         }
00100     } else { //if its the leaf
00101         return rootRef[*at]; // (create and) return that entry
00102     }
00103 }
00104 
00109 const PropertyMap::mapped_type *PropertyMap::findEntry(
00110     const PropertyMap &root,
00111     const propPathIterator at, const propPathIterator pathEnd )
00112 {
00113     propPathIterator next = at;
00114     next++;
00115     PropertyMap::const_iterator found = static_cast<const Container &>( root ).find( *at );
00116 
00117     if ( next != pathEnd ) {//we are not at the end of the path (aka the leaf)
00118         if ( found != root.end() ) {//and we found the entry
00119             const mapped_type &ref = found->second;
00120             return findEntry( ref.getBranch(), next, pathEnd ); //continue there
00121         }
00122     } else if ( found != root.end() ) {// if its the leaf and we found the entry
00123         return &found->second; // return that entry
00124     }
00125 
00126     return NULL;
00127 }
00128 bool PropertyMap::recursiveRemove( PropertyMap &root, const propPathIterator path_it, const propPathIterator pathEnd )
00129 {
00130     bool ret = false;
00131 
00132     if ( path_it != pathEnd ) {
00133         propPathIterator next = path_it;
00134         next++;
00135         iterator found = static_cast<Container &>( root ).find( *path_it );
00136 
00137         if ( found != root.end() ) {
00138             mapped_type &ref = found->second;
00139 
00140             if ( ! ref.is_leaf() ) {
00141                 ret = recursiveRemove( ref.getBranch(), next, pathEnd );
00142 
00143                 if ( ref.getBranch().isEmpty() )
00144                     root.erase( found ); // remove the now empty branch
00145             } else {
00146                 root.erase( found );
00147                 ret = true;
00148             }
00149         } else {
00150             LOG( Runtime, warning ) << "Entry " << MSubject( *path_it ) << " not found, skipping it";
00151         }
00152     }
00153 
00154     return ret;
00155 }
00156 
00157 
00159 // Generic interface for accessing elements
00161 
00162 const std::vector< PropertyValue >& PropertyMap::propertyValueVec( const PropertyMap::PropPath &path ) const
00163 {
00164     const mapped_type *ref = findEntry( *this, path.begin(), path.end() );
00165 
00166     if( ref && ref->is_leaf() ) {
00167         return ref->getLeaf();
00168     } else {
00169         LOG( Debug, warning ) << "Property " << path << " not found. Returning empty property.";
00170         static const _internal::treeNode emptyEntry;
00171         return emptyEntry.getLeaf();
00172     }
00173 }
00174 
00175 std::vector< PropertyValue >& PropertyMap::propertyValueVec( const PropertyMap::PropPath &path )
00176 {
00177     mapped_type &n = fetchEntry( *this, path.begin(), path.end() );
00178     LOG_IF( ! n.is_leaf(), Debug, error ) << "Using branch " << path << " as PropertyValue";
00179     return n.getLeaf();
00180 }
00181 
00182 
00183 const PropertyValue &PropertyMap::propertyValue( const PropertyMap::PropPath &path )const
00184 {
00185     return propertyValueVec( path )[0];
00186 }
00187 
00188 PropertyValue &PropertyMap::propertyValue( const PropertyMap::PropPath &path )
00189 {
00190     std::vector< PropertyValue > &p = propertyValueVec( path );
00191     p.resize( 1 ); // the user is expecting only one entry, so remove the others
00192     return p[0];
00193 }
00194 
00195 const PropertyMap &PropertyMap::branch( const PropertyMap::PropPath &path ) const
00196 {
00197     const mapped_type *ref = findEntry( *this, path.begin(), path.end() );
00198 
00199     if( ! ref ) {
00200         LOG( Runtime, warning ) << "Trying to access non existing branch " << path << ".";
00201         static const _internal::treeNode emptyEntry;
00202         return emptyEntry.getBranch();
00203     } else {
00204         LOG_IF( ref->getBranch().isEmpty(), Runtime, warning ) << "Accessing empty branch " << path;
00205         return ref->getBranch();
00206     }
00207 }
00208 PropertyMap &PropertyMap::branch( const PropPath &path )
00209 {
00210     mapped_type &n = fetchEntry( *this, path.begin(), path.end() );
00211     return n.getBranch();
00212 }
00213 
00214 bool PropertyMap::remove( const PropPath &path )
00215 {
00216     return recursiveRemove( *this, path.begin(), path.end() );
00217 }
00218 
00219 bool PropertyMap::remove( const KeyList &removeList, bool keep_needed )
00220 {
00221     bool ret = true;
00222     BOOST_FOREACH( const KeyType & key, removeList ) {
00223         if( hasProperty( key ) ) { // remove everything which is there
00224             if( !( propertyValue( key ).isNeeded() && keep_needed ) ) { // if its not needed or keep_need is not true
00225                 ret &= remove( key );
00226             }
00227         }
00228     }
00229     return ret;
00230 }
00231 
00232 
00233 bool PropertyMap::remove( const PropertyMap &removeMap, bool keep_needed )
00234 {
00235     iterator thisIt = begin();
00236     bool ret = true;
00237 
00238     //remove everything that is also in second
00239     for ( const_iterator otherIt = removeMap.begin(); otherIt != removeMap.end(); otherIt++ ) {
00240         //find the closest match for otherIt->first in this (use the value-comparison-functor of PropMap)
00241         if ( continousFind( thisIt, end(), *otherIt, value_comp() ) ) { //thisIt->first == otherIt->first - so its the same property or propmap
00242             if ( ! thisIt->second.is_leaf() ) { //this is a branch
00243                 if ( ! otherIt->second.is_leaf() ) { // recurse if its a branch in the removal map as well
00244                     PropertyMap &mySub = thisIt->second.getBranch();
00245                     const PropertyMap &otherSub = otherIt->second.getBranch();
00246                     ret &= mySub.remove( otherSub );
00247 
00248                     if( mySub.isEmpty() ) // delete my branch, if its empty
00249                         erase( thisIt++ );
00250                 } else {
00251                     LOG( Debug, warning ) << "Not deleting branch " << MSubject( thisIt->first ) << " because its no subtree in the removal map";
00252                     ret = false;
00253                 }
00254             } else if( !( thisIt->second.getLeaf()[0].isNeeded() && keep_needed ) ) { // this is a leaf
00255                 erase( thisIt++ ); // so delete this (they are equal - kind of)
00256             }
00257         }
00258     }
00259 
00260     return ret;
00261 }
00262 
00263 
00265 // utilities
00267 bool PropertyMap::isValid() const
00268 {
00269     //iterate through the whole map and return false as soon as we find something needed _and_ empty
00270     const const_iterator found = std::find_if( begin(), end(), treeInvalidP() );
00271     return found == end();
00272 }
00273 
00274 bool PropertyMap::isEmpty() const
00275 {
00276     return Container::empty();
00277 }
00278 
00279 PropertyMap::DiffMap PropertyMap::getDifference( const PropertyMap &other ) const
00280 {
00281     PropertyMap::DiffMap ret;
00282     diffTree( other, ret, "" );
00283     return ret;
00284 }
00285 
00286 void PropertyMap::diffTree( const PropertyMap &other, PropertyMap::DiffMap &ret, istring prefix ) const
00287 {
00288     const_iterator otherIt = other.begin();
00289 
00290     //insert everything that is in this, but not in second or is on both but differs
00291     for ( const_iterator thisIt = begin(); thisIt != end(); thisIt++ ) {
00292         const PropPath::value_type pathname = prefix + thisIt->first;
00293 
00294         //find the closest match for thisIt->first in other (use the value-comparison-functor of PropMap)
00295         if ( _internal::continousFind( otherIt, other.end(), *thisIt, value_comp() ) ) { //otherIt->first == thisIt->first - so its the same property
00296             const mapped_type &first = thisIt->second, &second = otherIt->second;
00297 
00298             if ( ! ( first.is_leaf() || second.is_leaf() ) ) { // if both are a branch
00299                 const PropertyMap &thisMap = first.getBranch();
00300                 const PropertyMap &refMap = second.getBranch();
00301                 thisMap.diffTree( refMap, ret, pathname + "/" );
00302             } else if ( ! ( first == second )  ) { // if they are not equal
00303                 const PropertyValue firstVal = first.is_leaf() ? first.getLeaf()[0] : PropertyValue( Value<std::string>( first.toString() ) );
00304                 const PropertyValue secondVal = second.is_leaf() ? second.getLeaf()[0] : PropertyValue( Value<std::string>( second.toString() ) );
00305                 ret.insert( // add (propertyname|(value1|value2))
00306                     ret.end(),      // we know it has to be at the end
00307                     std::make_pair(
00308                         pathname,   //the key
00309                         std::make_pair( firstVal, secondVal ) //pair of both values
00310                     )
00311                 );
00312             }
00313         } else { // if ref is not in the other map
00314             const PropertyValue firstVal = thisIt->second.is_leaf() ? thisIt->second.getLeaf()[0] : PropertyValue( Value<std::string>( thisIt->second.toString() ) );
00315             ret.insert( // add (propertyname|(value1|[empty]))
00316                 ret.end(),      // we know it has to be at the end
00317                 std::make_pair(
00318                     pathname,
00319                     std::make_pair( firstVal, PropertyValue() )
00320                 )
00321             );
00322         }
00323     }
00324 
00325     //insert everything that is in second but not in this
00326     const_iterator thisIt = begin();
00327 
00328     for ( otherIt = other.begin(); otherIt != other.end(); otherIt++ ) {
00329         const PropPath::value_type pathname = prefix + otherIt->first;
00330 
00331         if ( ! _internal::continousFind( thisIt, end(), *otherIt, value_comp() ) ) { //there is nothing in this which has the same key as ref
00332             const PropertyValue secondVal = otherIt->second.is_leaf() ? otherIt->second.getLeaf()[0] : PropertyValue( Value<std::string>( otherIt->second.toString() ) );
00333             ret.insert(
00334                 std::make_pair( // add (propertyname|([empty]|value2))
00335                     pathname,
00336                     std::make_pair( PropertyValue(), secondVal )
00337                 )
00338             );
00339         }
00340     }
00341 }
00342 
00343 void PropertyMap::removeEqual ( const PropertyMap &other, bool removeNeeded )
00344 {
00345     iterator thisIt = begin();
00346 
00347     //remove everything that is also in second and equal (or also empty)
00348     for ( const_iterator otherIt = other.begin(); otherIt != other.end(); otherIt++ ) {
00349         //find the closest match for otherIt->first in this (use the value-comparison-functor of PropMap)
00350         if ( continousFind( thisIt, end(), *otherIt, value_comp() ) ) { //thisIt->first == otherIt->first  - so its the same property
00351             if ( ! removeNeeded && thisIt->second.getLeaf()[0].isNeeded() ) {//Skip needed
00352                 thisIt++;
00353                 continue;
00354             }
00355 
00356             if ( thisIt->second.empty() ) { //this is empty
00357                 if ( otherIt->second.empty() ) { //the other is empty
00358                     erase( thisIt++ ); // so delete this (they are equal - kind of)
00359                 } else {
00360                     LOG( Debug, verbose_info ) << "Keeping the empty " << thisIt->first << " because its is not empty in the other (" << *otherIt << ")";
00361                     thisIt++;
00362                 }
00363             } else if ( ! otherIt->second.empty() ) { // if the other is not empty as well
00364                 if ( thisIt->second == otherIt->second ) { //delete this, if they are equal
00365                     LOG( Debug, verbose_info ) << "Removing " << *thisIt << " because its equal with the other (" << *otherIt << ")";
00366                     erase( thisIt++ ); // so delete this (they are equal - kind of)
00367                 } else if ( ! ( thisIt->second.is_leaf() || otherIt->second.is_leaf() ) ) { //but maybe they are branches
00368                     PropertyMap &thisMap = thisIt->second.getBranch();
00369                     const PropertyMap &otherMap = otherIt->second.getBranch();
00370                     thisMap.removeEqual( otherMap );
00371                     thisIt++;
00372                 }
00373             } else {//only the other is empty
00374                 LOG( Debug, verbose_info ) << "Keeping " << *thisIt << " because the other is empty";
00375                 thisIt++;
00376             }
00377         }
00378     }
00379 }
00380 
00381 
00382 PropertyMap::KeyList PropertyMap::join( const PropertyMap &other, bool overwrite )
00383 {
00384     KeyList rejects;
00385     joinTree( other, overwrite, "", rejects );
00386     return rejects;
00387 }
00388 
00389 void PropertyMap::joinTree( const PropertyMap &other, bool overwrite, istring prefix, KeyList &rejects )
00390 {
00391     iterator thisIt = begin();
00392 
00393     for ( const_iterator otherIt = other.begin(); otherIt != other.end(); otherIt++ ) { //iterate through the elements of other
00394         if ( continousFind( thisIt, end(), *otherIt, value_comp() ) ) { // if the element is allready here
00395             if ( thisIt->second.empty() ) { // if ours is empty
00396                 LOG( Debug, verbose_info ) << "Replacing empty property " << MSubject( thisIt->first ) << " by " << MSubject( otherIt->second );
00397                 thisIt->second.insert( otherIt->second );
00398             } else if ( ! ( thisIt->second.is_leaf() || otherIt->second.is_leaf() ) ) { // if both are a subtree
00399                 PropertyMap &thisMap = thisIt->second.getBranch();
00400                 const PropertyMap &refMap = otherIt->second.getBranch();
00401                 thisMap.joinTree( refMap, overwrite, prefix + thisIt->first + "/", rejects ); //recursion
00402             } else if ( overwrite ) { // otherwise replace ours by the other (if we shall overwrite)
00403                 LOG( Debug, info ) << "Replacing property " << MSubject( *thisIt ) << " by " << MSubject( otherIt->second );
00404                 thisIt->second = otherIt->second;
00405             } else if ( ! ( thisIt->second == otherIt->second ) ) { // otherwise put the other into rejected if its not equal to our
00406                 LOG( Debug, info )
00407                         << "Rejecting property " << MSubject( *otherIt )
00408                         << " because " << MSubject( thisIt->second ) << " is allready there";
00409                 rejects.insert( rejects.end(), prefix + otherIt->first );
00410             }
00411         } else { // ok we dont have that - just insert it
00412             std::pair<const_iterator, bool> inserted = insert( *otherIt );
00413             LOG_IF( inserted.second, Debug, verbose_info ) << "Inserted property " << MSubject( *inserted.first ) << ".";
00414         }
00415     }
00416 }
00417 
00418 
00419 void PropertyMap::makeFlatMap( FlatMap &out, KeyType key_prefix ) const
00420 {
00421     for ( const_iterator i = begin(); i != end(); i++ ) {
00422         KeyType key = ( key_prefix.empty() ? "" : key_prefix + pathSeperator ) + i->first;
00423 
00424         if ( i->second.is_leaf()  ) {
00425             out.insert( std::make_pair( key, i->second.getLeaf()[0] ) );
00426         } else {
00427             i->second.getBranch().makeFlatMap( out, key );
00428         }
00429     }
00430 }
00431 
00432 PropertyMap::FlatMap PropertyMap::getFlatMap() const
00433 {
00434     FlatMap buff;
00435     makeFlatMap( buff );
00436     return buff;
00437 }
00438 
00439 
00440 bool PropertyMap::transform( const PropPath &from,  const PropPath &to, int dstID, bool delSource )
00441 {
00442     const PropertyValue &found = propertyValue( from );
00443     bool ret = false;
00444 
00445     if( ! found.isEmpty() ) {
00446         ValueReference &dst = static_cast<ValueReference &>( propertyValue( to ) );
00447 
00448         if ( found.getTypeID() == dstID ) {
00449             if( from != to ) {
00450                 dst = found ;
00451                 ret = true;
00452             } else {
00453                 LOG( Debug, info ) << "Not transforming " << MSubject( found ) << " into same type at same place.";
00454             }
00455         } else {
00456             LOG_IF( from == to, Debug, warning ) << "Transforming " << MSubject( found ) << " in place.";
00457             dst = ( *found ).copyByID( dstID );
00458             ret = !dst.isEmpty();
00459         }
00460     }
00461 
00462     if ( ret && delSource )remove( from );
00463 
00464     return ret;
00465 }
00466 
00467 
00468 const PropertyMap::KeyList PropertyMap::getKeys()const
00469 {
00470     KeyList ret;
00471     std::for_each( begin(), end(), walkTree<trueP>( ret ) );
00472     return ret;
00473 }
00474 
00475 PropertyMap::KeyList PropertyMap::findLists()const
00476 {
00477     KeyList ret;
00478     std::for_each( begin(), end(), walkTree<listP>( ret ) );
00479     return ret;
00480 }
00481 
00482 
00483 const PropertyMap::KeyList PropertyMap::getMissing() const
00484 {
00485     PropertyMap::KeyList ret;
00486     std::for_each( begin(), end(), walkTree<invalidP>( ret ) );
00487     return ret;
00488 }
00489 
00490 
00491 void PropertyMap::addNeeded( const PropPath &path )
00492 {
00493     propertyValue( path ).needed() = true;
00494 }
00495 
00496 
00497 bool PropertyMap::hasProperty( const PropPath &path ) const
00498 {
00499     const mapped_type *ref = findEntry( *this, path.begin(), path.end() );
00500     return ( ref && ref->is_leaf() && ! ref->getLeaf()[0].isEmpty() );
00501 }
00502 
00503 PropertyMap::KeyType PropertyMap::find( PropertyMap::KeyType key, bool allowProperty, bool allowBranch ) const
00504 {
00505     // make sure we only get the last part of the path if its one
00506     const PropPath path = stringToList<KeyType>( key, pathSeperator );
00507 
00508     if( path.empty() ) {
00509         LOG( Debug, error ) << "Search key " << MSubject( key ) << " is invalid, won't search";
00510         return KeyType();
00511     } else if( path.size() > 1 ) {
00512         LOG( Debug, warning ) << "Stripping search key " << MSubject( key ) << " to " << path.back();
00513     }
00514 
00515     key = path.back();
00516 
00517     // if the searched key is on this brach return its name
00518     const Container &map = static_cast<const Container &>( *this );
00519     Container::const_iterator found = map.find( key );
00520 
00521     if( found != map.end() &&
00522         ( ( found->second.is_leaf() && allowProperty ) || ( !found->second.is_leaf() && allowBranch ) )
00523       ) {
00524         return found->first;
00525     } else { // otherwise search in the branches (getBranch() returns an empty PropMap for leaves - we wont have to check for that)
00526         BOOST_FOREACH( Container::const_reference ref, map ) {
00527             const KeyType foundKey = ref.second.getBranch().find( key, allowProperty, allowBranch );
00528 
00529             if( !foundKey.empty() ) // if the key is found abort search and return it with its branch-name
00530                 return ref.first + "/" + foundKey;
00531         }
00532     }
00533 
00534     return KeyType(); // nothing found
00535 }
00536 
00537 bool PropertyMap::hasBranch( const PropPath &path ) const
00538 {
00539     const mapped_type *ref = findEntry( *this, path.begin(), path.end() );
00540     return ( ref && ! ref->is_leaf()  );
00541 }
00542 
00543 bool PropertyMap::rename( const PropPath &oldname,  const PropPath &newname )
00544 {
00545     const mapped_type *old_e = findEntry( oldname );
00546     const mapped_type *new_e = findEntry( newname );
00547 
00548     if ( old_e ) {
00549         LOG_IF( new_e && ! new_e->empty(), Runtime, warning )
00550                 << "Overwriting " << std::make_pair( newname, *new_e ) << " with " << *old_e;
00551         fetchEntry( newname ) = *old_e;
00552         return remove( oldname );
00553     } else {
00554         LOG( Runtime, warning )
00555                 << "Cannot rename " << oldname << " it does not exist";
00556         return false;
00557     }
00558 }
00559 
00560 void PropertyMap::toCommonUnique( PropertyMap &common, std::set<KeyType> &uniques, bool init )const
00561 {
00562     if ( init ) {
00563         common = *this;
00564         uniques.clear();
00565         return;
00566     } else {
00567         const DiffMap difference = common.getDifference( *this );
00568         BOOST_FOREACH( const DiffMap::value_type & ref, difference ) {
00569             uniques.insert( ref.first );
00570 
00571             if ( ! ref.second.first.isEmpty() )common.remove( ref.first );//if there is something in common, remove it
00572         }
00573     }
00574 }
00575 
00576 std::ostream &PropertyMap::print( std::ostream &out, bool label )const
00577 {
00578     FlatMap buff;
00579     makeFlatMap( buff );
00580     size_t key_len = 0;
00581 
00582     for ( FlatMap::const_iterator i = buff.begin(); i != buff.end(); i++ )
00583         if ( key_len < i->first.length() )
00584             key_len = i->first.length();
00585 
00586     for ( FlatMap::const_iterator i = buff.begin(); i != buff.end(); i++ )
00587         out << i->first << std::string( key_len - i->first.length(), ' ' ) + ":" << i->second.toString( label ) << std::endl;
00588 
00589     return out;
00590 }
00591 
00592 const PropertyMap::mapped_type *PropertyMap::findEntry( const PropPath &path )const
00593 {
00594     return findEntry( *this, path.begin(), path.end() );
00595 }
00596 
00597 
00598 bool PropertyMap::listP::operator()( const std::pair< const istring, _internal::treeNode >& ref ) const
00599 {
00600     return ref.second.is_leaf() && ref.second.getLeaf().size() > 1;
00601 }
00602 
00603 bool PropertyMap::trueP::operator()( const PropertyMap::value_type &/*ref*/ ) const
00604 {
00605     return true;
00606 }
00607 bool PropertyMap::invalidP::operator()( const PropertyMap::value_type &ref ) const
00608 {
00609     return ref.second.getLeaf()[0].isNeeded() && ref.second.getLeaf()[0].isEmpty();
00610 }
00611 bool PropertyMap::treeInvalidP::operator()( const PropertyMap::value_type &ref ) const
00612 {
00613     if ( ref.second.is_leaf() ) {
00614         const PropertyValue &val = ref.second.getLeaf()[0];
00615         return val.isNeeded() && val.isEmpty();
00616     } else  {
00617         return ! ref.second.getBranch().isValid();
00618     }
00619 }
00620 
00621 }
00622 }