Algorithm intuition: transform but with possibly more output items than input items?

Viewed 108

I want to escape a string. That is, I want to copy characters, but where the input has " or \, I want to prepend \ on the output. I can write that easily enough, even very generically:

//! Given a range of code units (e.g., bytes in utf-8), transform them to an output range.
//! If a code unit needs escaping (per the given predicate), insert esc before that code unit in the output.
template <typename InRange, typename OutIter, typename NeedsEscapingPred, typename EscCodeUnit>
OutIter transformEscapeCodeUnits(const InRange& in, OutIter out,
     NeedsEscapingPred needsEscaping,
     EscChar esc) {
     for (const auto& codeUnit : in) {
         if (needsEscaping(codeUnit)) {
             *out++ = esc;
         }
         *out++ = codeUnit;
     }
     return out;
}

//! Convenience overload for common case:
template <typename InRange, typename OutIter>
OutIter transformEscapeCodeUnits(const InRange& in, OutIter out, char esc = '\') {
    return transformEscapeCodeUnits(in, out, [](auto c) { return c == '\' || c == '"'; }, esc);
}

However, in the spirit of "no raw loops", I looked at the algorithm and numeric header in search of a generic algorithm to do this. There's replace_if and replace_copy_if and remove_if, but I'm not seeing any std algorithms that take a sequence and output a potentially-longer sequence. This would be basically insert_copy_if, or even more generically, something like transform_items:

//! Like transform, but TransformItem takes an element and an iterator and writes zero or more output elements:
template <typename InRange, typename OutIter, typename TransformItem>
OutIter transform_items(InRange&& inRange, OutIter out, TxFn transformItem) {
    for (auto&& x : std::forward<InRange>(inRange)) {
        out = transformItem(std::forwrad<decltype(x)>(x), out);
    }
    return out;
}

Then the escaping case would call transform_items(in, out, [shouldEsc, esc](auto c, auto out) { if (shouldEsc(c)) { *out++ = esc; } *out++ = c; }).

Am I missing something, or is there nothing quite like that in the standard library?

0 Answers
Related