
Hi all, Quoting Lubomir Bourdev <lbourdev@adobe.com>:
So, to summarize, GIL incorporates the pixel transformation function into the iterator itself, whereas Vigra uses accessor objects separately, and goes through their interface explicitly to get/set the values of pixels, correct?
If so, I think accessors are a major limitation.
There are two major reasons why I think Data Accessors are a good idea: 1. incorporating pixel transformation functions into the iterator is much more work than writing an accessor because all the navigation functionality is (unnecessarily) repeated. This is not a big deal for a simple forward iterator, but becomes much more involved for complicated iteration patterns such as 2-dimensional navigation. Handling orthogonal concepts (navigation and data access) in separate classes just makes sense to me. 2. more importantly: the STL data access idiom via *iterator has a major limitation in that the (non-const) iterator::operator* must be able to handle rvalue and lvalue semantics simultaneously: value = *iterator; *iterator = value; However, lvalue and rvalue transformations may require very different implementations. For example, consider an RGB pixel in 565 format packed into a 16 bit unsigned int. Suppose you need an iterator adaptor whose operator* just reads/writes the green channel -- implementing this is very tricky and requires a proxy. Similarly, how do you implement "RGBValue & iterator::operator*()" when the color channels are located in different bands? In contrast, implementing either functionality by means of the separate get and set functions of a data accessor is trivial. This was the main motivation for introducing accessors. If the C++ language allowed for separate implementations of the lvalue and rvalue operator*, I'd reconsider the matter.
Or do you always provide accessors (the default ones doing a noop) and use their set method?
That's what we do in VIGRA, and the noops are nicely optimized away by all compilers we tested.
Second, isn't it cumbersome to provide an accessor separately from the iterator and to have to pass it around everywhere you need it?
That's not a big deal. Most of the time, you use the dafault accessor, which is automatically passed to the algorithms by means of an argument object. Admittedly, "dst_a.set(src_a(src_i),dst_i)" is not as nice as "*dest_i = *src_i" in terms of syntax, but it is much more powerful in terms of semantics (see above).
Third, perhaps the most severe limitation, expressions like "dst_a.set(src_a(src_i),dst_i)" do not follow standard iterator interfaces and cannot be used in any standard generic algorithms.
Yes, and I didn't take the decision lightly. But as I said, I consider this a limitation of the STL and the operator* semantics rather than a limitation of VIGRA.
For example, how can you invoke any STL algorithm on images that have custom accessors?
You can invoke them because operator* is always available in any VIGRA iterator. I.e., VIGRA provides the possibility to write GIL-style iterator adaptors. Regards Ulli Koethe (VIGRA maintainer)