1

I'm trying to transform a sequence of numbers in parallel in C++17 and store the results in a vector. But so far I'm unable to find a way to represent the sequence without explicitly filling an array with it, like so:

void transformRange(size_t N)
{
    // Want to replace nums with a generator (an iterator that is not associated with a container)
    std::vector<size_t> nums(N);
    std::iota(nums.begin(), nums.end(), 0);

    std::vector<size_t> a(N);
    std::transform(std::execution::par, nums.begin(), nums.end(), a.begin(), fun);
}

I want this to be doable in parallel (hence the std::execution::par), and the above transform does work in parallel, but the iota does not and it's 3X the memory bandwidth.

I'm also open to deriving the sequence number from the reference to the value being transformed, but I can't get the syntax right. Something like:

void transformRange2(size_t N)
{
    std::vector<size_t> a(N);
    std::transform(std::execution::par, a.begin(), a.end(), a.begin(), [&](auto & i) {fun(&i - a.begin()); });
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
All The Rage
  • 743
  • 5
  • 24
  • You can use std::distance to create the index of an iterator: https://stackoverflow.com/questions/2152986/what-is-the-most-effective-way-to-get-the-index-of-an-iterator-of-an-stdvector – José Manuel Ramos Nov 10 '18 at 21:29

2 Answers2

1

Ranges not backed by a container (or the nightmare called std::vector<bool>) are not part of C++17.

But don't despair, Boost provides the counting_iterator, just what you need for a lazy range.

It even provides it conveniently packaged as a range using counting_range.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Why is `std::vector` a nightmare and why is it not part of C++17? – V0ldek Nov 10 '18 at 21:48
  • 2
    @V0ldek Well, the ranges TS might make it into C++20, as might concepts. (Huh, I'm not quite sure a counting-range is actually part of that. Oh well.) And `std::vector` is a nightmare because it is not really a `std::vector`, as it has a very different interface, nor is it really a contyiner. There are good posts on SO going further into it than a comment should try. – Deduplicator Nov 10 '18 at 21:51
0
template<class F, class R=std::result_of_t<F&(std::size_t)>>
std::vector<R> rangeFromIndex(F&& f, std::size_t N)
{
  std::vector<R> a(N);
  std::for_each(std::execution::par,
    a.begin(), a.end(),
    [&](auto & i) {i = fun(std::size_t(std::addressof(i) - a.data())); }
  );
}

that should do it.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524