[llvm] r203354 - Adding range-based STL-like helper APIs. llvm::distance() is the range version of std::distance. llvm::copy is the range version of std::copy.

Aaron Ballman aaron at aaronballman.com
Sun Mar 9 05:51:36 PDT 2014


On Sat, Mar 8, 2014 at 8:23 PM, Chandler Carruth <chandlerc at google.com> wrote:
> On Sat, Mar 8, 2014 at 12:11 PM, Aaron Ballman <aaron at aaronballman.com>
> wrote:
>>
>> Author: aaronballman
>> Date: Sat Mar  8 14:11:24 2014
>> New Revision: 203354
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=203354&view=rev
>> Log:
>> Adding range-based STL-like helper APIs. llvm::distance() is the range
>> version of std::distance. llvm::copy is the range version of std::copy.
>>
>> Modified:
>>     llvm/trunk/include/llvm/ADT/iterator_range.h
>
>
> I don't think these belong in this header at all.

I was going to put them into STLExtras.h, except that didn't seem
right given that ranges aren't in the STL yet. Do you have a better
suggestion as to where they should live? RangeExtras.h perhaps?

I'm only adding things which come up several places. I don't mind
using iterators if it's one- or two-off instances, but when it's 4-5+,
it seems beneficial to have range versions of some iterator APIs.

>
>>
>> Modified: llvm/trunk/include/llvm/ADT/iterator_range.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/iterator_range.h?rev=203354&r1=203353&r2=203354&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/ADT/iterator_range.h (original)
>> +++ llvm/trunk/include/llvm/ADT/iterator_range.h Sat Mar  8 14:11:24 2014
>> @@ -23,6 +23,11 @@
>>
>>  namespace llvm {
>>
>> +template <typename Range>
>> +struct range_traits {
>> +  typedef typename Range::difference_type difference_type;
>> +};
>> +
>
>
> There is no documentation for this. We have no pattern or reference from the
> standard about how it should work. I don't even know where you're really
> going here or why we need this at all. It feels like just boilerplate to me.

I was modelling off the MSVC iterator implementation for how
std::distance was implemented. But I'm fine yanking the traits.

>
>>  /// \brief A range adaptor for a pair of iterators.
>>  ///
>>  /// This just wraps two iterators into a range-compatible interface.
>> Nothing
>> @@ -32,6 +37,10 @@ class iterator_range {
>>    IteratorT begin_iterator, end_iterator;
>>
>>  public:
>> +  // FIXME: We should be using iterator_traits to determine the
>> +  // difference_type, but most of our iterators do not expose anything
>> like it.
>> +  typedef int difference_type;
>
>
> I don't think we should expose this until those iterators are fixed and we
> can use something sensible. "int" doesn't really seem like a sensible choice
> for most of our iterators.

Probably should be ptrdiff_t, in retrospect. But if the boilerplate is
going away, no need to expose this.

>
>>
>> +
>>    iterator_range() {}
>>    iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
>>        : begin_iterator(std::move(begin_iterator)),
>> @@ -41,6 +50,19 @@ public:
>>    IteratorT end() const { return end_iterator; }
>>  };
>>
>> +/// \brief Determine the distance between the end() and begin() iterators
>> of
>> +/// a range. Analogous to std::distance().
>> +template <class Range>
>> +typename range_traits<Range>::difference_type distance(Range R) {
>> +  return std::distance(R.begin(), R.end());
>> +}
>
>
> Is this really worth providing at this point?

Yes, it gets used about a half-dozen times at least, and it looks
considerably easier on the eye using the range API.

> If it is, why not define it with the return type computed from
> std::distance's return type? I don't see a need for traits yet.

Something along the lines of:

template <typename RangeT>
auto distance(RangeT R) {
  return std::distance(R.begin(), R.end());
}

?

>
> It doesn't belong in this header file either way.
>
>> +
>> +/// \brief Copies members of a range into the output iterator provided.
>> +/// Analogous to std::copy.
>> +template <class Range, class OutputIterator>
>> +OutputIterator copy(Range In, OutputIterator Result) {
>> +  return std::copy(In.begin(), In.end(), Result);
>> +}
>
>
> Same problems. This provides no actual advantage over just using the
> iterator form. I would just use the iterator form. If we do provide it, it
> shouldn't be in this header.

The iterator form is more boilerplate typing without benefit:

std::copy(Records->field_begin(), Records->field_end(),
std::back_inserter(Fields));

vs

llvm::copy(Records->fields(), std::back_inserter(Fields));

So I'd disagree that it provides no actual benefit, but would agree
that it's not drastic benefit.

> Also, as a meta style point: please prefer "typename" to "class" everywhere.
> Please prefer "FooT" to "Foo" for parameters everywhere.

Can do!

~Aaron



More information about the llvm-commits mailing list