I was just playing around with some code and had the idea about writing some kind of ostream
manipulator to delay the output of characters in a typewriter like style.
The focus was mostly on how to use it and was inspired by std::fixed
or std::setprecision
.
Overall it works pretty well. I just want to make sure that I didn't miss anything that may backfire any time.
The code is just for playing around and doesn't have a real use case (yet).
#include <iostream>
#include <string>
#include <utility>
#include <thread>
namespace manip
{
struct delayed : std::ostream, std::streambuf
{
std::ostream* m_postream;
std::chrono::milliseconds m_ms;
delayed(std::chrono::milliseconds ms)
: std::ostream(this)
, m_postream(nullptr)
, m_ms(ms)
{}
delayed(std::ostream& o, std::chrono::milliseconds ms)
: std::ostream(this)
, m_postream(&o)
, m_ms(ms)
{}
int overflow(int c) override
{
std::this_thread::sleep_for(m_ms);
if (m_postream)
{
(*m_postream) << (char)c;
}
return 0;
}
friend delayed& operator<<(std::ostream&, delayed&&);
};
delayed& operator<<(std::ostream& o, delayed&& d)
{
delayed* delayed_ostream = dynamic_cast<delayed*>(&o);
if (delayed_ostream)
{
d.m_postream = delayed_ostream->m_postream;
}
else
{
d.m_postream = &o;
}
return d;
}
}
int main()
{
using namespace std::literals;
using namespace manip;
std::cout
<< delayed(200ms) << "Wake up Neo." << delayed(1100ms) << std::endl
<< delayed(200ms) << "The Matrix has you." << delayed(3100ms) << std::endl
<< delayed(200ms) << "Follow the white Rabbit." << delayed(1100ms) << std::endl;
}
As it seems my intention on what delayed
should do and how it works weren't very clear. So here is what the example will do as instructions:
//delayed(200ms) is passed to the stream: delay all following characters by 200ms
<wait 200ms><print 'W'>
<wait 200ms><print 'a'>
<wait 200ms><print 'k'>
<wait 200ms><print 'e'>
<wait 200ms><print ' '>
<wait 200ms><print 'u'>
<wait 200ms><print 'p'>
<wait 200ms><print ' '>
<wait 200ms><print 'N'>
<wait 200ms><print 'e'>
<wait 200ms><print 'o'>
<wait 200ms><print '.'>
//delayed(1100ms) is passed to the stream: delay all following characters by 1100ms
<wait 1100ms><print endl>
//delayed(200ms) is passed to the stream: delay all following characters by 200ms
<wait 200ms><print 'T'>
<wait 200ms><print 'h'>
<wait 200ms><print 'e'>
<wait 200ms><print ' '>
<wait 200ms><print 'M'>
<wait 200ms><print 'a'>
<wait 200ms><print 't'>
<wait 200ms><print 'r'>
<wait 200ms><print 'i'>
<wait 200ms><print 'x'>
<wait 200ms><print ' '>
<wait 200ms><print 'h'>
<wait 200ms><print 'a'>
<wait 200ms><print 's'>
<wait 200ms><print ' '>
<wait 200ms><print 'y'>
<wait 200ms><print 'o'>
<wait 200ms><print 'u'>
<wait 200ms><print '.'>
//delayed(3100ms) is passed to the stream: delay all following characters by 3100ms
<wait 3100ms><print endl>
//delayed(200ms) is passed to the stream: delay all following characters by 200ms
<wait 200ms><print 'F'>
<wait 200ms><print 'o'>
<wait 200ms><print 'l'>
<wait 200ms><print 'l'>
<wait 200ms><print 'o'>
<wait 200ms><print 'w'>
<wait 200ms><print ' '>
<wait 200ms><print 't'>
<wait 200ms><print 'h'>
<wait 200ms><print 'e'>
<wait 200ms><print ' '>
<wait 200ms><print 'w'>
<wait 200ms><print 'h'>
<wait 200ms><print 'i'>
<wait 200ms><print 't'>
<wait 200ms><print 'e'>
<wait 200ms><print ' '>
<wait 200ms><print 'R'>
<wait 200ms><print 'a'>
<wait 200ms><print 'b'>
<wait 200ms><print 'b'>
<wait 200ms><print 'i'>
<wait 200ms><print 't'>
<wait 200ms><print '.'>
//delayed(1100ms) is passed to the stream: delay all following characters by 1100ms
<wait 1100ms><print endl>