Is it possible to have a transformer iterator in C ++?

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

As an example, in the real world, an iterator is used here, which moves pixels in a bitmap image, converting the image format in the format of a bitmap image 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-constant iterator (i.e. let the user change the pixels), what is the best way to do this?

Some ideas I reviewed:

  • I could use the access methods in the Pixel structure instead of simple fields and give a link to my owner to call home. This, however, would mean that if the user changed R, G, B, and A, I would convert the pixel four times to a raster pixel format and write to memory 4 times.

  • I could return the pixel reference from the iterator and provide it with the Update() method, which needs to be called if the pixel has been changed. This would be unintuitive, and users at the risk of forgetting to call Update .

  • I can always return a Pixel value by value and provide a special assignment operator. Breaks the standard iterator pattern - assigning iterator without dereferencing, should move the iterator, and not update the element it points to

+5
source share
3 answers

We have an existing example in std::vector<bool>::iterator , which should pull out several tricks for writing in one bit.

One solution is to return a ProxyPixel . It contains a link to the source pixel. You stated that updating R, G, B, A can cause 4 entries. This is true and understandable. After the first record is only R, the base image should have an updated R value in the end.

Or are you happy to accept the final update? In this case, you can postpone the return to ProxyPixel::~ProxyPixel . Yes, the main image will be temporarily out of sync with the resizing of the proxy pixel, but it will be more efficient. Reasonable compromise.

+3
source

I could use the access methods in the Pixel structure instead of simple fields and give a link to my owner to call home. This, however, would mean that if the user changed R, G, B, and A, I would convert the pixel 4 times to a raster pixel format and write to memory 4 times.

This pushes the demeter law (the pixel does not have to modify the bitmap to set its own value); You must not do this.

I could return the pixel reference from the iterator and provide it with the Update () method, which needs to be called if the pixel has been changed. This would be unintuitive, and users at the risk of forgetting to call Update.

This is a bit of a bad interface, as it will be difficult to use correctly without forgetting anything. This also breaks the demeter strip (you should not update the bitmap through the pixel).

I could always return a Pixel value by value and provide a special assignment operator. Breaks the standard iterator pattern - assigning iterator without dereferencing should move the iterator, and not update the element pointing to

Do not do this; this violates the principle of least surprise.

Consider instead to make the pixel independent of the bitmap (i.e., the pixel does not know what the bitmap is).

You should be able to set (real) values ​​to a pixel easily (using accessories for fields or Update(R, G, B, A) or similar) and have a bitmap, know what a pixel is and how to update yourself from pixels, with one (or more):

 void Bitmap::Update(int x, int y, const Pixel& p); void Bitmap::Fill(const Pixel& p); void Bitmap::SetRange(SomeRangeObject r, const Pixel& p); 

Thus, the update operation for pixels will require the following steps:

  • get pixels from a bitmap
  • update / convert pixels as needed
  • refresh pixel bitmap

This does not apply to those who will know the positions of the pixels (they probably should not be part of the pixel itself), but this is the beginning.

In this implementation, your interdependencies remain low (the functionality for updating the pixels of the bitmap remains in the bitmap, not the pixels), and the iterative model is trivial (the same as standard iterators).

0
source

Pixel structure elements can be implemented as properties.

This will allow you to write things like

 iter->r = 0; 

This will not allow you to send the pixel structure to functions that expect it to be "stressful"

Implementing a property in C ++ is simple, see for example here

Writing to memory several times should not be a problem, since it will be cache-local

0
source

Source: https://habr.com/ru/post/1212423/


All Articles