trying to implement a simple iterator adapter working

(oops, didn't expect this to be so difficult...)
This commit is contained in:
Fischlurch 2009-07-13 01:16:30 +02:00
parent fa3d596a59
commit 60cf9e8c9e
10 changed files with 369 additions and 105 deletions

View file

@ -123,6 +123,8 @@ namespace lumiera {
/* generic error situations */
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
/** Macro for creating derived exception classes properly
* integrated into Lumiera's exception hierarchy. Using

View file

@ -66,6 +66,7 @@ namespace lumiera {
/* some further generic error situations */
LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch");
LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached");
} // namespace error

View file

@ -43,32 +43,172 @@
//#include "include/logging.h"
//#include "lib/error.hpp"
#include "lib/error.hpp"
#include "lib/bool-checkable.hpp"
//#include "lib/util.hpp"
//#include <vector>
//#include <boost/noncopyable.hpp>
#include <boost/type_traits/remove_pointer.hpp>
namespace lib {
// using util::for_each;
using boost::remove_pointer;
/**
* simple ptr-to-object based implementation of the lumiera forward iterator concept.
* Basically such an PtrIter behaves like the similar concept from STL, but
* - it is not just a disguised pointer (meaning, its more expensive)
* - it checks validity on every operation and may throw
* - it has a distinct back-link to the source container
* - the source container needs to implement iterStart() and iterInc()
* - we need friendship to and from the container class
* - the end-of-iteration can be detected by bool check
*
* @see scoped-ptrvect.hpp usage example
* @see iter-adaptor-test.cpp
*/
template<class T, class CON>
class PtrIter
template<class POS, class CON>
class IterAdapter
: public lib::BoolCheckable<IterAdapter<POS,CON> >
{
const CON* source_;
POS pos_;
/////////////////////////////////////////////////////////////////////////TODO: implement empty test
/////////////////////////////////////////////////////////////////////////TODO: implement comparisons
public:
typedef typename POS::pointer pointer; //////////////////TODO: do we really need all those typedefs???
typedef typename POS::reference reference;
typedef typename POS::value_type value_type;
IterAdapter (const CON* src, const POS& startpos)
: source_(src)
, pos_(startpos)
{ }
IterAdapter ()
: source_(0)
, pos_(0)
{ }
/* === lumiera forward iterator concept === */
reference
operator*() const
{
_maybe_throw();
return *pos_;
}
pointer
operator->() const
{
_maybe_throw();
return pos_;
}
IterAdapter&
operator++()
{
_maybe_throw();
CON::iterNext (source_,pos_);
return *this;
}
IterAdapter
operator++(int)
{
_maybe_throw();
IterAdapter oldPos(*this);
CON::iterNext (source_,pos_);
return oldPos;
}
bool
isValid () const
{
return (source_ && CON::iterValid(source_,pos_));
}
private:
void
_maybe_throw() const
{
if (!isValid())
throw lumiera::error::Invalid ("Can't iterate further",
lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
}
};
/**
/** wrapper for an existing Iterator type,
* automatically dereferencing the former's output.
* For this to work, the "source" iterator is expected
* to be declared on \em pointers rather than on values.
* @note bool checkable if and only if source is...
*/
template<class T, class CON>
template<class IT>
class PtrDerefIter
: public lib::BoolCheckable<PtrDerefIter<IT> >
{
IT i_;
public:
typedef typename IT::value_type pointer;
typedef typename remove_pointer<pointer>::type & reference;
PtrDerefIter (IT srcIter)
: i_(srcIter)
{ }
/* === lumiera forward iterator concept === */
reference
operator*() const
{
return *(*i_);
}
pointer
operator->() const
{
return *i_;
}
PtrDerefIter&
operator++()
{
++i_;
return *this;
}
PtrDerefIter
operator++(int)
{
return PtrDerefIter (i_++);
}
bool
isValid () const
{
return bool(i_);
}
};

View file

@ -45,6 +45,7 @@
#include "include/logging.h"
#include "lib/iter-adaptor.hpp"
#include "lib/error.hpp"
#include "lib/util.hpp"
@ -101,25 +102,25 @@ namespace lib {
T&
manage (T* obj)
{
if (obj)
try
{
push_back (obj);
return *obj;
}
catch(...)
{
delete obj;
throw;
} }
REQUIRE (obj);
try
{
push_back (obj);
return *obj;
}
catch(...)
{
delete obj;
throw;
} }
void
clear()
{
typedef typename _Vec::iterator VIter;
VIter e = this->end();
for (VIter i = this->begin(); i!=e; ++i)
VIter e = _Vec::end();
for (VIter i = _Vec::begin(); i!=e; ++i)
{
if (*i)
try
@ -143,8 +144,8 @@ namespace lib {
return *get(i);
}
typedef PtrDerefIter<reference, _Vec> iterator;
typedef PtrDerefIter<const_reference, _Vec> const_iterator;
typedef PtrDerefIter<typename _Vec::iterator> iterator;
typedef PtrDerefIter<typename _Vec::const_iterator> const_iterator;
iterator begin() { return iterator (_Vec::begin()); }
const_iterator begin() const { return const_iterator (_Vec::begin()); }

View file

@ -26,9 +26,11 @@
#include "include/symbol.hpp"
#include "lib/lumitime.hpp"
#include <typeinfo>
#include <string>
#include <cstdlib>
@ -36,7 +38,9 @@ namespace lib {
namespace test{
using lumiera::Symbol;
using lumiera::Time;
using std::string;
using std::rand;
@ -48,7 +52,7 @@ namespace test{
* type identification as implemented by the compiler.
*/
template<typename T>
const char*
inline const char*
showType (T const& obj, Symbol name=0)
{
return name? name : typeid(obj).name();
@ -61,7 +65,7 @@ namespace test{
* type identification as implemented by the compiler.
*/
template<typename T>
const char*
inline const char*
showType (Symbol name=0)
{
return name? name : typeid(T).name();
@ -75,21 +79,21 @@ namespace test{
/** for printing sizeof(), trying to figure out the type name automatically */
template<typename T>
string
inline string
showSizeof(Symbol name=0)
{
return showSizeof (sizeof (T), showType<T> (name));
}
template<typename T>
string
inline string
showSizeof(T const& obj, Symbol name=0)
{
return showSizeof (sizeof (obj), showType (obj,name));
}
template<typename T>
string
inline string
showSizeof(T *obj, Symbol name=0)
{
return obj? showSizeof (*obj, name)
@ -97,6 +101,16 @@ namespace test{
}
/** create a random but not insane Time value */
inline Time
randTime ()
{
return Time (500 * (rand() % 2), (rand() % 600));
}
}} // namespace lib::test

View file

@ -23,45 +23,14 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
//#include "proc/asset/media.hpp"
//#include "proc/mobject/session.hpp"
//#include "proc/mobject/session/edl.hpp"
//#include "proc/mobject/session/testclip.hpp"
//#include "proc/mobject/test-dummy-mobject.hpp"
//#include "lib/p.hpp"
//#include "proc/mobject/placement.hpp"
//#include "proc/mobject/placement-index.hpp"
//#include "proc/mobject/explicitplacement.hpp"
#include "proc/control/argument-tuple-accept.hpp"
#include "lib/meta/function.hpp"
#include "lib/meta/tuple.hpp"
//#include "lib/scoped-ptrvect.hpp"
//#include "lib/lumitime-fmt.hpp"
//#include "lib/meta/typelist.hpp"
//#include "lib/meta/tuple.hpp"
//#include "lib/util.hpp"
#include "lib/lumitime-fmt.hpp"
#include <tr1/functional>
//#include <boost/format.hpp>
#include <iostream>
//#include <strstream>
//#include <cstdlib>
//#include <string>
//using std::tr1::bind;
//using std::tr1::placeholders::_1;
//using std::tr1::placeholders::_2;
using std::tr1::function;
//using util::isnil;
//using util::and_all;
//using boost::format;
//using lumiera::Time;
//using util::contains;
//using std::string;
//using std::rand;
//using std::ostream;
//using std::ostrstream;
using std::cout;
using std::endl;
@ -70,15 +39,12 @@ namespace control {
namespace test {
using lib::test::showSizeof;
using lib::test::randTime;
using lumiera::Time;
using std::tr1::function;
using lumiera::typelist::FunctionSignature;
using lumiera::typelist::Tuple;
// using session::test::TestClip;
// using lumiera::P;
// using namespace lumiera::typelist;
// using lumiera::typelist::Tuple;
// using control::CmdClosure;
@ -98,36 +64,32 @@ namespace test {
template<typename SIG>
class TestClass
: public ArgumentTupleAccept< SIG // to derive the desired signature
, TestClass // the target class providing the implementation
, TestClass<SIG> // the target class providing the implementation
, typename Tup<SIG>::Ty // base class to inherit from
>
{
typedef typename Tup<SIG>::Ty ATuple;
public:
void
bind (typename Tup<SIG>::Ty const& tuple)
bindArg (ATuple const& tuple)
{
*this = tuple;
static_cast<ATuple&> (*this) = tuple;
}
};
Time
randTime ()
{
UNIMPLEMENTED ("create a random but not insane Time value");
}
} // test-helper implementation
typedef lib::ScopedPtrVect<CmdClosure> ArgTuples;
/***************************************************************
* @test Build test object, which accepts a bind(...) call with
* specifically typed arguments.
/*************************************************************
* @test Build a test object, which accepts a bind(...) call
* with specifically typed arguments.
*
* @see control::CommandArgumentHolder
*/
@ -144,10 +106,10 @@ namespace test {
testTime.bind(randTime(),23);
cout << showSizeof(testVoid) << endl;
cout << showSizeof(testITim) << endl;
cout << showSizeof(testTime) << endl;
cout << testITim.getHead() << endl;
ASSERT (23 == testITim.getTail().getHead());
cout << testTime.getHead() << endl;
ASSERT (23 == testTime.getTail().getHead());
}
};

View file

@ -42,7 +42,7 @@
//#include <tr1/functional>
#include <boost/format.hpp>
#include <iostream>
#include <strstream>
#include <sstream>
//#include <cstdlib>
#include <string>
@ -58,7 +58,7 @@ using lumiera::Time;
using std::string;
//using std::rand;
using std::ostream;
using std::ostrstream;
using std::ostringstream;
using std::cout;
using std::endl;
@ -67,6 +67,7 @@ namespace control {
namespace test {
using lib::test::showSizeof;
using lib::test::randTime;
// using session::test::TestClip;
// using lumiera::P;
@ -82,7 +83,7 @@ namespace test {
namespace { // test helpers
ostrstream protocol; ///< used to verify the test function calls
ostringstream protocol; ///< used to verify the test function calls
template<typename TY>
@ -103,7 +104,7 @@ namespace test {
}
TY&
operator* () const
operator* ()
{
return element_;
}
@ -111,7 +112,7 @@ namespace test {
friend ostream&
operator<< (ostream& out, const Tracker& tra)
{
return out << element_;
return out << tra.element_;
}
};
@ -128,13 +129,13 @@ namespace test {
}
Tracker<string>
captureState (Tracker<Time> time, Tracker<string> str, int rand)
captureState (Tracker<Time>, Tracker<string>, int)
{
return protocol.str();
}
void
undoIt (Tracker<Time> time, Tracker<string> str, int rand, Tracker<string> memento)
undoIt (Tracker<Time> time, Tracker<string>, int, Tracker<string> memento)
{
protocol << "undoIt(time="<<time<<")---state-was-:"<< *memento;
}
@ -156,12 +157,6 @@ namespace test {
// serialise, then de-serialise into a new instance and compare both
}
Time
randTime ()
{
UNIMPLEMENTED ("create a random but not insane Time value");
}
} // test-helper implementation
@ -183,6 +178,7 @@ namespace test {
virtual void
run (Arg)
{
#if false ////////////////////////////////////////////////////////////////////////////TODO.....
ArgTuples testTuples;
Tracker<Time>::instanceCnt = 0;
Tracker<string>::instanceCnt = 0;
@ -323,6 +319,7 @@ namespace test {
bound_undoFun();
cout << protocol.str() << endl;
#endif ////////////////////////////////////////////////////////////////////////////TODO.....
}
};

View file

@ -77,14 +77,14 @@ namespace mobject {
// TODO: how to handle insufficiently determinated Placement? Throw?
FixedLocation & fixloc = pc.chain(Time(1)); // TODO: the track??
ExplicitPlacement expla = pc.resolve();
ASSERT (expla.time == 1);
ASSERT (expla.time == Time(1));
ASSERT (!expla.chain.isOverdetermined());
//ASSERT (*expla == *pc); ////////////////////////TODO: define equality on placements (Trac #119)
// now overconstraining with another Placement
pc.chain(Time(2));
ExplicitPlacement expla2 = pc.resolve();
ASSERT (expla2.time == 2); // the latest addition wins
ASSERT (expla2.time == Time(2)); // the latest addition wins
ASSERT (expla2.chain.isOverdetermined());
}
};

View file

@ -106,7 +106,7 @@ namespace test {
ASSERT (1 == ref1.use_count());
ASSERT (1 == ref2.use_count());
ExplicitPlacement exPla = refX.resolve();
ASSERT (exPla.time == 2); // indeed get back the time we set on p2 above
ASSERT (exPla.time == Time(2)); // indeed get back the time we set on p2 above
ASSERT (2 == ref2.use_count()); // exPla shares ownership with p2
ASSERT (index->contains(ref1)); // ref can stand-in for a placement-ID
@ -144,9 +144,9 @@ namespace test {
ASSERT (ref2 != refX);
// resolution is indeed "live", we see changes to the referred placement
ASSERT (refX.resolve().time == 0);
ASSERT (refX.resolve().time == Time(0));
p1 = p2;
ASSERT (refX.resolve().time == 2); // now we get the time tie we originally set on p2
ASSERT (refX.resolve().time == Time(2)); // now we get the time tie we originally set on p2
ASSERT (3 == ref2.use_count()); // p1, p2 and exPla share ownership
// actually, the assignment has invalidated ref1, because of the changed ID

View file

@ -26,14 +26,93 @@
#include "lib/util.hpp"
//#include "lib/scoped-ptrvect.hpp"
#include "lib/iter-adaptor.hpp"
//#include "testdummy.hpp"
#include <vector>
#include <iostream>
#include <boost/lexical_cast.hpp>
namespace lib {
namespace test{
using ::Test;
using util::isnil;
// using util::isnil;
using boost::lexical_cast;
using util::for_each;
using std::vector;
using std::cout;
using std::endl;
namespace {
uint NUM_ELMS = 10;
class TestContainer
{
typedef vector<int *> _Vec;
_Vec numberz_;
static void killIt (int *it) { delete it; }
public:
TestContainer (uint count)
: numberz_(count)
{
for (uint i=0; i<count; ++i)
numberz_[i] = new int(i);
}
~TestContainer ()
{
for_each (numberz_, killIt);
}
typedef int * value_type;
typedef int ** pointer;
typedef int *& reference;
typedef IterAdapter<_Vec::iterator, TestContainer> iterator;
typedef IterAdapter<_Vec::const_iterator, TestContainer> const_iterator;
typedef PtrDerefIter<iterator > ref_iterator;
typedef PtrDerefIter<const_iterator> const_ref_iter;
iterator begin () { return iterator (this, numberz_.begin()); }
const_iterator begin () const { return const_iterator (this, numberz_.begin()); }
ref_iterator begin_ref () { return ref_iterator (begin()); }
const_ref_iter begin_ref () const { return const_ref_iter (begin()); }
iterator end () { return iterator(); }
const_iterator end () const { return const_iterator(); }
protected:
friend class IterAdapter<_Vec::iterator, TestContainer>;
friend class IterAdapter<_Vec::const_iterator,TestContainer>;
template<class ITER>
static void
iterNext (const TestContainer* src, ITER& pos)
{
if (iterValid(src,pos))
++pos;
}
template<class ITER>
static bool
iterValid (const TestContainer* src, ITER& pos)
{
REQUIRE (src);
return pos != src->numberz_.end();
}
};
}
@ -47,21 +126,89 @@ namespace test{
{
virtual void
run (Arg)
run (Arg arg)
{
UNIMPLEMENTED ("build a simple lumiera forward iterator");
simpleUsage();
// iterating();
// detaching();
if (0 < arg.size()) NUM_ELMS = lexical_cast<uint> (arg[0]);
TestContainer testElms (NUM_ELMS);
simpleUsage (testElms);
iterTypeVariations (testElms);
}
static void showIt (int* elm) { cout << "::" << *elm; }
void
simpleUsage()
simpleUsage (TestContainer& elms)
{
for_each (elms, showIt);
cout << endl;
}
void
iterTypeVariations (TestContainer& elms)
{
TestContainer const& const_elms (elms);
int i = 0;
for (TestContainer::iterator iter = elms.begin();
iter; ++iter, ++i
)
{
ASSERT (iter);
ASSERT (iter != elms.end());
ASSERT (**iter == i);
--(**iter);
ASSERT (**iter == i-1);
}
i = 0;
for (TestContainer::const_iterator iter = const_elms.begin();
iter; ++iter, ++i
)
{
ASSERT (iter);
// ASSERT (iter != elms.end()); ////////////////////////////TODO: implement comparison
ASSERT (**iter == i-1);
// note: the previous run indeed modified
// the element within the container.
// --(**iter); // doesn't compile, because it's const
}
i = 0;
for (TestContainer::ref_iterator iter = elms.begin_ref();
iter; ++iter, ++i
)
{
ASSERT (iter);
ASSERT ((*iter) == i-1);
++(*iter);
ASSERT ((*iter) == i);
}
i = 0;
for (TestContainer::const_ref_iter iter = const_elms.begin_ref();
iter; ++iter, ++i
)
{
ASSERT (iter);
ASSERT ((*iter) == i);
}
ASSERT (TestContainer::iterator() == elms.end());
ASSERT (!(TestContainer::iterator()));
ASSERT (!(elms.end()));
// ASSERT (isnil (elms.end())); ////////////////////////////TODO: implement empty test
ASSERT (elms.begin());
// ASSERT (!isnil (elms.begin())); ////////////////////////////TODO: implement empty test
}
};
LAUNCHER (IterAdaptor_test, "unit common");