Index: llvm/include/llvm/Support/raw_ostream.h =================================================================== --- llvm/include/llvm/Support/raw_ostream.h +++ llvm/include/llvm/Support/raw_ostream.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -594,6 +595,66 @@ ~buffer_ostream() override { OS << str(); } }; +/// Wrapper to make a raw_ostream look like an output iterator. +/// Designed to match the API of std::ostream_iterator. +/// Enables reusing STL algorithms with raw_ostream. For example: +/// +/// \code{.cpp} +/// +/// std::vector V = { 1, 2, 3 }; +/// std::copy(V.begin(), V.end(), raw_ostream_iterator(outs(), ", ")); +/// +/// \endcode +/// +/// The code above outputs: "1, 2, 3, " +template class raw_ostream_iterator { + raw_ostream &OutStream; + const CharT *Delim; + +public: + using iterator_category = std::output_iterator_tag; + using value_type = void; + using difference_type = void; + using pointer = void; + using reference = void; + using char_type = CharT; + + /// Constructs the iterator with \p Stream as the associated stream and \p + /// Delim as the delimiter. + /// + /// \param Stream The output stream to be accessed by this iterator. + /// + /// \param Delim The null-terminated character string to be inserted into the + /// stream after each output. + raw_ostream_iterator(raw_ostream &Stream, const CharT *Delim) + : OutStream(Stream), Delim(Delim) {} + + /// Constructs the iterator with \p Stream as the associated stream and a null + /// pointer as the delimiter. + /// + /// \param Stream The output stream to be accessed by this iterator. + raw_ostream_iterator(raw_ostream &Stream) + : OutStream(Stream), Delim(nullptr) {} + + /// Inserts \p Value into the associated stream, then inserts the delimiter, + /// if one was specified at construction time. + /// + /// \param value The object to insert. + raw_ostream_iterator &operator=(const T &Value) { + OutStream << Value; + if (Delim != 0) + OutStream << Delim; + return *this; + } + + /// No-op. Provided to satisfy the requirements of LegacyOutputIterator. + ///@{ + raw_ostream_iterator &operator*() { return *this; } + raw_ostream_iterator &operator++() { return *this; } + raw_ostream_iterator &operator++(int) { return *this; } + ///@} +}; + } // end namespace llvm #endif // LLVM_SUPPORT_RAW_OSTREAM_H Index: llvm/unittests/Support/raw_ostream_test.cpp =================================================================== --- llvm/unittests/Support/raw_ostream_test.cpp +++ llvm/unittests/Support/raw_ostream_test.cpp @@ -351,4 +351,33 @@ { raw_fd_ostream("-", EC, sys::fs::OpenFlags::OF_None); } { raw_fd_ostream("-", EC, sys::fs::OpenFlags::OF_None); } } + +template +std::string iterator_str(InputIt First, InputIt Last) { + std::string S; + raw_string_ostream Str(S); + std::copy(First, Last, raw_ostream_iterator(Str)); + Str.flush(); + return S; +} + +template +std::string iterator_str(InputIt First, InputIt Last, const char *Delim) { + std::string S; + raw_string_ostream Str(S); + std::copy(First, Last, raw_ostream_iterator(Str, Delim)); + Str.flush(); + return S; +} + +TEST(raw_ostream_iteratorTest, raw_ostream_iterator_std_copy) { + // Test without a delimiter. + std::vector V1 = {'a', 'b', 'c'}; + EXPECT_EQ("abc", iterator_str(V1.begin(), V1.end())); + + // Test with a delimiter. + std::vector V2 = {1, 2, 3}; + EXPECT_EQ("1, 2, 3, ", iterator_str(V2.begin(), V2.end(), ", ")); +} + }