5

My question is partially motivated by this question.

Is there a way to compose STL algorithms, or user made algorithms, without an intermediate container? An answer can use a tool from boost, but assume the composed algorithms are user made, or from the STL.

So boost::adaptors::reversed doesn't count since the reversing algorithm is in boost.

Community
  • 1
  • 1
Polymer
  • 1,043
  • 11
  • 13
  • What assumption about the algorithms user made or from the STL precludes the given answer? –  Dec 16 '13 at 01:22
  • @PaulDraper Didn't say that when I wrote the comment :) –  Dec 16 '13 at 01:33
  • "My question is partially motivated by this question." - how is this *partially motivated* and not a duplicate? – Tony Delroy Dec 16 '13 at 01:53
  • I wanted a direct answer for whether there was or wasn't some mapping from pre-existing algorithms to a system which could elegantly compose said algorithms. I'm trying to emphasize that using a library which reimplements algorithms doesn't fit my question. I want to use std::reverse instead of boost::adaptors::reversed. – Polymer Dec 16 '13 at 02:05
  • The answer to the motivating question was "you can't compose the STL, here is an alternative". I was poking for an answer along the lines "This library(or pattern, or whatever) makes composing algorithms without an intermediate vector possible". Boost.Range doesn't come prepackaged with *my* algorithms. – Polymer Dec 16 '13 at 02:14

2 Answers2

8

No.

Let's say f and g are STL algorithms.

Let's say what you want is f(g(x)) (I'm trying to convey the idea here...).

There is no way to get around having a intermediate container, since the result of g(x) must be a container.

If you are going to avoid intermediate containers, then you must use algorithms that can "inspect" or interact with other algorithms, like Boost.Range adaptors (e.g. boost::adaptors::reversed).

For example, say f is "sort" and g is "reverse". Boost's adapters could figure out that the reverse step is a no-op and skip it. STL algorithms couldn't do that, since there's no way for that information to make it through.

Paul Draper
  • 78,542
  • 46
  • 206
  • 285
  • So there is no "adaptor adaptor", that can turn `std::reversed` into a kind of 'boost::adaptors::reversed'? I wouldn't want to have to rewrite a wrapper for every independent algorithm I might have. – Polymer Dec 16 '13 at 01:37
  • @Polymer, I'm not sure about the rewriting a wrapper; I think you would write a `boost::adaptors` compatible algorithm. But the answer is yes, you cannot "covert"(?) `std::reversed` to `boost::adaptors::reversed` – Paul Draper Dec 16 '13 at 01:48
1

Yes for algorithms compatible with input and output iterators.

It requires threads to store execution state, or something coroutine like.

Each step writes to an output iterator that stops execution and runs the next algorithm. Similarly reading from the next input value stops that thread of execution and waits on it being ready.

Many <algorithms> do not fit the above restrictions. But the ones that do should document their requirements. transform qualifies, I cannot think of others off the top of my head.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • This is a really interesting answer. Let me see if I understand. You have a deferred execution iterator, we'll call `defIter`. Its constructor accepts an algorithm (with an interface accepting input iterators). We are writing an algorithm taking `[inA, inB)` and outputting to `[outA, outB)` where `inA, inB` are input iterators and `outA, outB` are output iterators. The "composed" code would look something like `first_algorithm(inA, inB, defIter{second_algorithm, outA, outB})`. `second_algorithm` would read from input iterators which would return execution back to `first_algorithm`. – Polymer Dec 17 '13 at 18:03
  • @Polymer yep, that sounds basically right. If you had some kind of C++ coroutine extension you could even do it in one thread, as the lack of buffering means that we are single threaded anyhow: the threading simply exists to let us *halt* the processing of `second_algorithm` in a spot where it really does not intend to halt (when reading from its input). Note that `defIter` would output to a single output iterator, not 2. – Yakk - Adam Nevraumont Dec 17 '13 at 18:10
  • Your right, It would only output to one iterator! Before I try to implement this iterator, is there anything in boost, or some other library, which provides something like this? – Polymer Dec 17 '13 at 18:41
  • @Polymer not that I know of. And, as noted, I'm not sure if it would be useful other than for transform or filter: doing it the `boost` way of creating streaming algorithms with explicit state is much, much more efficient. – Yakk - Adam Nevraumont Dec 17 '13 at 19:28
  • Well, `adjacent_difference` also qualifies, and it's easy to imagine various other "numeric" solutions which could easily be composed. So although boost's library has an `adjacent_difference` algorithm, I would prefer being able to write algorithms decoupled from boost. Still, you're right, I'm probably sweating too much to preserve infinite ranges. – Polymer Dec 17 '13 at 20:09