#include <iostream>
#include <array>
#include <functional>
#include <algorithm>
 
class formatting_streambuf: public std::streambuf
{
   typedef std::function<std::string(const std::string&)> formatter_t;
public:
   formatting_streambuf(std::streambuf* buf, const formatter_t& formatter) : buffer_{}, buf_(buf), formatter_(formatter)
   {
      setp(buffer_.begin(), buffer_.end() - 1);
   }
protected:
   virtual int overflow(int_type c = traits_type::eof()) override
   {
      *pptr() = traits_type::to_char_type(c);
      format();
      return traits_type::not_eof(c);
   }
 
   virtual int sync() override
   {
      format();
      return 0;
   }
private:
   void format()
   {
      const std::string value(buffer_.begin(), pptr() - buffer_.begin());
      const std::string formatted = formatter_(value);
      buf_->sputn(formatted.c_str(), formatted.size());
      setp(buffer_.begin(), buffer_.end());
   }
 
   std::array<char, 1024> buffer_;
   std::streambuf* buf_;
   formatter_t formatter_;
};
 
class formatting_ostream : public std::ostream
{
   typedef std::function<std::string(const std::string&)> formatter_t;
public:
   formatting_ostream(std::ostream& stream, const formatter_t& formatter) : 
      stream_(stream), old_buf_(stream_.rdbuf()), streambuf_(old_buf_, formatter)
   {
      init(&streambuf_);
   }
private:
   std::ostream& stream_;
   std::streambuf* old_buf_;
   formatting_streambuf streambuf_;
};
 
class source
{
public:
   source(std::ostream& stream) : stream_(stream)
   {
   }
 
   void print()
   {
      stream_ << "HeLlO" << std::endl;
   }
private:
   std::ostream& stream_;
};
 
int main()
{
   auto to_lower = [](const std::string& v) -> std::string
   {
      std::string result;
      std::transform(v.begin(), v.end(), std::back_inserter(result), tolower);
      return result;
   };
   formatting_ostream stream(std::cout, to_lower);
   source s(stream);
   s.print();
   s.print();
 
   source ss(std::cout);
   ss.print();
}