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
bool equal( const boost::iterator_adaptor & 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@novell.com 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@opensuse.org For additional commands, e-mail: zypp-devel+help@opensuse.org