augment extensible filter to add the obvious variations

that is
 - allow also for a disjunctive extension
 - allow for negated conditions
 - allow to flip the current condition

unit test PASS
This commit is contained in:
Fischlurch 2015-12-05 02:00:44 +01:00
parent 0e41555402
commit 6659a7dee1
3 changed files with 118 additions and 11 deletions

View file

@ -358,6 +358,20 @@ namespace lib {
* modified, current head of iteration gets re-evaluated
* and possible fast-forwarded to the next element
* satisfying the now extended filter condition.
* @note changing the condition modifies a given iterator in place.
* Superficially this might look as if the storage remains
* the same, but in fact we're adding a lambda closure,
* which the runtime usually allocates on the heap,
* holding the previous functor and a second functor
* for the added clause.
* @warning the addition of disjunctive and negated clauses might
* actually weaken the filter condition. Yet still there is
* \em no reset of the source iterator, i.e. we don't
* re-evaluate from start, but just from current head.
* Which means we might miss elements in the already consumed
* part of the source sequence, which theoretically would
* pass the now altered filter condition.
* @see IterTools_test::verify_filterExtension
*/
template<class IT>
class ExtensibleFilterIter
@ -396,6 +410,64 @@ namespace lib {
reEvaluate();
return *this;
}
template<typename COND>
ExtensibleFilterIter&
andNotFilter (COND conjunctiveClause)
{
function<bool(Val)>& filter = this->core_.predicate_;
filter = [=](Val val)
{
return filter(val)
and not conjunctiveClause(val);
};
reEvaluate();
return *this;
}
template<typename COND>
ExtensibleFilterIter&
orFilter (COND disjunctiveClause)
{
function<bool(Val)>& filter = this->core_.predicate_;
filter = [=](Val val)
{
return filter(val)
or disjunctiveClause(val);
};
reEvaluate();
return *this;
}
template<typename COND>
ExtensibleFilterIter&
orNotFilter (COND disjunctiveClause)
{
function<bool(Val)>& filter = this->core_.predicate_;
filter = [=](Val val)
{
return filter(val)
or not disjunctiveClause(val);
};
reEvaluate();
return *this;
}
ExtensibleFilterIter&
flipFilter ()
{
function<bool(Val)>& filter = this->core_.predicate_;
filter = [=](Val val)
{
return not filter(val);
};
reEvaluate();
return *this;
}
};

View file

@ -206,15 +206,18 @@ END
TEST "Lumiera Iterator Tools" IterTools_test 20 <<END
out: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out: ::20::18::16::14::12::10::8::6::4::2
out: ::19::17::15::13::11::9::7::5::3::1
out: ::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out: ::16::14::12::10::8::6::4::2
out: ::17::15::13::11::9::7::5::3::1
out: ::10::9::8::7::6::5::4::3::2::1
out: ::-10::-9::-8::-7::-6::-5::-4::-3::-2::-1
out: ::12::11::10::9::8::7::6::5::4::3
out-lit: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out-lit: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out-lit: ::20::18::16::14::12::10::8::6::4::2
out-lit: ::19::17::15::13::11::9::7::5::3::1
out-lit: ::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out-lit: ::16::14::12::10::8::6::4::2
out-lit: ::17::15::13::11::9::7::5::3::1
out-lit: ::12::18::24::30::36::42::48::54
out-lit: ::13::17::19::23::25::29::31::35::37::41::43::47::49::53::55::59
out-lit: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
out-lit: ::-20::-19::-18::-17::-16::-15::-14::-13::-12::-11::-10::-9::-8::-7::-6::-5::-4::-3::-2::-1
out-lit: ::22::21::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3
END

View file

@ -161,7 +161,12 @@ namespace test{
* while in the middle of an ongoing iteration.
* Typically this means sharpening the filter condition
* and thus making the filter more restrictive, filtering
* away more elements of the source stream.
* away more elements of the source stream. But through
* the ability to add disjunctive and negated clauses,
* it is also possible to weaken the filter condition
* @note in case of a weakened filter condition, there is
* \em no reset of the source iterator, i.e. we don't
* re-evaluate from start, but just from current head.
*/
void
verify_filterExtension ()
@ -189,14 +194,41 @@ namespace test{
++filterIter;
CHECK (4 == *filterIter);
// sharpen the condition...
filterIter.andFilter(takeTrd);
CHECK (!isnil (filterIter));
CHECK (6 == *filterIter);
CHECK (6 == *filterIter); // divisible by two and by three
++filterIter;
CHECK (12 == *filterIter);
verifyComparisons (filterIter);
pullOut (filterIter);
// adding a disjunctive clause actually weakens the filter...
filterIter = {completeSequence, takeTrd};
CHECK (!isnil (filterIter));
CHECK (0 == *filterIter);
++filterIter;
CHECK (3 == *filterIter);
filterIter.orFilter(takeEve);
CHECK (3 == *filterIter);
++filterIter;
CHECK (4 == *filterIter);
++filterIter;
CHECK (6 == *filterIter);
verifyComparisons (filterIter);
// flip filter logic
filterIter.flipFilter();
CHECK (7 == *filterIter); // not even and not divisible by three
++filterIter;
CHECK (11 == *filterIter);
++filterIter;
CHECK (13 == *filterIter);
verifyComparisons (filterIter);
pullOut (filterIter);
}