[cfe-commits] [patch] TransformIterator (motivating use case in Clang)

Douglas Gregor dgregor at apple.com
Tue May 15 11:24:01 PDT 2012


On May 15, 2012, at 9:31 AM, David Blaikie <dblaikie at gmail.com> wrote:

> On Tue, May 15, 2012 at 9:19 AM, Douglas Gregor <dgregor at apple.com> wrote:
>> 
>> On May 6, 2012, at 7:02 PM, David Blaikie wrote:
>> 
>>> This patch adds an iterator much like boost's transform_iterator
>>> (without some extra bells & whistles) for use in some changes I'd like
>>> to make to Clang to correct some misimplemented iterators there.
>>> 
>>> A few gotchas that could be improved/changed depending on opinions:
>>> * I may be playing a little loose with the return type of the functor
>>> (see the example/motivating functor, to_pointer) - the return type
>>> actually must be a reference, though the result_type provides the
>>> underlying value type, not the reference type. If this is violated
>>> Clang will emit a warning, but I could make it more robust with a
>>> compile time assertion in the TransformIterator that the result_type
>>> is actually a reference type, and strip that off to provide the
>>> value_type of the TransformIterator.
>> 
>> It's much more correct for the value and reference types of the iterator type to be, e.g.,
>> 
>>  typedef typename Functor::result_type reference;
>>  typedef typename remove_reference<reference>::type value_type;
>> 
>>> * I realize adding pointer-yness back onto an iterator over references
>>> when the underlying data structure (in the Clang patch you can see
>>> this situation) is a sequence of pointers may be a bit overkill -
>>> though the alternatives are writing different algorithms in the two
>>> cases where I've used TransformIterator, or having the decl_iterator
>>> iterate over pointers (in which case I should probably change the
>>> other iterators I've modified to iterate over pointers for symmetry).
>> 
>> diff --git include/clang/AST/DeclBase.h include/clang/AST/DeclBase.h
>> index 6aef681..0a16ea5 100644
>> --- include/clang/AST/DeclBase.h
>> +++ include/clang/AST/DeclBase.h
>> @@ -1175,17 +1175,18 @@ public:
>>     Decl *Current;
>> 
>>   public:
>> -    typedef Decl*                     value_type;
>> -    typedef Decl*                     reference;
>> -    typedef Decl*                     pointer;
>> +    typedef Decl                     value_type;
>> +    typedef value_type&              reference;
>> +    typedef value_type*              pointer;
>> 
>> Since we tend to traffic in declaration pointers, not references, it's really beneficial to have value_type be Decl*.
> 
> Fair enough - I was hoping to reduce the amount of pointers handed
> around, but I realize in this case especially (where the underlying
> sequence is a sequence of pointers) it's really an awkward fit.

Why is reducing the number of pointers a specific goal? We tend use pointers  (not references) for AST nodes throughout AST, Sema, and a number of other places in the compiler.

> This means killing off the op-> for these iterators though, right? Or
> do you want to keep that as an excusable convenience?

Honestly, I preferred the world back in its conveniently-inconsistent state where operator* returned a pointer and operator-> returned that same pointer, because being able to refer to Iter->getDeclName() rather than (*Iter)->getDeclName() is *really* convenient. 

The inclusion of operator-> in the iterator concepts was a mistake. Nothing in the standard library actually depends on it, no sane algorithms need it, and it's a major PITA to implement for iterator adaptors (as you've noticed <g>).

> In which case my
> change boils down to just changing the pointer typedefs to be Decl**
> in these various iterator types. (& might make my planned work,
> generalizing the filtering iterators, a bit weird - possibly providing
> an op-> to the generic filtering iterators whenever the value type is
> a pointer to match/support this oddity)

Decl** won't always work, though. You'll almost certainly need a proxy.

> Would you prefer the other iterators I changed
> (specific_decl_iterator, filtered_decl_iterator) be switched to
> pointer value_type too?

I did prefer the pointer value_type; perhaps others want to weigh in.

>> This isn't going to work; m_func returns a value_type or reference. Dealing with -> is a real pain, because in the general case you need a proxy class.
>> 
>> +// a convenient utility for a common adaptation
>> +template<typename T>
>> +struct to_pointer {
>> +  typedef T * result_type;
>> +  typedef T argument_type;
>> +  result_type &operator()(T &t) const {
>> +    ptr = &t;
>> +    return ptr;
>> +  }
>> +private:
>> +  mutable T *ptr;
>> +};
>> 
>> 'to_pointer' is a very non-LLVM-y name.
>> 
>> More generally, this particular function object seems like a bad idea. There's nothing wrong with having an iterator type whose reference type is not a true reference, which means that there is no reason to do this little dance with the mutable 'ptr'.
> 
> Yeah, a proxy would be nicer.
> 
> In any case all this transformation stuff isn't needed for this change
> anymore if we're sticking with a pointer value_type.

Right.

	- Doug




More information about the cfe-commits mailing list