Mailinglist Archive: zypp-devel (227 mails)

< Previous Next >
Re: [zypp-devel] implementing PoolQuery iterator using sat-solver's Dataiterator
  • From: Michael Andres <ma@xxxxxxx>
  • Date: Thu, 3 Apr 2008 15:40:08 +0200
  • Message-id: <20080403134008.GA15508@xxxxxxx>
On Thu, Apr 03, Jan Kupec wrote:

class PoolQuery
{
public:

typedef ::_Dataiterator RepoDataIterator;

class ResultIterator : public boost::iterator_adaptor<
ResultIterator // Derived
, RepoDataIterator * // Base
, const sat::Solvable // Value
, boost::forward_traversal_tag // CategoryOrTraversal
, const sat::Solvable & // Reference
>

The value type sat::Solvable is created by your iterator. So you can't
pass back a 'const sat::Solvable &' in operator*. So it should IMO be:

class ResultIterator : public boost::iterator_adaptor<
ResultIterator // Derived
, RepoDataIterator * // Base
! , sat::Solvable // Value
, boost::forward_traversal_tag // CategoryOrTraversal
! , sat::Solvable // Reference
>


{
public:
ResultIterator()
: ResultIterator::iterator_adaptor_(0)
{ _rdit = 0; base_reference() = 0; }

(AFAIK is base_reference()=0 not necessary. That's what
ResultIterator::iterator_adaptor_(0) does)

As Josef sugested, store the ::Dataiterator

private:
::Dataiterator _di;

and adjust base to be &_di, as long as the iterator is valid.
set it to 0 to indicate the end is reached.



ResultIterator(RepoDataIterator * rdit)
: ResultIterator::iterator_adaptor_(0)
{ _rdit = rdit; base_reference() = rdit; }

Takes a 'const RepoDataIterator &' and strore a copy to _di.

If this ctor stays public add some comment, that tells that the
user is responsible for passing a valid RepoDataIterator. One that
did (at least) the first step and is not at end of query. Otherwise
you don't know whether to adjust base to 0 or &_di.

Or make it private and 'friend class PoolQuery'. PoolQuery will then
use ::dataiterator_init to create it. Then constructs the iterator, and
the iterator always does the 1st ::dataiterator_step to move to the 1st
result. The ::dataiterator_step then determines the value for base.


Thake care what happens in the iterator is copied!

Each copy of the iterator creates it's own copy of the ::Dataiterator.
so the base Dataiterator* is not valid in the copy. Don't use it. But the
same base indicates that both iterators originate from the same
::Dataiterator (at least you can assume this, otherwise use a serial
number in base).


private:
friend class boost::iterator_core_access;

sat::Solvable dereference() const
{
return _rdit ? sat::Solvable(_rdit->solvid) :
sat::Solvable::noSolvable;
}

void increment()
{
if (::dataiterator_step(_rdit))
else
{
base_reference() = 0;
}
}

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;
{

2 iterators are equal if

- either both are at the end (base is 0)
- or if base is the same and _di == rhs._di.
Same query and same position in the query.
(maye we find some _di fields that must be excluded,
Don't know yet).

...
if (rhs.base()->solvid == base()->solvid)
return true;

But just testing for the same solvabe is wrong, even if you test two
itertors that originate fron the same query. Maye you have multiple visits
of the same solvable.

And if you compare two iterators from different queries, they should not
be equal, even if they happen to point to the same solvable.




I use (maybe wrongly) the RepoDataIterator * as the base.

This should not matter if you overload all relevant methods, so you
completely control the base value.



RepoDataIterator is being created in PoolQuery::Impl, the begin() and
end() methods look like this:

PoolQuery::ResultIterator PoolQuery::Impl::begin()
{
sat::Pool pool(sat::Pool::instance());
sat::Pool::RepositoryIterator itr = pool.reposBegin();
::dataiterator_init(&_rdit, itr->get(), 0 /*p*/, 0/*keyname*/, 0
/*matchstring*/, _flags);

INT << "next: " << ::dataiterator_step(&_rdit) << endl;

( The _step would be moved to the iterator)

return PoolQuery::ResultIterator(&_rdit);
}

PoolQuery::ResultIterator PoolQuery::Impl::end()
{
return PoolQuery::ResultIterator(0);

Default constructed ResultIterator().


}


This has (at least :O) two drawbacks:

1) RepoDataIterator * is the same in all instances except for those
created with PoolQuery::end()
2) PoolQuery::begin() always resets the dataiterator state for all
existing instances

The above might help to fix this.

BUT I also agree with Josef, that this assumes that the whole query
is done by a single ::dataiterator, and there is not much room for
optimization.

It will become a bit harder if the query should include the poolitem
status. PoolQuery could e.g provide additional filter functors which
are passed to the iterator. We will see..

--

cu,
Michael Andres

+------------------------------------------------------------------+
Key fingerprint = 2DFA 5D73 18B1 E7EF A862 27AC 3FB8 9E3A 27C6 B0E4
+------------------------------------------------------------------+
Michael Andres YaST Development ma@xxxxxxxxxx
SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG Nuernberg)
Maxfeldstrasse 5, D-90409 Nuernberg, Germany, ++49 (0)911 - 740 53-0
+------------------------------------------------------------------+

--
To unsubscribe, e-mail: zypp-devel+unsubscribe@xxxxxxxxxxxx
For additional commands, e-mail: zypp-devel+help@xxxxxxxxxxxx

< Previous Next >
References