After the various refactorings the pipes library went through, to define a pipe such as transform or filter we need to implement two classes: the pipe itself, and the class representing a pipeline starting with this pipe. It would be nicer if implementing a pipe would solely require one class. That would make the code clearer, […]
To insert a new entry into an STL set or map, or any of their multi- and unordered- equivalents, we use the insert method: std::map<int, std::string> myMap = // myMap is initialized with stuff… myMap.insert({12, “twelve”}); insert performs the action of inserting the new entry into the container, if that entry wasn’t there already. But insert doesn’t only […]
After the refactoring of the pipes library we saw in the previous post, we’re in a situation where we have three concepts emulated with C++14 by the detection idiom: Range, Pipe and Pipeline. This allowed us to write operator>>= with different combinations of parameters: a Pipe and a Pipeline: add the pipe to the pipeline and return […]
One of the things that one would expect C++ pipes to do, and that they couldn’t do until recently, is creating composite reusable pipes. Indeed, we could chain several pipes into a complete pipeline: input >>= pipes::filter([](int i) { return i % 2 == 0; }) >>= pipes::transform([](int i ){ return i * 2; }) >>= back_inserter(results); […]
Today we have a guest post from Alex Astashyn. Alex is a tech lead for the RefSeq resource at the National Center for Biotechnology Information. Note: The opinions expressed in this article are those of the author. Also, I can’t count myself as a “range expert”, so some of the information pertaining to ranges might […]
Up until now, the pipelines created with the pipes library needed to start with pipes::funnel: myVector >>= pipes::funnel >>= pipes::transform(f) >>= pipes::demux(back_inserter(results1), back_inserter(results2), back_inserter(results3)); pipes::funnel was in the library because I couldn’t see how to implement pipes without it. Several reviewers, including Sy Brand and TH, suggested that the library could be implemented without pipes::funnel. That helped […]
The pipes library has gone through an in-depth refactoring to become what it is now, and one of the components that changed the most is the demultiplexer, a.k.a. demux pipe. I think this refactoring illustrates two principles or phenomena that we observe in software refactoring: Single Responsibility Principle and Refactoring breakthrough. They contributed to make […]
As we saw in the previous post, the Smart output iterators are now called Pipes. Pipes allow to write this kind of code: A >>= funnel >>= transform(f) >>= filter(p) >>= unzip(back_inserter(B), demux(back_inserter(C), filter(q) >>= back_inserter(D), filter(r) >>= back_inserter(E)); Which has the plumbing equivalent of this: However, like we required of smart output iterators, we […]
What DDD calls a refactoring breakthrough is when after making incremental changes to your codebase you suddenly realize that it would make more sense to represent the domain in a different way. This new point of view allows to make a change on a large scale in the codebase, and that new structure seems to […]
In our current stage of development of smart output iterators, we have: some iterators, such as filter, transform, unzip or demux, the possibility to combine them: filter(pred) >>= transform(f) >>= unzip(back_inserter(output1), back_inserter(output2)) their usage as the output iterator of an STL algorithm: std::copy(begin(inputs), end(inputs), transform(f) >>= back_inserter(outputs)); What we’re going to work on today […]