ref: refs/heads/master
commit 1184bb3499ef3e6942ad6026f9d9135726e97521
Author: Michael Andres
Date: Thu Jun 25 16:17:26 2009 +0200
Enhance PoolQueryIterator to allow detailed inspection attribute matches.
---
zypp/PoolQuery.cc | 99 ++++++++++++++++++++++++++++++++++++++++++++----
zypp/PoolQuery.h | 77 ++++++++++++++++++++++++++++++++++++-
zypp/sat/LookupAttr.cc | 6 +++
zypp/sat/LookupAttr.h | 8 +++-
4 files changed, 178 insertions(+), 12 deletions(-)
diff --git a/zypp/PoolQuery.cc b/zypp/PoolQuery.cc
index 375a349..79f5ee6 100644
--- a/zypp/PoolQuery.cc
+++ b/zypp/PoolQuery.cc
@@ -1217,21 +1217,71 @@ attremptycheckend:
if ( base_r == end() )
base_r = startNewQyery(); // first candidate
else
+ {
+ base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
++base_r; // advance to next candidate
+ }
while ( base_r != end() )
{
if ( isAMatch( base_r ) )
- {
- base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
return true;
- }
// No match: try next
- ++base_r;
+ ++base_r;
}
return false;
}
+ /** Provide all matching attributes within this solvable.
+ *
+ */
+ void matchDetail( const base_iterator & base_r, std::vector & return_r ) const
+ {
+ if ( base_r == end() )
+ return;
+
+ sat::Solvable inSolvable( base_r.inSolvable() );
+
+ if ( _attrMatchList.size() == 1 )
+ {
+ // base_r is already on the 1st matching attribute!
+ // String matching is done by the base iterator. We must check the predicate here.
+ // Let's see if there are more matches for this solvable:
+ base_iterator base( base_r );
+ base.stayInThisSolvable(); // avoid discarding matches we found far away from here.
+ return_r.push_back( base );
+
+ const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
+ for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
+ {
+ if ( ! predicate || predicate( base ) )
+ return_r.push_back( base );
+ }
+ }
+ else
+ {
+ // Here: search all attributes ;(
+ for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
+ {
+ const AttrMatchData & matchData( *mi );
+ sat::LookupAttr q( matchData.attr, inSolvable );
+ if ( matchData.attrMatcher ) // an empty searchstring matches always
+ q.setAttrMatcher( matchData.attrMatcher );
+
+ if ( ! q.empty() ) // there are matches.
+ {
+ // now check any predicate:
+ const AttrMatchData::Predicate & predicate( matchData.predicate );
+ for_( it, q.begin(), q.end() )
+ {
+ if ( ! predicate || predicate( it ) )
+ return_r.push_back( it );
+ }
+ }
+ }
+ }
+ }
+
public:
/** Ctor stores the \ref PoolQuery settings.
* \throw MatchException Any of the exceptions thrown by \ref PoolQuery::Impl::compile.
@@ -1344,8 +1394,7 @@ attremptycheckend:
if ( ! predicate || predicate( base_r ) )
return true;
- base_r.nextSkipSolvable();
- return false;
+ return false; // no skip as there may be more occurrences od this attr.
}
// Here: search all attributes ;(
@@ -1396,8 +1445,42 @@ attremptycheckend:
// matcher restarts if at end! It is called from the ctor
// to get the 1st match. But if the end is reached, it should
// be deleted, otherwise we'd start over again.
- if ( _matcher && ! _matcher->advance( base_reference() ) )
- _matcher.reset();
+ if ( !_matcher )
+ return; // at end
+ if ( _matches )
+ _matches.reset(); // invalidate old matches
+ if ( ! _matcher->advance( base_reference() ) )
+ _matcher.reset();
+ }
+
+ const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
+ {
+ if ( _matches )
+ return *_matches;
+
+ if ( !_matcher )
+ {
+ // at end of query:
+ static const Matches _none;
+ return _none;
+ }
+
+ _matches.reset( new Matches );
+ _matcher->matchDetail( base_reference(), *_matches );
+ return *_matches;
+ }
+
+ std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
+ {
+ str << *obj;
+ if ( ! obj.matchesEmpty() )
+ {
+ for_( it, obj.matchesBegin(), obj.matchesEnd() )
+ {
+ str << endl << " " << it->inSolvAttr() << "\t" << it->asString();
+ }
+ }
+ return str;
}
///////////////////////////////////////////////////////////////////
diff --git a/zypp/PoolQuery.h b/zypp/PoolQuery.h
index 032650c..4238155 100644
--- a/zypp/PoolQuery.h
+++ b/zypp/PoolQuery.h
@@ -77,6 +77,7 @@ namespace zypp
* on kinds, multiple repos, and multiple attributes are filtered inside
* the PoolQuery, so these tend to be slower.
*
+ * \see detail::PoolQueryIterator on how to inspect matches in detail.
* \see tests/zypp/PoolQuery_test.cc for more examples
* \see sat::SolvIterMixin
*/
@@ -463,7 +464,6 @@ namespace zypp
/** \relates PoolQuery Stream output. */
std::ostream & operator<<( std::ostream & str, const PoolQuery & obj );
-
///////////////////////////////////////////////////////////////////
namespace detail
{ /////////////////////////////////////////////////////////////////
@@ -475,7 +475,12 @@ namespace zypp
// CLASS NAME : PoolQuery::PoolQueryIterator
//
/** \ref PoolQuery iterator as returned by \ref PoolQuery::begin.
- */
+ *
+ * The \ref PoolQueryIterator visits sat::Solavables that do contain matches.
+ *
+ * But it also provides an iterator by itself, to allow a detailed inspection of
+ * the individual attribute matches within the current Solvable.
+ */
class PoolQueryIterator : public boost::iterator_adaptor<
PoolQueryIterator // Derived
, sat::LookupAttr::iterator // Base
@@ -484,6 +489,10 @@ namespace zypp
, const sat::Solvable // Reference
{
+ typedef std::vectorsat::LookupAttr::iterator Matches;
+ public:
+ typedef Matches::size_type size_type;
+ typedef Matches::const_iterator matches_iterator;
public:
/** Default ctor is also \c end.*/
PoolQueryIterator()
@@ -494,6 +503,61 @@ namespace zypp
: _matcher( matcher_r )
{ increment(); }
+ /** \name Detailed inspection of attribute matches within the current Solvable.
+ *
+ * The \ref matches_iterator visits all attribute matches within the current Solvable,
+ * providing a \ref sat::LookupAttr::iterator pointing to attribute. While a
+ * \ref matches_iterator itself becomes invalid if the PoolQueryIterator is advanced,
+ * the \ref sat::LookupAttr::iterator it pointed to stays valid, even after the query
+ * ended.
+ *
+ * \code
+ * // Setup query for "libzypp" in name or requires:
+ * PoolQuery q;
+ * q.addString( "libzypp" );
+ * q.setMatchSubstring();
+ * q.setCaseSensitive( false );
+ * q.addAttribute( sat::SolvAttr::name );
+ * q.addDependency( sat::SolvAttr::requires );
+ *
+ * // Iterate the result:
+ * for_( solvIter, q.begin(), q.end() )
+ * {
+ * sat::Solvable solvable( *solvIter );
+ * cout << "Found matches in " << solvable << endl;
+ * if ( verbose )
+ * for_( attrIter, solvIter.matchesBegin(), solvIter.matchesEnd() )
+ * {
+ * sat::LookupAttr::iterator attr( *attrIter );
+ * cout << " " << attr.inSolvAttr() << "\t\"" << attr.asString() << "\"" << endl;
+ * }
+ * }
+ *
+ *
+ * Found matches in PackageKit-0.3.11-1.12.i586(@System)
+ * solvable:requires "libzypp.so.523"
+ * Found matches in libqdialogsolver1-1.2.6-1.1.2.i586(@System)
+ * solvable:requires "libzypp.so.523"
+ * solvable:requires "libzypp >= 5.25.3-0.1.2"
+ * Found matches in libzypp-5.30.3-0.1.1.i586(@System)
+ * solvable:name "libzypp"
+ * Found matches in libzypp-testsuite-tools-4.2.6-8.1.i586(@System)
+ * solvable:name "libzypp-testsuite-tools"
+ * solvable:requires "libzypp.so.523"
+ * ...
+ * \endcode
+ */
+ //@{
+ /** \c False unless this is the \c end iterator. */
+ bool matchesEmpty() const { return ! _matcher; }
+ /** Number of attribute matches. */
+ size_type matchesSize() const { return matches().size(); }
+ /** Begin of matches. */
+ matches_iterator matchesBegin() const { return matches().begin(); }
+ /** End of matches. */
+ matches_iterator matchesEnd() const { return matches().end(); }
+ //@}
+
private:
friend class boost::iterator_core_access;
@@ -502,8 +566,12 @@ namespace zypp
void increment();
- private:
+ private:
+ const Matches & matches() const;
+
+ private:
shared_ptr<PoolQueryMatcher> _matcher;
+ mutable shared_ptr<Matches> _matches;
};
///////////////////////////////////////////////////////////////////
@@ -511,6 +579,9 @@ namespace zypp
inline std::ostream & operator<<( std::ostream & str, const PoolQueryIterator & obj )
{ return str << obj.base(); }
+ /** \relates PoolQueryIterator Detailed stream output. */
+ std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj );
+
///////////////////////////////////////////////////////////////////
} //namespace detail
///////////////////////////////////////////////////////////////////
diff --git a/zypp/sat/LookupAttr.cc b/zypp/sat/LookupAttr.cc
index cd8cada..f184502 100644
--- a/zypp/sat/LookupAttr.cc
+++ b/zypp/sat/LookupAttr.cc
@@ -350,6 +350,12 @@ namespace zypp
void LookupAttr::iterator::nextSkipRepo()
{ if ( _dip ) ::dataiterator_skip_repo( _dip.get() ); }
+ void LookupAttr::iterator::stayInThisSolvable()
+ { if ( _dip ) { _dip.get()->repoid = -1; _dip.get()->flags |= SEARCH_THISSOLVID; } }
+
+ void LookupAttr::iterator::stayInThisRepo()
+ { if ( _dip ) { _dip.get()->repoid = -1; } }
+
///////////////////////////////////////////////////////////////////
// attr value type test
///////////////////////////////////////////////////////////////////
diff --git a/zypp/sat/LookupAttr.h b/zypp/sat/LookupAttr.h
index 34a3ecd..3152b11 100644
--- a/zypp/sat/LookupAttr.h
+++ b/zypp/sat/LookupAttr.h
@@ -214,7 +214,7 @@ namespace zypp
//
// CLASS NAME : LookupRepoAttr
//
- /** Lightweight repositor attribute value lookup.
+ /** Lightweight repository attribute value lookup.
*
* This is just a convenience class that overloads all
* \ref LookupAttr methods which take a \ref LookupAttr::Location
@@ -357,6 +357,12 @@ namespace zypp
/** Immediately advance to the next \ref Repository. */
void skipRepo()
{ nextSkipRepo(); increment(); }
+
+ /** Stop after all matches in the current \ref Solvable are processed. */
+ void stayInThisSolvable();
+
+ /** Stop after all matches in the current \ref Repository are processed. */
+ void stayInThisRepo();
//@}
/** \name Current position info. */
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org