1D iterators really don't need to store much more than the address they represent. They are very light weight and only have one value to compare for equality, the pointers. 2D iterators are proving a bit more complex and are quite a bit heavier.
I decided to use indexes instead of just a simple pointer. The reasoning behind this is someone or myself might have a vector of vectors where each element in the row vector is a row of data. I wouldn't be able to use pointer arithmetic. Another reason I chose indexes is to be able to return those indices to the user through the lambdas provided to the algorithms in case they are needed.
Well, when iterating over the entire container, the width constraints and stride of the container are the same, but in iterating over a region of the container, the width constraints and stride of the container are different. So, where to handle all the complexity? How to handle the differences?
As stated, the width constraints and container stride might be different, so my solution is to put the width and height of the region into the iterator. It also needs to know it's current position, so an X and Y value. It also needs a way to access the value at the current position when the user dereferences the iterator and so either store the stride and a pointer to the underlying array or just a pointer to the container and force the container to handle access since it knows it's own stride. I opted for the latter.
So the member list is:
container_pointer = 4/8 bytes depending on x86/x64
int x,y = (4+4) 8 bytes
int width, height = (4+4) 8 bytes
totaling: 20-24 bytes
Next issue is since there could be a difference in width and stride, and from my usage most of the time there is, the begin() function is always going to return an iterator with the full stride for the width, so even adding an offset to the iterator, it's not going to wrap the X position until it reaches the full stride of the container and not the region. Unless I plan on iterating over the entire container every time, I need to manually construct the iterators, which looks ugly.
Code: Select all
const auto beg_it = dim2d::const_index_iterator<dim2d::surface<Color>>( 10, 10, 50, 50, surface );
Code: Select all
const auto end_it = beg_it + dim2d::offset{ 0, 40 }; // stops when indices reach x = 10, y = 50
Code: Select all
const auto end_it = dim2d::const_index_iterator<dim2d::surface<Color>>( 10, 50, 50, 50, surface );
All this just to avoid having to type nested for loops every time I want to iterate over a 2D array.
My brain has been in a fog lately, so that may be what's been slowing me down or making this more complicated than it needs to be.
I could have just made an index class that takes those four inputs ( left, top, right, bottom ) and implement all the same behavior with the exception that dereferencing would just return the indices. The algorithms would be useless, but I'd be able to use ranged based for loops to iterate over the entire array or just a single for loop for regions and just use the current indexed position. Perhaps I'll still do that on top of the iterator and surface_wrapper setup for different purposes.
I haven't looked into the Ranges stuff that's suppose to come out in C++20, so I don't know how they will work.