//InterleavedArrayIterator.h
//Provides iterator classes for accesing arbitrary arrays of interleaved components
//Primary uses are to allow STL-like generalised algorithms to iterate over any data
//that can be used as OpenGL vertex attribute data, and to allow image processing algorithms to be written
//without relying on a specific format/layout in memory .
//That being the case, it will operate on any sequential block of memory (e.g. plain arrays, std::vector)
//Given a compound class it provides an interface to iterate over some or all of the components as
//if they were a plain array of the component type. The pointer to member operator is also implemented,
//so the dereferenceable component type can itself be a compound type.
//see the tests for examples
#include <iterator>
//Models the stl concept of Random Access Iterator
//dereference is not range checked, for speed
template<typename dereftype>
class InterleavedArrayIterator : public std::iterator<std::random_access_iterator_tag,dereftype>
//note: implicit distance type is platform int, at least on ms compiler
//ms stl and alloc stuff assumes that if you can alloc it, you can index it with an int. Fair enough.
//I use distance_type instead of int, so hopefully the compiler and stl implementation should always sort it
//Still, it's worth checking the platform distance_type before using on 64bit platforms where mem can be > 2GB
{
distance_type m_stridebytes; //full element size in bytes
distance_type m_size; //number of adjacent dereferenceable elements
const void * m_pointer;
distance_type full_pos;
distance_type derefable_pos;
public:
//copy constructor
InterleavedArrayIterator(const InterleavedArrayIterator<dereftype>& r)
{
//copy vals
m_size = r.m_size;
m_stridebytes = r.m_stridebytes;
m_pointer = r.m_pointer;
full_pos = r.full_pos;
derefable_pos=r.derefable_pos;
}
//same params as gl*Pointer
InterleavedArrayIterator(const unsigned int& size, const unsigned int& stride, const void* ptr)
{
m_size =size; //change to use param list for speed
m_stridebytes = stride;
m_pointer = ptr;
full_pos=0;
derefable_pos=0;
}
///assignment operator
InterleavedArrayIterator<dereftype>&
operator=(const InterleavedArrayIterator<dereftype>& r)
{
if(this == &r)
{
return *this;
}
//copy vals
m_size = r.m_size;
m_stridebytes = r.m_stridebytes;
m_pointer = r.m_pointer;
full_pos = r.full_pos;
derefable_pos=r.derefable_pos;
return *this;
}
///preincrement operator; to model ForwardIterator; returns incremented value
const InterleavedArrayIterator<dereftype>&
operator++()
{
derefable_pos++;
if(derefable_pos >= m_size)
{
derefable_pos -=m_size;
full_pos++;
}
return *this;
}
///postincrement operator; to model ForwardIterator, returns the value before increment
const InterleavedArrayIterator<dereftype>
operator++(int a)
{
InterleavedArrayIterator<dereftype>before(*this);
++(*this);
return before;
}
///predecrement operator; to model Bidirectional Iterator; returns incremented value
const InterleavedArrayIterator<dereftype>&
operator--()
{
derefable_pos--;
if(derefable_pos < 0)
{
derefable_pos += m_size;
full_pos--;
}
return *this;
}
///postdecrement operator; to model Bidirectional Iterator; returns the value before increment
const InterleavedArrayIterator<dereftype>
operator--(int a)
{
InterleavedArrayIterator<dereftype>before(*this);
--(*this);
return before;
}
///iterator addition & ; to model RandomAccessIterator
InterleavedArrayIterator<dereftype>&
operator+=(const distance_type& right)
{
distance_type m = right%m_size;
derefable_pos += m;
full_pos += (right-m)/m_size;
if(derefable_pos >= m_size)
{
full_pos++;
derefable_pos -= m_size;
}
return *this;
}
///iterator addition; to model RandomAccessIterator
//make this friend func? makes more sense
const InterleavedArrayIterator<dereftype>
operator+ (const distance_type& right) const
{
InterleavedArrayIterator<dereftype>r(*this);
r+=right;
return r;
}
///iterator subtraction & ; to model RandomAccessIterator
InterleavedArrayIterator<dereftype>&
operator-=(const distance_type& right)
{
distance_type m = right%m_size;
derefable_pos -= m;
full_pos -= (right-m)/m_size;
if(derefable_pos < 0)
{
full_pos--;
derefable_pos += m_size;
}
return *this;
}
///iterator subtraction ; to model RandomAccessIterator
const InterleavedArrayIterator<dereftype>
operator- (const distance_type& right) const
{
InterleavedArrayIterator<dereftype>r(*this);
r-=right;
return r;
}
///difference ; to model RandomAccessIterator
const difference_type operator-(const InterleavedArrayIterator<dereftype>& right) const
{
return ((full_pos - right.full_pos)*m_size) + (derefable_pos - right.derefable_pos);
}
///element access operator ; to model RandomAccessIterator
dereftype& operator[](const distance_type& x) const
{
InterleavedArrayIterator<dereftype>r(*this);
r+=x;
return * r;
}
///operator lessthan; to model LessThan Comparable for RandomAccessIterator
bool operator<(const InterleavedArrayIterator<dereftype>&right)const
{
return ((full_pos*m_size)+derefable_pos)
< ( (right.full_pos*right.m_size)+right.derefable_pos);
}
///dereference ; to model TrivialIterator etc
dereftype& operator*() const
{
unsigned char * ptr = (unsigned char*)m_pointer + (full_pos*m_stridebytes) + (derefable_pos*sizeof(dereftype));
return *(dereftype*)ptr;
}
////dereference ; to model TrivialIterator etc
dereftype* operator->() const
{
unsigned char * ptr = (unsigned char*)m_pointer + (full_pos*m_stridebytes) + (derefable_pos*sizeof(dereftype));
return (dereftype*)ptr;
}
///comparison ; to model Equality Comparable
bool operator==(const InterleavedArrayIterator<dereftype>&right)const
{
if(right.derefable_pos != derefable_pos)
{
return false;
}
if(right.full_pos != full_pos)
{
return false;
}
if(right.m_pointer != m_pointer)
{
return false;
}
if(right.m_stridebytes != m_stridebytes)
{
return false;
}
if(right.m_size != m_size)
{
return false;
}
return true;
}
///comparison ; to model Equality Comparable
bool operator!=(const InterleavedArrayIterator<dereftype>&right)
{
return ! (*this == right);
}
};
|