Boost logo

Boost :

From: koethe_at_[hidden]
Date: 2006-10-16 06:24:58


Hi all,

Quoting Lubomir Bourdev <lbourdev_at_[hidden]>:
>
> 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)


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk