Range based for loop using an index

The Partridge Family were neither partridges nor a family. Discuss.
albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Range based for loop using an index

Post by albinopapa » November 5th, 2019, 2:56 pm

I don't like the asymmetry in some situations.

Code: Select all

void draw(Graphics& gfx)const noexcept 
{
	for( auto[ i, vertex ] : IndexIteratorAdapter( Constants::player_ship_vertices ) )
	{
		auto const j = ( i + 1 ) % Constants::player_ship_vertices.size();
		auto const p0 = Point( vertex.position );
		auto const p1 = Point( Constants::player_ship_vertices[ j ].position );
		gfx.DrawLine( p0, p1, vertex->color );
	}
}


I guess now I need an iterator that returns pair( current, next % size ). :)
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Range based for loop using an index

Post by chili » November 6th, 2019, 1:19 pm

Looks very nice indeed! I've thought about a circular iterator that can wrap around. Might be nice to help turn any container into a circular buffer with a little bit of twerking. Also, such an iterator with a second count parameter could be nice. Create a range based for loop that cycles through a range in order N times.
Chili

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Range based for loop using an index

Post by albinopapa » November 6th, 2019, 7:38 pm

After I made that comment about the wrap around iterator, I did think about a circular buffer.

I'm not familiar enough with circular buffers. I have heard of them in a multi-threading context. They usually have a read head and a write head I believe. If that's the case, the best I could do is have the read head be 1 element ahead or behind the write head except after wrap around. Either way, they'd be incremented at the same time. In a single threaded context and specifying how many iterations of the loop to do with no read/write heads, it should be easy enough to have the user specify the number of iterations and the number of loops.

Just so it's clear, creating the iterators alone isn't enough to make these things work with a ranged based for loop. They might work standalone with the STL algorithms, but you need a begin()/end() function that returns the same type of iterator in a ranged based for loop, and this is why the "container adapters" are used. They provide a thin interface specifically for the purpose of using the STL containers ( or user defined containers ) in a range based for loop with different iterators than the ones coming from the containers.

The bare minimum for any container you want to use in a ranged for loop is the begin()/end() functions that return the same type.
The bare minimum for any iterator in the same context is:
operator++() -> pre-increment
operator++(int) -> post-increment
operator!=() -> to compare current iterator not equal to end iterator
operator*() -> to dereference the iterator

It's kind of funny. It's considered "best practice" to eliminate raw for loops even the ranged for loop in favor of algorithms. With Ranges this will become easier to accomplish in some tasks I'm sure, but here I am writing iterators and adapters to make ranged for loops more flexible. For shame.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply