#ifndef ZYPP_SAT_LOOKUPATTR_H
#define ZYPP_SAT_LOOKUPATTR_H
-extern "C"
-{
-struct _Dataiterator;
-}
#include <iosfwd>
#include "zypp/base/PtrTypes.h"
#include "zypp/base/DefaultIntegral.h"
-#include "zypp/sat/Pool.h"
+#include "zypp/sat/detail/PoolMember.h"
+#include "zypp/sat/SolvAttr.h"
///////////////////////////////////////////////////////////////////
namespace zypp
{ /////////////////////////////////////////////////////////////////
+
+ class CheckSum;
+ class Match;
+ class MatchException;
+ class StrMatcher;
+
///////////////////////////////////////////////////////////////////
namespace sat
{ /////////////////////////////////////////////////////////////////
* or one \ref Solvable. \ref LookupAttr builds the query,
* \ref LookupAttr::iterator iterates over the result.
*
+ * Per default \ref LookupAttr looks for attributes associated with
+ * a \ref Solvable. But you may also pass \ref REPO_ATTR as
+ * \ref Location argument, to lookup attributes associated with
+ * the \ref Repository (e.g. DeltaRpm information).
+ *
+ * For convenience \see \ref LookupRepoAttr.
+ *
* Modifying the query will not affect any running
* iterator.
*
* Use \ref SolvAttr::allAttr to search all attributes.
*
+ * To search for attributes located in a sub-structure (flexarray)
+ * you also have to pass the sub-structures attribute as parent.
+ * Passing \ref SolvAttr::allAttr a parent will lookup the attribute
+ * in \c any sub-structure. Few attributes are known to have a parent
+ * (\see \ref SolvAttr::parent). Setting those attributes will automatically
+ * initialize their parent value.
+ *
+ * \code
+ * // Lookup all 'name' attributes:
+ * sat::LookupAttr q( sat::SolvAttr::name );
+ * // Lookup all 'name' attributes within a sub-structure 'data':
+ * sat::LookupAttr q( sat::SolvAttr::name, sat::SolvAttr::data );
+ * // Lookup all 'name' attributes within any sub-structure:
+ * sat::LookupAttr q( sat::SolvAttr::name, sat::SolvAttr::allAttr );
+ * \endcode
+ *
* \code
* // look for all attributes of one solvable
* void ditest( sat::Solvable slv_r )
* MIL << " " << it << endl;
* }
* \endcode
+ *
+ * \code
+ * // look for a repo attribute in the pool.
+ * sat::LookupRepoAttr q( sat::SolvAttr::repositoryAddedFileProvides );
+ * MIL << q << ": " << endl;
+ * for_( it, q.begin(), q.end() )
+ * {
+ * MIL << " " << it << endl;
+ * }
+ * \endcode
*/
class LookupAttr
{
public:
+ typedef MatchException Exception;
+
+ public:
typedef unsigned size_type;
+ /** Specify the where to look for the attribule. */
+ enum Location {
+ SOLV_ATTR = 0, //!< Search for solvable attributes (default)
+ REPO_ATTR = -1 //!< Search for repository attributes
+ };
+
public:
/** Default ctor finds nothing. */
- LookupAttr()
- {}
+ LookupAttr();
+
/** Lookup \ref SolvAttr in \ref Pool (all repositories). */
- explicit
- LookupAttr( SolvAttr attr_r )
- : _attr( attr_r )
- {}
+ explicit LookupAttr( SolvAttr attr_r, Location = SOLV_ATTR );
+ /** \overload SolvAttr within sub-structure \a parent_r. */
+ LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Location = SOLV_ATTR );
+
/** Lookup \ref SolvAttr in one\ref Repository. */
- explicit
- LookupAttr( SolvAttr attr_r, Repository repo_r )
- : _attr( attr_r ), _repo( repo_r )
- {}
+ LookupAttr( SolvAttr attr_r, Repository repo_r, Location = SOLV_ATTR );
+ /** \overload SolvAttr within sub-structure \a parent_r. */
+ LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Repository repo_r, Location = SOLV_ATTR );
+
/** Lookup \ref SolvAttr in one \ref Solvable. */
- LookupAttr( SolvAttr attr_r, Solvable solv_r )
- : _attr( attr_r ), _solv( solv_r )
- {}
+ LookupAttr( SolvAttr attr_r, Solvable solv_r );
+ /** \overload SolvAttr within sub-structure \a parent_r. */
+ LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Solvable solv_r );
public:
/** \name Search result. */
*/
size_type size() const;
- /** TransformIterator returning an \ref iterator vaue of type \c _ResultT. */
- template<class _ResultT, class _AttrT> class transformIterator;
+ /** TransformIterator returning an \ref iterator vaue of type \c TResult. */
+ template<class TResult, class TAttr = TResult>
+ class TransformIterator;
//@}
public:
/** \name What to search. */
//@{
-
/** The \ref SolvAttr to search. */
- SolvAttr attr() const
- { return _attr; }
+ SolvAttr attr() const;
/** Set the \ref SolvAttr to search. */
- void setAttr( SolvAttr attr_r )
- { _attr = attr_r; }
-
+ void setAttr( SolvAttr attr_r );
//@}
+
+ /** \name Restrict attributes to match a pattern. */
+ //@{
+ /** The pattern to match.
+ * You can also evaluate \ref StrMatcher in a boolean context,
+ * in order to test whether an \ref StrMatcher is set:
+ * \code
+ * LookupAttr q;
+ * if ( q.strMatcher() )
+ * ...; // an StrMatcher is set
+ * \endcode
+ */
+ const StrMatcher & strMatcher() const;
+
+ /** Set the pattern to match.
+ * \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
+ */
+ void setStrMatcher( const StrMatcher & matcher_r );
+
+ /** Reset the pattern to match. */
+ void resetStrMatcher();
+ //@}
+
public:
/** \name Where to search. */
//@{
- /** Wheter to search in \ref Pool. */
- bool pool() const
- { return ! (_repo || _solv); }
+ /** Whether to search in \ref Pool. */
+ bool pool() const;
/** Set search in \ref Pool (all repositories). */
- void setPool()
- {
- _repo = Repository::noRepository;
- _solv = Solvable::noSolvable;
- }
+ void setPool( Location = SOLV_ATTR );
- /** Wheter to search in one \ref Repository. */
- Repository repo() const
- { return _repo; }
+ /** Whether to search in one \ref Repository. */
+ Repository repo() const;
/** Set search in one \ref Repository. */
- void setRepo( Repository repo_r )
- {
- _repo = repo_r;
- _solv = Solvable::noSolvable;
- }
+ void setRepo( Repository repo_r, Location = SOLV_ATTR );
- /** Wheter to search in one \ref Solvable. */
- Solvable solvable() const
- { return _solv; }
+ /** Whether to search in one \ref Solvable. */
+ Solvable solvable() const;
/** Set search in one \ref Solvable. */
- void setSolvable( Solvable solv_r )
- {
- _repo = Repository::noRepository;
- _solv = solv_r;
- }
+ void setSolvable( Solvable solv_r );
+ /** Whether to search within a sub-structure (\ref SolvAttr::noAttr if not) */
+ SolvAttr parent() const;
+
+ /** Set search within a sub-structure (\ref SolvAttr::noAttr for none) */
+ void setParent( SolvAttr attr_r );
//@}
+
private:
- SolvAttr _attr;
- Repository _repo;
- Solvable _solv;
+ class Impl;
+ RWCOW_pointer<Impl> _pimpl;
};
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//
+ // CLASS NAME : LookupRepoAttr
+ //
+ /** Lightweight repository attribute value lookup.
+ *
+ * This is just a convenience class that overloads all
+ * \ref LookupAttr methods which take a \ref LookupAttr::Location
+ * argument and sets it to \ref REPO_ATTR.
+ *
+ * \code
+ * // look for a repo attribute in the pool:
+ * sat::LookupAttr p( sat::SolvAttr::repositoryAddedFileProvides, sat::LookupAttr::REPO_ATTR );
+ *
+ * // Equivalent but using LookupRepoAttr:
+ * sat::LookupRepoAttr q( sat::SolvAttr::repositoryAddedFileProvides );
+ * \endcode
+ *
+ * \see \ref LookupAttr
+ */
+ class LookupRepoAttr : public LookupAttr
+ {
+ public:
+ /** \copydoc LookupAttr::LookupAttr() */
+ LookupRepoAttr()
+ {}
+ /** \copydoc LookupAttr::LookupAttr(SolvAttr) */
+ explicit LookupRepoAttr( SolvAttr attr_r )
+ : LookupAttr( attr_r, REPO_ATTR )
+ {}
+ /** \copydoc LookupAttr::LookupAttr(SolvAttr,Repository) */
+ explicit LookupRepoAttr( SolvAttr attr_r, Repository repo_r );
+
+ public:
+ /** \copydoc LookupAttr::setPool */
+ void setPool()
+ { LookupAttr::setPool( REPO_ATTR ); }
+ /** \copydoc LookupAttr::setRepo */
+ void setRepo( Repository repo_r );
+ private:
+ // Hide. You can't look inside and outside Solvables at the same time.
+ using LookupAttr::solvable;
+ using LookupAttr::setSolvable;
+ };
+ ///////////////////////////////////////////////////////////////////
+
+ namespace detail
+ {
+ /** Wrapper around sat \c detail::CDataiterator.
+ *
+ * Manages copy and assign, and release of allocated
+ * resources like datamatcher inside the dataiterator.
+ * Also maintains a copy of the matchstring in order to
+ * keep the char* passed to the dataiterator valid.
+ */
+ class DIWrap
+ {
+ public:
+ /** \c NULL \c detail::CDataiterator */
+ DIWrap()
+ : _dip( 0 )
+ {}
+ /** Initializes */
+ DIWrap( RepoIdType repoId_r, SolvableIdType solvId_r, IdType attrId_r,
+ const std::string & mstring_r = std::string(), int flags_r = 0 );
+ /** \overload to catch \c NULL \a mstring_r. */
+ DIWrap( RepoIdType repoId_r, SolvableIdType solvId_r, IdType attrId_r,
+ const char * mstring_r, int flags_r = 0 );
+ DIWrap( const DIWrap & rhs );
+ ~DIWrap();
+ public:
+ void swap( DIWrap & rhs )
+ {
+ if ( &rhs != this ) // prevent self assign!
+ {
+ std::swap( _dip, rhs._dip );
+ std::swap( _mstring, rhs._mstring );
+ }
+ }
+ DIWrap & operator=( const DIWrap & rhs )
+ {
+ if ( &rhs != this ) // prevent self assign!
+ DIWrap( rhs ).swap( *this );
+ return *this;
+ }
+ void reset()
+ { DIWrap().swap( *this ); }
+ public:
+ /** Evaluate in a boolean context <tt>( _dip != NULL )</tt>. */
+ explicit operator bool() const
+ { return _dip; }
+
+ public:
+ detail::CDataiterator * operator->() const { return _dip; }
+ detail::CDataiterator * get() const { return _dip; }
+ const std::string & getstr() const { return _mstring; }
+
+ private:
+ detail::CDataiterator * _dip;
+ std::string _mstring;
+ };
+ /** \relates DIWrap Stream output. */
+ std::ostream & operator<<( std::ostream & str, const DIWrap & obj );
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ //
// CLASS NAME : LookupAttr::iterator
//
/** Result iterator.
*/
class LookupAttr::iterator : public boost::iterator_adaptor<
iterator // Derived
- , ::_Dataiterator * // Base
+ , detail::CDataiterator * // Base
, detail::IdType // Value
, boost::forward_traversal_tag // CategoryOrTraversal
, detail::IdType // Reference
/** 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. */
/** The current \ref SolvAttr. */
SolvAttr inSolvAttr() const;
+
+ /** Whether this points to the end of a query (Iterator is invalid). */
+ bool atEnd() const
+ { return !_dip; }
//@}
/** \name Test attribute value type. */
/** Whether this is a string attribute. */
bool solvAttrString() const;
- /** *Whether this string attribute is available as \ref IdString. */
+ /** Whether this string attribute is available as \ref IdString. */
bool solvAttrIdString() const;
/** Whether this is a CheckSum attribute.*/
bool solvAttrCheckSum() const;
+
+ /** Whether this is the entry to a sub-structure (flexarray).
+ * This is the entry to a sequence of attributes. To
+ * acces them use \ref subBegin and \ref subEnd.
+ */
+ bool solvAttrSubEntry() const;
+ //@}
+
+ /** \name Iterate sub-structures.
+ *
+ * These are usable iff \ref solvAttrSubEntry is \c true.
+ *
+ * \note Unfortunately the underlying libsolv dataiterator as returned
+ * by \ref subBegin and \ref subFind loses some context when being created.
+ * Thus it's not possible to invoke \ref subBegin and \ref subFind on an
+ * iterator that was previously returned by one of those methods. The result
+ * will be an \c end iterator. For the same reason it is not possible for an
+ * iterator to leave the sub-structure again.
+ *
+ * \code
+ * // Lookup all "update:reference" entries for a specific solvable
+ * sat::LookupAttr q( sat::SolvAttr::updateReference, p->satSolvable() );
+ * for_( res, q.begin(), q.end() )
+ * {
+ * // List all sub values
+ * for_( sub, res.subBegin(), res.subEnd() )
+ * {
+ * cout << sub.asString() << endl;
+ * }
+ *
+ * // Directly access c specific value:
+ * sat::LookupAttr::iterator it( res.subFind( sat::SolvAttr::updateReferenceHref ) );
+ * if ( it != res.subEnd() )
+ * cout << it.asString() << endl;
+ * }
+ * \endcode
+ */
+ //@{
+ /** Whether the sub-structure is empty. */
+ bool subEmpty() const;
+
+ /** Ammount of attributes in the sub-structure.
+ * \note This is not a cheap call. It runs the query.
+ */
+ size_type subSize() const;
+
+ /** Iterator to the begin of a sub-structure.
+ * \see \ref solvAttrSubEntry
+ */
+ iterator subBegin() const;
+ /** Iterator behind the end of a sub-structure.
+ * \see \ref solvAttrSubEntry
+ */
+ iterator subEnd() const;
+ /** Iterator pointing to the first occurance of \ref SolvAttr \a attr_r in sub-structure.
+ * If \ref sat::SolvAttr::allAttr is passed, \ref subBegin is returned.
+ * \see \ref solvAttrSubEntry
+ */
+ iterator subFind( SolvAttr attr_r ) const;
+ /** \overload Extending the current attribute name with by \c ":attrname_r".
+ *
+ * This assumes a sub-structur \c "update:reference" has attributes
+ * like \c "update:reference:type", \c "update:reference:href".
+ *
+ * If an empty \c attrname_r is passed, \ref subBegin is returned.
+ */
+ iterator subFind( const C_Str & attrname_r ) const;
//@}
/** \name Retrieving attribute values. */
unsigned asUnsigned() const;
/** \overload */
bool asBool() const;
+ /** \overload */
+ unsigned long long asUnsignedLL() const;
/** Conversion to string types. */
const char * c_str() const;
* via \ref c_str and \ref asString.
*/
IdString idStr() const;
+ /** \overload Directly returning the \c Id */
+ detail::IdType id() const
+ { return idStr().id(); }
/** As \ref CheckSum. */
CheckSum asCheckSum() const;
/** Templated return type.
- * Specialized for supported types.
+ * Per default assumes an Id based type, so try to construct
+ * it from the Id.
+ *
+ * Should be specialized for supported types above.
*/
- template<class _Tp> _Tp asType() const;
+ template<class Tp> Tp asType() const { return Tp(id()); }
//@}
///////////////////////////////////////////////////////////////////
public:
/**
- * C-tor taking over ownership of the passed scoped _Dataiterator*
+ * C-tor taking over ownership of the passed \c detail::CDataiterator
* and doing it's first iteration (::dataiterator_step)
*/
- iterator( scoped_ptr< ::_Dataiterator> & dip_r );
+ iterator( detail::DIWrap & dip_r );
private:
friend class boost::iterator_core_access;
- ::_Dataiterator * cloneFrom( const ::_Dataiterator * rhs );
-
template <class OtherDerived, class OtherIterator, class V, class C, class R, class D>
bool equal( const boost::iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> & rhs ) const
{
&& ( ! base() || dip_equal( *base(), *rhs.base() ) );
}
- bool dip_equal( const ::_Dataiterator & lhs, const ::_Dataiterator & rhs ) const;
+ bool dip_equal( const detail::CDataiterator & lhs, const detail::CDataiterator & rhs ) const;
detail::IdType dereference() const;
public:
/** Expert backdoor. */
- ::_Dataiterator * get() const
+ detail::CDataiterator * get() const
{ return _dip.get(); }
private:
- scoped_ptr< ::_Dataiterator> _dip;
+ detail::DIWrap _dip;
};
///////////////////////////////////////////////////////////////////
/** \relates LookupAttr::iterator Stream output. */
std::ostream & operator<<( std::ostream & str, const LookupAttr::iterator & obj );
+ ///////////////////////////////////////////////////////////////////
+
+ /** \name Helpers and forward declarations from LookupAttrTools.h */
+ //@{
template<> inline int LookupAttr::iterator::asType<int>() const { return asInt(); }
template<> inline unsigned LookupAttr::iterator::asType<unsigned>() const { return asUnsigned(); }
+ template<> inline unsigned long long LookupAttr::iterator::asType<unsigned long long>() const { return asUnsignedLL(); }
template<> inline bool LookupAttr::iterator::asType<bool>() const { return asBool(); }
template<> inline const char * LookupAttr::iterator::asType<const char *>() const { return c_str(); }
template<> inline std::string LookupAttr::iterator::asType<std::string>() const { return asString(); }
template<> inline IdString LookupAttr::iterator::asType<IdString>() const { return idStr(); }
+ template<> CheckSum LookupAttr::iterator::asType<CheckSum>() const;
- ///////////////////////////////////////////////////////////////////
- //
- // CLASS NAME : LookupAttr::transformIterator
- //
- /** TransformIterator returning an \ref iterator value of type \c _ResultT.
- *
- * The underlying LookupAttr::iterators value is retrieved \ref asType<_AttrT>
- * and the returned \ref ResultT is constructed fron that value.
- *
- * \code
- * class Keywords
- * {
- * public:
- * Keywords( sat::Solvable solv_r )
- * : _q( sat::SolvAttr::keywords, solv_r )
- * {}
- *
- * public:
- * typedef sat::LookupAttr::transformIterator<PackageKeyword,IdString> iterator;
- *
- * iterator begin() const { return iterator( _q.begin() ); }
- * iterator end() const { return iterator( _q.end() ); }
- *
- * private:
- * sat::LookupAttr _q;
- * };
- * \endcode
- *
- * \see \ref ArrayAttr.
- */
- template<class _ResultT, class _AttrT>
- class LookupAttr::transformIterator : public boost::iterator_adaptor<
- transformIterator<_ResultT,_AttrT> // Derived
- , LookupAttr::iterator // Base
- , _ResultT // Value
- , boost::forward_traversal_tag // CategoryOrTraversal
- , _ResultT // Reference
- >
- {
- public:
- transformIterator()
- {}
-
- explicit
- transformIterator( const LookupAttr::iterator & val_r )
- { this->base_reference() = val_r; }
-
- public:
-
- /** \name Moving fast forward. */
- //@{
- /** On the next call to \ref operator++ advance to the next \ref SolvAttr. */
- void nextSkipSolvAttr()
- { this->base_reference().nextSkipSolvAttr(); }
-
- /** On the next call to \ref operator++ advance to the next \ref Solvable. */
- void nextSkipSolvable()
- { this->base_reference().nextSkipSolvable(); }
-
- /** On the next call to \ref operator++ advance to the next \ref Repository. */
- void nextSkipRepo()
- { this->base_reference().nextSkipRepo(); }
-
- /** Immediately advance to the next \ref SolvAttr. */
- void skipSolvAttr()
- { this->base_reference().skipSolvAttr(); }
-
- /** Immediately advance to the next \ref Solvable. */
- void skipSolvable()
- { this->base_reference().skipSolvable(); }
-
- /** Immediately advance to the next \ref Repository. */
- void skipRepo()
- { this->base_reference().skipRepo(); }
- //@}
-
- /** \name Current position info. */
- //@{
- /** The current \ref Repository. */
- Repository inRepo() const
- { return this->base_reference().inRepo(); }
-
- /** The current \ref Solvabele. */
- Solvable inSolvable() const
- { return this->base_reference().inSolvable(); }
-
- /** The current \ref SolvAttr. */
- SolvAttr inSolvAttr() const
- { return this->base_reference().inSolvAttr(); }
- //@}
-
- private:
- friend class boost::iterator_core_access;
-
- _ResultT dereference() const
- {
- const LookupAttr::iterator lit( this->base_reference() );
- return _ResultT( lit.asType<_AttrT>() );
- }
- };
- ///////////////////////////////////////////////////////////////////
-
- template<class _ResultT, class _AttrT>
+ template<class TResult, class TAttr>
class ArrayAttr;
-
- template<class _ResultT, class _AttrT>
- std::ostream & operator<<( std::ostream & str, const ArrayAttr<_ResultT,_AttrT> & obj );
-
- ///////////////////////////////////////////////////////////////////
- //
- // CLASS NAME : ArrayAttr
- //
- /** \ref LookupAttr::transformIterator based container to retrieve list attributes.
- *
- * \code
- * typedef ArrayAttr<PackageKeyword,IdString> Keywords;
- * Keywords k( sat::SolvAttr::keywords );
- * dumpRange( MIL << "All Keywords: ", k.begin(), k.end() ) << endl;
- * \endcode
- *
- * \todo Maybe add some way to unify the result.
- */
- template<class _ResultT, class _AttrT>
- class ArrayAttr
- {
- friend std::ostream & operator<< <_ResultT,_AttrT>( std::ostream & str, const ArrayAttr<_ResultT,_AttrT> & obj );
-
- public:
- ArrayAttr()
- {}
-
- ArrayAttr( SolvAttr attr_r )
- : _q( attr_r )
- {}
-
- ArrayAttr( SolvAttr attr_r, Repository repo_r )
- : _q( attr_r, repo_r )
- {}
-
- ArrayAttr( SolvAttr attr_r, Solvable solv_r )
- : _q( attr_r, solv_r )
- {}
-
- public:
- typedef sat::LookupAttr::transformIterator<_ResultT,_AttrT> iterator;
-
- iterator begin() const
- { return iterator( _q.begin() ); }
-
- iterator end() const
- { return iterator( _q.end() ); }
-
- bool empty() const
- { return _q.empty(); }
-
- public:
-
- iterator find( const _ResultT & key_r ) const
- {
- for_( it, begin(), end() )
- {
- if ( *it == key_r )
- return it;
- }
- return end();
- }
-
- private:
- sat::LookupAttr _q;
- };
- ///////////////////////////////////////////////////////////////////
-
- /** \relates LookupAttr::iterator Stream output. */
- template<class _ResultT, class _AttrT>
- inline std::ostream & operator<<( std::ostream & str, const ArrayAttr<_ResultT,_AttrT> & obj )
- { return dumpOn( str, obj._q); }
+ //@}
/////////////////////////////////////////////////////////////////
} // namespace sat
///////////////////////////////////////////////////////////////////
/** \relates LookupAttr::iterator Stream output of the underlying iterator for debug. */
-std::ostream & operator<<( std::ostream & str, const ::_Dataiterator * obj );
+std::ostream & operator<<( std::ostream & str, const zypp::sat::detail::CDataiterator * obj );
/** \relates LookupAttr::iterator Stream output of the underlying iterator for debug. */
-inline std::ostream & operator<<( std::ostream & str, const ::_Dataiterator & obj )
+inline std::ostream & operator<<( std::ostream & str, const zypp::sat::detail::CDataiterator & obj )
{ return str << &obj; }
#endif // ZYPP_SAT_LOOKUPATTR_H