Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it Possible to Have a Transforming Iterator in C++?

Assume I have a C++ iterator that not only traverses a data structure but also applies a transformation to the elements when it is dereferenced.

As a real-world example, here's an iterator that goes over the pixels in a bitmap, transforming the bitmap-specific pixel format into a convenient structure:

class ConstPixelIterator {

  public: struct Pixel {
    float Red;
    float Green;
    float Blue;
    float Alpha;
  };

  public: ConstPixelIterator(const Bitmap &bitmap);

  // ...standard iterator functionality...

  public: Pixel operator *() {
    // Read from memory and convert pixel format-specific bytes into Pixel structure
  }

};

Now if I wanted to implement a non-const iterator (i.e. let the user modify pixels), what is the best way to go about this?

Some ideas I considered:

  • I could put accessor methods in the Pixel structure instead of plain fields and give it a reference to its owner to phone home. This would however mean that if the user changed R,G,B and A, I would convert the pixel into the bitmap's pixel format 4 times and write to memory 4 times.

  • I could return a Pixel reference from the iterator and provide it with an Update() method that needs to be called if the pixel was changed. This would be non-intuitive and risk users forgetting to call Update.

  • I could always return the Pixel by value and provide a special assignment operator. Does break the standard iterator pattern - assigning to an iterator without dereferencing should move the iterator, not update the element it is pointing at

like image 287
Cygon Avatar asked Oct 19 '22 18:10

Cygon


1 Answers

We've got an existing example in std::vector<bool>::iterator - that has to pull a few tricks to write to a single bit.

One solution is to return a ProxyPixel. It keeps a reference to the original pixel. You stated that updating R,G,B,A may cause 4 writes. That's true, and understandable. After the first write of just R, the underlying image should have an updated R value after all.

Or are you happy to accept an eventual update? In that case, you may delay the write-back to ProxyPixel::~ProxyPixel. Yes, the underlying image will then be temporarily out of sync as the proxy pixel is being changed, but it would be more efficient. A reasonable tradeoff.

like image 96
MSalters Avatar answered Oct 22 '22 21:10

MSalters