Skip to content
Snippets Groups Projects
Commit 0e973766 authored by Markus Blatt's avatar Markus Blatt
Browse files

facade clases for easy creation of stl conformant iterators together with tests.

[[Imported from SVN: r1030]]
parent f5b35197
No related branches found
No related tags found
No related merge requests found
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// $Id$
#ifndef __DUNE_ITERATORFACADES_HH__
#define __DUNE_ITERATORFACADEs_HH__
#include <iterator>
#include <dune/common/typetraits.hh>
namespace Dune
{
/*! \defgroup IteratorFacades Iterator facades
\ingroup Common
\brief Iterator facades for writing stl conformant iterators.
With using these facades writing iterators for arbitrary containers becomes much less
cumbersome as only few functions have to be implemented. All other functions needed by
the stl are provided by the facades using the Barton-Nackman trick (also known as
curiously recurring template pattern.
The following example illustrates how a random access iterator might be written:
\include dune/common/test/iteratorfacadetest.hh
\code
#include<dune/common/iteratorfacades.hh>
...
template<class C, class T>
class TestIterator : public Dune::BidirectionalIteratorFacade<TestIterator<C,T>,T, T&, int>
{
friend class TestIterator<typename Dune::RemoveConst<C>::Type, typename Dune::RemoveConst<T>::Type >;
friend class TestIterator<const typename Dune::RemoveConst<C>::Type, const typename Dune::RemoveConst<T>::Type >;
public:
// Constructors needed by the facade iterators.
TestIterator(): container_(0), position_(0)
{ }
TestIterator(C& cont, int pos)
: container_(&cont), position_(pos)
{}
TestIterator(const TestIterator<typename Dune::RemoveConst<C>::Type, typename Dune::RemoveConst<T>::Type >& other)
: container_(other.container_), position_(other.position_)
{}
TestIterator(const TestIterator<const typename Dune::RemoveConst<C>::Type, const typename Dune::RemoveConst<T>::Type >& other)
: container_(other.container_), position_(other.position_)
{}
// Methods needed by the forward iterator
bool equals(const TestIterator<typename Dune::RemoveConst<C>::Type,typename Dune::RemoveConst<T>::Type>& other) const
{
return position_ == other.position_ && container_ == other.container_;
}
bool equals(const TestIterator<const typename Dune::RemoveConst<C>::Type,const typename Dune::RemoveConst<T>::Type>& other) const
{
return position_ == other.position_ && container_ == other.container_;
}
T& dereference() const
{
return container_->values_[position_];
}
void increment()
{
++position_;
}
// Additional function needed by BidirectionalIterator
void decrement()
{
--position_;
}
// Additional function needed by RandomAccessIterator
T& elementAt(int i)const
{
return container_->operator[](position_+i);
}
void advance(int n)
{
position_=position_+n;
}
std::ptrdiff_t distanceTo(TestIterator<const typename Dune::RemoveConst<C>::Type,const typename Dune::RemoveConst<T>::Type> other) const
{
assert(other.container_==container_);
return other.position_ - position_;
}
std::ptrdiff_t distanceTo(TestIterator<const typename Dune::RemoveConst<C>::Type, typename Dune::RemoveConst<T>::Type> other) const
{
assert(other.container_==container_);
return other.position_ - position_;
}
private:
C *container_;
size_t position_;
};
\endcode
See dune/common/test/iteratorbase.hh for details.
*/
/**
* @file
* @brief This file implements iterator facade classes for writing stl conformant iterators.
*
* With using these facades writing iterators for arbitrary containers becomes much less
* cumbersome as only few functions have to be implemented. All other functions needed by
* the stl are provided by the facades using the Barton-Nackman trick (also known as
* curiously recurring template pattern.
*/
/** @addtogroup IteratorFacades
*
* @{
*/
/**
* @brief Base class for stl conformant forward iterators.
*
*/
template<class T, class V, class R = V&, class D = std::ptrdiff_t>
class ForwardIteratorFacade :
public std::iterator< std::forward_iterator_tag,
typename RemoveConst<V>::Type, // std::iterator needs mutable value type
D,
V*,
R>
{
public:
/**
* @brief The type of derived iterator.
*
* The iterator has to define following
* functions have to be present:
*
* <pre>
*
* // Access the value referred to.
* Reference dereference() const;
*
* // Compare for equality with iterator j
* equals(i);
*
* // position the iterator at the next element.
* void increment()
* </pre>
*
* For an elaborate explanation see the STL Documentation
* @url{http://www.sgi.com/tech/stl/iterator_traits.html}
*/
typedef T DerivedType;
/**
* @brief The type of value accessed through the iterator.
*/
typedef V Value;
/**
* @brief The pointer to the Value.
*/
typedef V* Pointer;
/**
* @brief The type of the difference between two positions.
*/
typedef D DifferenceType;
/**
* @brief The type of the reference to the values accessed.
*/
typedef R Reference;
/** @brief Dereferencing operator. */
Reference operator*() const
{
return static_cast<DerivedType const*>(this)->dereference();
}
Pointer operator->() const
{
return &(static_cast<const DerivedType *>(this)->dereference());
}
/** @brief Preincrement operator. */
DerivedType& operator++()
{
static_cast<DerivedType *>(this)->increment();
return *static_cast<DerivedType *>(this);
}
/** @brief Postincrement operator. */
DerivedType operator++(int)
{
DerivedType tmp(static_cast<DerivedType const&>(*this));
this->operator++();
return tmp;
}
};
/**
* @brief Checks for equality.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator==(const ForwardIteratorFacade<T1,V1,R1,D>& lhs,
const ForwardIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<T1>(lhs).equals(static_cast<T2>(rhs));
else
return static_cast<T2>(rhs).equals(static_cast<T1>(lhs));
}
/**
* @brief Checks for inequality.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator!=(const ForwardIteratorFacade<T1,V1,R1,D>& lhs,
const ForwardIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return !static_cast<const T1&>(lhs).equals(static_cast<const T2&>(rhs));
else
return !static_cast<const T2&>(rhs).equals(static_cast<const T1&>(lhs));
}
/**
* @brief Facade class for stl conformant bidirectional iterators.
*
*/
template<class T, class V, class R = V&, class D = std::ptrdiff_t>
class BidirectionalIteratorFacade :
public std::iterator< std::bidirectional_iterator_tag,
typename RemoveConst<V>::Type, // std::iterator needs mutable value type
D,
V*,
R>
{
public:
/**
* @brief The type of derived iterator.
*
* The iterator has to define following
* functions have to be present:
*
* <pre>
*
* // Access the value referred to.
* Reference dereference() const;
*
* // Compare for equality with j
* equals(i);
*
* // position the iterator at the next element.
* void increment()
*
* // position the iterator at the previous element.
* void decrement()
*
* </pre>
*
* For an elaborate explanation see the STL Documentation
* @url{http://www.sgi.com/tech/stl/iterator_traits.html}
*/
typedef T DerivedType;
/**
* @brief The type of value accessed through the iterator.
*/
typedef V Value;
/**
* @brief The pointer to the Value.
*/
typedef V* Pointer;
/**
* @brief The type of the difference between two positions.
*/
typedef D DifferenceType;
/**
* @brief The type of the reference to the values accessed.
*/
typedef R Reference;
/** @brief Dereferencing operator. */
Reference operator*() const
{
return static_cast<DerivedType const*>(this)->dereference();
}
Pointer operator->() const
{
return &(static_cast<const DerivedType *>(this)->dereference());
}
/** @brief Preincrement operator. */
DerivedType& operator++()
{
static_cast<DerivedType *>(this)->increment();
return *static_cast<DerivedType *>(this);
}
/** @brief Postincrement operator. */
DerivedType operator++(int)
{
DerivedType tmp(static_cast<DerivedType const&>(*this));
this->operator++();
return tmp;
}
/** @brief Preincrement operator. */
DerivedType& operator--()
{
static_cast<DerivedType *>(this)->decrement();
return *static_cast<DerivedType *>(this);
}
/** @brief Postincrement operator. */
DerivedType operator--(int)
{
DerivedType tmp(static_cast<DerivedType const&>(*this));
this->operator--();
return tmp;
}
};
/**
* @brief Checks for equality.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator==(const BidirectionalIteratorFacade<T1,V1,R1,D>& lhs,
const BidirectionalIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<T1>(lhs).equals(static_cast<T2>(rhs));
else
return static_cast<T2>(rhs).equals(static_cast<T1>(lhs));
}
/**
* @brief Checks for inequality.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator!=(const BidirectionalIteratorFacade<T1,V1,R1,D>& lhs,
const BidirectionalIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return !static_cast<const T1&>(lhs).equals(static_cast<const T2&>(rhs));
else
return !static_cast<const T2&>(rhs).equals(static_cast<const T1&>(lhs));
}
/**
* @brief Base class for stl conformant forward iterators.
*
*/
template<class T, class V, class R = V&, class D = std::ptrdiff_t>
class RandomAccessIteratorFacade :
public std::iterator< std::random_access_iterator_tag,
typename RemoveConst<V>::Type, // std::iterator needs mutable value type
D,
V*,
R>
{
public:
/**
* @brief The type of derived iterator.
*
* The iterator has to define following
* functions have to be present:
*
* <pre>
*
* // Access the value referred to.
* Reference dereference() const;
*
* // Compare for equality with j
* equals(i);
*
* // position the iterator at the next element.
* void increment()
*
* // position the iterator at the previous element.
* void decrement()
*
* // advance the iterator by a number of positions-
* void advance(DifferenceType n);
* // calculate the distance to another iterator.
* // One should incorporate an assertion wether
* // the same containers are referenced
* DifferenceType distanceTo(j) const;
* </pre>
*
* For an elaborate explanation see the STL Documentation
* @url{http://www.sgi.com/tech/stl/iterator_traits.html}
*/
typedef T DerivedType;
/**
* @brief The type of value accessed through the iterator.
*/
typedef V Value;
/**
* @brief The pointer to the Value.
*/
typedef V* Pointer;
/**
* @brief The type of the difference between two positions.
*/
typedef D DifferenceType;
/**
* @brief The type of the reference to the values accessed.
*/
typedef R Reference;
/** @brief Dereferencing operator. */
Reference operator*() const
{
return static_cast<DerivedType const*>(this)->dereference();
}
Pointer operator->() const
{
return &(static_cast<const DerivedType *>(this)->dereference());
}
/**
* @brief Get the element n positions from the current one.
* @param n The distance to the element.
* @return The element at that distance.
*/
Reference operator[](DifferenceType n) const
{
return static_cast<const DerivedType *>(this)->elementAt(n);
}
/** @brief Preincrement operator. */
DerivedType& operator++()
{
static_cast<DerivedType *>(this)->increment();
return *static_cast<DerivedType *>(this);
}
/** @brief Postincrement operator. */
DerivedType operator++(int)
{
DerivedType tmp(static_cast<DerivedType const&>(*this));
this->operator++();
return tmp;
}
DerivedType& operator+=(DifferenceType n)
{
static_cast<DerivedType *>(this)->advance(n);
return *static_cast<DerivedType *>(this);
}
DerivedType operator+(DifferenceType n)
{
DerivedType tmp(static_cast<DerivedType const&>(*this));
tmp.advance(n);
return tmp;
}
/** @brief Predecrement operator. */
DerivedType& operator--()
{
static_cast<DerivedType *>(this)->decrement();
return *static_cast<DerivedType *>(this);
}
/** @brief Postdecrement operator. */
DerivedType operator--(int)
{
DerivedType tmp(static_cast<DerivedType const&>(*this));
this->operator--();
return tmp;
}
DerivedType& operator-=(DifferenceType n)
{
static_cast<DerivedType *>(this)->advance(-n);
return *static_cast<DerivedType *>(this);
}
DerivedType operator-(DifferenceType n)
{
DerivedType tmp(static_cast<DerivedType const&>(*this));
tmp.advance(-n);
return tmp;
}
};
/**
* @brief Checks for equality.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator==(const RandomAccessIteratorFacade<T1,V1,R1,D>& lhs,
const RandomAccessIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<T1>(lhs).equals(static_cast<T2>(rhs));
else
return static_cast<T2>(rhs).equals(static_cast<T1>(lhs));
}
/**
* @brief Checks for inequality.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator!=(const RandomAccessIteratorFacade<T1,V1,R1,D>& lhs,
const RandomAccessIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return !static_cast<const T1&>(lhs).equals(static_cast<const T2&>(rhs));
else
return !static_cast<const T2&>(rhs).equals(static_cast<const T1&>(lhs));
}
/**
* @brief Comparison operator.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator<(const RandomAccessIteratorFacade<T1,V1,R1,D>& lhs,
const RandomAccessIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<const T1&>(lhs).distanceTo(static_cast<const T2&>(rhs))>0;
else
return static_cast<const T2&>(rhs).distanceTo(static_cast<const T1&>(lhs))<0;
}
/**
* @brief Comparison operator.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator<=(const RandomAccessIteratorFacade<T1,V1,R1,D>& lhs,
const RandomAccessIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<const T1&>(lhs).distanceTo(static_cast<const T2&>(rhs))>=0;
else
return static_cast<const T2&>(rhs).distanceTo(static_cast<const T1&>(lhs))<=0;
}
/**
* @brief Comparison operator.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator>(const RandomAccessIteratorFacade<T1,V1,R1,D>& lhs,
const RandomAccessIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<const T1&>(lhs).distanceTo(static_cast<const T2&>(rhs))<0;
else
return static_cast<const T2&>(rhs).distanceTo(static_cast<const T1&>(lhs))>0;
}
/**
* @brief Comparison operator.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,bool>::type
operator>=(const RandomAccessIteratorFacade<T1,V1,R1,D>& lhs,
const RandomAccessIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<const T1&>(lhs).distanceTo(static_cast<const T2&>(rhs))<=0;
else
return static_cast<const T2&>(rhs).distanceTo(static_cast<const T1&>(lhs))>=0;
}
/**
* @brief Calculates the difference between two pointers.
*
* This operation is only defined if either D2
* is convertible to D1 or vice versa. If that is
* not the case the compiler will report an error
* as EnableIfInterOperable<D1,D2,bool>::type is
* not defined.
*
*/
template<class T1, class V1, class R1, class D,
class T2, class V2, class R2>
typename EnableIfInterOperable<T1,T2,D>::type
operator-(const RandomAccessIteratorFacade<T1,V1,R1,D>& lhs,
const RandomAccessIteratorFacade<T2,V2,R2,D>& rhs)
{
if(Conversion<T2,T1>::exists)
return static_cast<const T1&>(lhs).distanceTo(static_cast<const T2&>(rhs));
else
return -static_cast<const T2&>(rhs).distanceTo(static_cast<const T1&>(lhs));
}
/** @} */
}
#endif
# $Id$
TESTPROGS = parsetest test-stack arraylisttest smartpointertest
TESTPROGS = parsetest test-stack arraylisttest smartpointertest \
iteratorfacadetest
# which tests to run
TESTS = $(TESTPROGS)
......@@ -17,3 +18,5 @@ test_stack_SOURCES = test-stack.cc
arraylisttest_SOURCES = arraylisttest.cc
smartpointertest_SOURCES = smartpointertest.cc
iteratorfacadetest_SOURCES = iteratorfacadetest.cc
File added
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#include <dune/common/test/iteratorfacadetest.hh>
#include <dune/common/test/iteratortest.hh>
#include <iostream>
#include <algorithm>
template<class T>
class Printer {
typename Dune::RemoveConst<T>::Type res;
public:
Printer() : res(0){}
void operator()(const T& t){
res+=t;
// std::cout << t <<" ";
}
};
void randomize(TestContainer<double>& cont){
srand((unsigned)time(0));
double size=1000;
for(int i=0; i < 100; i++) {
cont[i] = (size*(rand()/(RAND_MAX+1.0)));
}
}
void print(TestContainer<double>& cont){
for(int i=0; i < 100; i++)
std::cout<<cont[i]<<" ";
std::cout<<std::endl;
}
int main(){
// Test the TestIterator;
TestContainer<double> container;
randomize(container);
// print(container);
//std::sort(container.begin(), container.end());
//print(container);
const TestContainer<double> ccontainer(container);
int ret=0;
Printer<const double> print;
ret += testIterator(container, print);
ret += testIterator(ccontainer, print);
exit(ret);
}
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef __DUNE_ITERATORFACADETEST_HH__
#define __DUNE_ITERATORFACADETEST_HH__
#include <dune/common/iteratorfacades.hh>
#include <dune/common/typetraits.hh>
template<class C, class T> class TestIterator;
template<class T>
class TestContainer {
friend class TestIterator<TestContainer<T>,T>;
friend class TestIterator<const TestContainer<T>, const T>;
// friend class TestConstIterator<T>;
public:
typedef TestIterator<TestContainer<T>,T> iterator;
typedef TestIterator<const TestContainer<T>,const T> const_iterator;
TestContainer(){
for(int i=0; i < 100; i++)
values_[i]=i;
}
iterator begin(){
return iterator(*this, 0);
}
const_iterator begin() const {
return const_iterator(*this, 0);
}
iterator end(){
return iterator(*this, 100);
}
const_iterator end() const {
return const_iterator(*this, 100);
}
T& operator[](int i){
return values_[i];
}
const T& operator[](int i) const {
return values_[i];
}
private:
T values_[100];
};
template<class C, class T>
class TestIterator : public Dune::RandomAccessIteratorFacade<TestIterator<C,T>,T, T&, int>
{
friend class TestIterator<typename Dune::RemoveConst<C>::Type, typename Dune::RemoveConst<T>::Type >;
friend class TestIterator<const typename Dune::RemoveConst<C>::Type, const typename Dune::RemoveConst<T>::Type >;
public:
// Constructors needed by the base iterators.
TestIterator() : container_(0), position_(0)
{ }
TestIterator(C& cont, int pos)
: container_(&cont), position_(pos)
{}
TestIterator(const TestIterator<typename Dune::RemoveConst<C>::Type, typename Dune::RemoveConst<T>::Type >& other) : container_(other.container_), position_(other.position_)
{}
TestIterator(const TestIterator<const typename Dune::RemoveConst<C>::Type, const typename Dune::RemoveConst<T>::Type >& other) : container_(other.container_), position_(other.position_)
{}
// Methods needed by the forward iterator
bool equals(const TestIterator<typename Dune::RemoveConst<C>::Type,typename Dune::RemoveConst<T>::Type>& other) const
{
return position_ == other.position_ && container_ == other.container_;
}
bool equals(const TestIterator<const typename Dune::RemoveConst<C>::Type,const typename Dune::RemoveConst<T>::Type>& other) const
{
return position_ == other.position_ && container_ == other.container_;
}
T& dereference() const {
return container_->values_[position_];
}
void increment(){
++position_;
}
// Additional function needed by BidirectionalIterator
void decrement(){
--position_;
}
// Additional function needed by RandomAccessIterator
T& elementAt(int i) const {
return container_->operator[](position_+i);
}
void advance(int n){
position_=position_+n;
}
std::ptrdiff_t distanceTo(TestIterator<const typename Dune::RemoveConst<C>::Type,const typename Dune::RemoveConst<T>::Type> other) const
{
assert(other.container_==container_);
return other.position_ - position_;
}
std::ptrdiff_t distanceTo(TestIterator<typename Dune::RemoveConst<C>::Type, typename Dune::RemoveConst<T>::Type> other) const
{
assert(other.container_==container_);
return other.position_ - position_;
}
private:
C *container_;
size_t position_;
};
#endif
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// $Id$
#ifndef __DUNE_ITERATORTEST_HH__
#define __DUNE_ITERATORTEST_HH__
#include <iostream>
#include <algorithm>
/**
* @brief Tests the capabilities of a forward iterator.
* @param begin Iterator positioned at the stsrt.
* @param end Iterator positioned at the end.
* @param opt Functor for doing whatever one wants.
*/
template<class Iter, class Opt>
int testForwardIterator(Iter begin, Iter end, Opt& opt){
//std::cout<< "forward: ";
for(; begin!=end; ++begin)
opt(*begin);
//std::cout<< " OK "<<std::endl;
return 0;
}
/**
* @brief Tests the capabilities of a bidirectional iterator.
*
* Namely it test wether random positions can be reached from
* each directions.
*
* @param begin Iterator positioned at the stsrt.
* @param end Iterator positioned at the end.
* @param opt Functor for doing whatever one wants.
*/
template<class Iter, class Opt>
int testBidirectionalIterator(Iter begin, Iter end, Opt opt){
testForwardIterator(begin, end, opt);
Iter tbegin=--begin;
Iter tend=--end;
for(; tbegin!=tend; --tend)
opt(*tend);
typename Iter::difference_type size = std::distance(begin, end);
srand((unsigned)time(0));
int no= (size>10) ? 10 : size;
for(int i=0; i < no; i++) {
int index = static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
int backwards=size-index;
tbegin=begin;
tend=end;
for(int j=0; j < index; j++) ++tbegin;
for(int j=0; j < backwards; j++) --tend;
if(tbegin != tend) {
std::cerr<<"Did not reach same index by starting forward from "
<<"begin and backwards from end."<<std::endl;
return 1;
}
}
return 0;
}
template<class Iter, class Opt>
int testRandomAccessIterator(Iter begin, Iter end, Opt opt){
int ret=testBidirectionalIterator(begin, end, opt);
typename Iter::difference_type size = end-begin;
srand((unsigned)time(0));
int no= (size>10) ? 10 : size;
for(int i=0; i < no; i++) {
int index = static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
opt(begin[index]);
}
// Test the less than operator
if(begin != end &&!( begin<end)) {
std::cerr<<"! (begin()<end())"<<std::endl;
ret++;
}
for(int i=0; i < no; i++) {
int index = static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
Iter rand(begin), test(begin), res;
rand+=index;
if((res=begin+index) != rand) {
std::cerr << " i+n should have the result i+=n, where i is the "
<<"iterator and n is the difference type!" <<std::endl;
ret++;
}
for(int i=0; i< index; i++) ++test;
if(test != rand) {
std::cerr << "i+=n should have the same result as applying the"
<< "increment ooperator n times!"<< std::cerr;
ret++;
}
rand=end, test=end;
rand-=index;
if((end-index) != rand) {
std::cerr << " i-n should have the result i-=n, where i is the "
<<"iterator and n is the difference type!" <<std::endl;
ret++;
}
for(int i=0; i< index; i++) --test;
if(test != rand) {
std::cerr << "i+=n should have the same result as applying the"
<< "increment ooperator n times!"<< std::cerr;
ret++;
}
}
for(int i=0; i < no; i++) {
Iter iter1 = begin+static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
Iter iter2 = begin+static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
typename Iter::difference_type diff = iter2 -iter1;
if((iter1+diff)!=iter2) {
std::cerr<< "i+(j-i) = j should hold, where i,j are iterators!"<<std::endl;
ret++;
}
}
return ret;
}
template<class Iter, class Opt, typename iterator_category>
int testIterator(Iter& begin, Iter& end, Opt& opt, iterator_category cat);
template<class Iter, class Opt>
int testIterator(Iter& begin, Iter& end, Opt& opt, std::forward_iterator_tag){
return testForwardIterator(begin, end, opt);
}
template<class Iter, class Opt>
int testIterator(Iter& begin, Iter& end, Opt& opt, std::bidirectional_iterator_tag){
return testBidirectionalIterator(begin, end, opt);
}
template<class Iter, class Opt>
int testIterator(Iter& begin, Iter& end, Opt& opt, std::random_access_iterator_tag){
// std::cout << "Testing iterator ";
int ret = testRandomAccessIterator(begin, end, opt);
//std::cout<<std::endl;
return ret;
}
template<class Iter, class Opt>
int testConstIterator(Iter& begin, Iter& end, Opt& opt){
//std::cout << "Testing constant iterator: ";
int ret=testIterator(begin, end, opt, typename std::iterator_traits<Iter>::iterator_category());
//std::cout<<std::endl;
return ret;
}
template<class Container, class Opt>
int testIterator(Container& c, Opt& opt){
typename Container::iterator begin=c.begin(), end=c.end();
typename Container::const_iterator cbegin(begin);
typename Container::const_iterator cbegin1=begin;
typename Container::const_iterator cend=c.end();
int ret=0;
if(end!=cend || cend!=end) {
std::cerr<<"constant and mutable iterators should be equal!"<<std::endl;
ret=1;
}
return ret + testConstIterator(cbegin, cend, opt) +
testIterator(begin,end,opt);
}
template<class Container, class Opt>
int testIterator(const Container& c, Opt& opt){
typename Container::const_iterator begin=c.begin(), end=c.end();
return testConstIterator(begin,end, opt);
}
template<class Iter, class Opt>
void testAssignment(Iter begin, Iter end, Opt& opt){
//std::cout << "Assignment: ";
for(; begin!=end; begin++)
*begin=typename std::iterator_traits<Iter>::value_type();
//std::cout<<" Done."<< std::endl;
}
template<class Iter, class Opt>
int testIterator(Iter& begin, Iter& end, Opt& opt){
testAssignment(begin, end, opt);
return testConstIterator(begin, end, opt);
}
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment