I don't know if anyone has had any trouble with creating an iterator object to go hand-in-hand with data structures (stacks, queues, etc.), and I thought I would present an implementation that I'm currently using and updating in my custom library I'm working on.
#ifndef _ITERATOR_OBJ_H_
#define _ITERATOR_OBJ_H_
// Iterator Object refresher
#include <stdio.h>
#include <stdlib.h>
typedefunsignedchar uint8;
typedefunsignedint uint32;
// Borrowing this from libnds
#define BIT(x) (1 << x)
#define NULL_MEMORY BIT(1)
#define PUSH_ERROR BIT(2)
#define POP_ERROR BIT(3)
#define INDEX_OB BIT(4)
template<typename T>
void swapargs(T& x, T& y)
{
T z = x;
x = y;
y = z;
}
// Thought I would need this, apparently not.
uint32 get_size(uint32* a)
{
uint32 len = 0;
while(*a++)
len++;
return len;
}
void throwException(uint8 flags)
{
if(flags & NULL_MEMORY)
printf("[ERROR] Memory could not be allocated to the heap. Aborting...\n");
if(flags & PUSH_ERROR)
printf("[ERROR] Value could not be pushed properly.\n");
if(flags & POP_ERROR)
printf("[ERROR] Value could not be popped properly.\n");
if(flags & INDEX_OB)
printf("[ERROR] Index goes out of bounds of data array.\n");
}
// Put in a recovery iiterator object to hold a backup of the data,
// just in case an allocation doesn't work properly?
class iiterator
{
private:
uint32 *data; // Holds the addresses of variable locations.
uint32 ssize, alloc_size, pos; // Current size and capacity size. pos is the position 'cursor' of where to write in a new value. Might not need it.
// void refresh() // Refreshes size of the array.
public:
iiterator()
{
ssize = 0;
alloc_size = 10;
data = (uint32*)malloc(alloc_size * sizeof(uint32));
if(!data)
{
throwException(NULL_MEMORY);
}
else
{
for(int i = 0; i < alloc_size; i++)
data[i] = 0;
}
}
iiterator(uint32 len)
{
if(len < 0)
len *= -1;
alloc_size = len;
ssize = 0;
data = (uint32*)malloc(alloc_size * sizeof(uint32));
if(!data)
{
throwException(NULL_MEMORY);
}
else
{
for(int i = 0; i < alloc_size; i++)
data[i] = 0;
}
}
~iiterator() { free((void*)data); }
void resize(uint32 len)
{
if(len >= alloc_size)
{
alloc_size = len * 2;
void* newdata = realloc((void*)data, alloc_size * sizeof(uint32));
if(!newdata)
{
throwException(NULL_MEMORY);
return;
}
else
data = (uint32*)newdata;
}
else
ssize = len;
}
bool is_empty()
{
uint32 total = 0;
for(int i = 0; i < alloc_size; i++)
total += data[i];
return total == 0;
}
void push(uint32 val)
{
if(ssize < alloc_size)
{
data[ssize] = val;
ssize++;
}
else
{
resize(ssize + 1);
push(val);
}
}
// Stack push implementation
void pushs(uint32 val)
{
ssize++; // Empty cell is now part of the main array.
if(ssize >= alloc_size)
resize(ssize + 1);
for(int i = ssize; i > 0; i--)
swapargs(data[i], data[i - 1]);
data[0] = val;
}
void pop(uint32 index)
{
if(!is_empty())
{
if(index < 0 || index >= ssize)
{
throwException(INDEX_OB);
return;
}
else
{
data[index] = 0;
ssize--;
}
}
}
void pop() { pop(ssize - 1); }
void pops()
{
for(int i = 0; i < ssize; i++)
swapargs(data[i], data[i+1]);
pop();
}
intoperator[](uint32 index)
{
if(index < 0 || index >= ssize)
{
throwException(INDEX_OB);
return -1;
}
elsereturn data[index];
}
uint32 size() { return ssize; }
uint32 length() { return size(); }
uint32 capacity() { return alloc_size; }
};
#endif
So far, from what I've tested, most of these methods work fine. Any errors/vulnerablity notices would be great, and suggestions to make it faster or easier to use would be welcome as well.
[NOTE] I'm currently using Visual Studio 2010, using nothing but a blank project file, no MFC or ATL options included, if it helps anyone having trouble with compiling.
TBH - I wouldn't associate iterators with push/pop style operations.
In most people's minds including mine - Iterators are associated with stepping through containers ( iterators exhibit pointer type semantics).
So iterators go forward/backwards through a container and you get the object at the iterator position by dereferencing the iterator like a pointer.
The contatiner may have operations such as copy/remove/find which
may take an iterator to that type of container or return an iterator to an object
in the container - but basicaly the iterators are fairly passive things.
This actually started out when I first started to program with data structures. After I figured out how to program them, I tried to think of a way to access them via the [] operator.
A year's passed since then. Now that I know how to resize arrays, this code looks silly in retrospect.
To clarify, an iterator is an object that steps through a structure, returning data at certain points, correct? I think I need some review...