#include <chrono>
#include <cstdlib>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>
/// Waits until a predicate proves true, then calls a function.
class when {
public:
/// Constructor.
/// \tparam Predicate A callable object which returns true when a condition is met.
/// \tparam Callable Another callable object. Will be called when the condition is met.
/// \tparam Args A variadic list of argument types.
/// \param p The predicate.
/// \param c The function to call when the predicate is true.
/// \param args The variadic list of arguments.
template <class Predicate, class Callable, typename... Args>
when(Predicate p, Callable c, Args... args)
{
std::thread thread(when_thread_entry<Predicate, Callable, Args...>(p, c, args...));
thread.detach();
}
private:
/// std::thread entry point for 'when'.
/// \tparam Predicate A callable object which returns true when a condition is met.
/// \tparam Callable Another callable object. Will be called when the condition is met.
/// \tparam Args A variadic list of argument types.
template <class Predicate, class Callable, typename... Args>
struct when_thread_entry {
/// Constructor.
/// \param p The predicate.
/// \param c The function to call when the predicate is true.
/// \param args The variadic list of arguments.
when_thread_entry(Predicate p, Callable c, Args... args) : predicate(p), function(c), tuple(args...)
{
// Do nothing.
}
/// Waits until the predicate becomes true, then calls the function.
void operator()()
{
while (!(predicate()))
std::this_thread::yield();
call_function();
}
private:
/// Stores the indices of a tuple.
template <int... Indices>
struct index {};
/// Generates a sequence of indices for a tuple.
template <int N, int... Indices>
struct gen_seq : gen_seq<N - 1, N - 1, Indices...> {};
/// Generates a sequence of indices for a tuple.
template <int... Indices>
struct gen_seq<0, Indices...> : index<Indices...> {};
/// The predicate.
Predicate predicate;
/// The function.
Callable function;
/// A tuple containing the arguments.
std::tuple<Args...> tuple;
/// Expands the arguments-tuple back into variadic arguments and calls the function.
template <int... Indices>
void call_function(index<Indices...>)
{
function(std::get<Indices>(tuple)...);
}
/// Calls the function with its arguments.
void call_function()
{
call_function(gen_seq<sizeof...(Args)>{});
}
};
};
/// Returns true when a pre-set timeout elapses.
struct timeout_predicate {
/// Constructor.
/// \param duration The duration to wait.
timeout_predicate(std::time_t duration) : end(curtime() + duration)
{
// Do nothing.
}
/// Returns true when the timeout elapses.
bool operator()()
{
return (curtime() >= end);
}
private:
/// The time at which the original duration will have elapsed.
std::time_t end;
/// Gets the current time as a time_t (because std::chrono is designed for editors running on the silver screen).
std::time_t curtime()
{
return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
}
};
/// Calls a function after a timeout elapses.
class after : public when {
public:
/// Constuctor.
/// \tparam Callable A callable object.
/// \tparam Args A variadic list of template argument types for Callable.
/// \param timeout The timeout.
/// \param c The callable object.
/// \param args The variadic arguments.
template <class Callable, typename... Args>
after(std::time_t timeout, Callable c, Args... args) : when(timeout_predicate(timeout), c, args...)
{
// Do nothing.
}
};
/// Prints strings.
struct string_printer {
/// Constructor.
/// \param stream The stream to print on.
string_printer(std::ostream& stream) : m_stream(stream)
{
// Do nothing.
}
/// Prints a string.
/// \param string The string to print.
void operator()(const std::string& string)
{
m_stream << string;
}
private:
/// The stream.
std::ostream& m_stream;
};
/// Flushes streams.
struct stream_flusher {
/// Constructor.
/// \param stream The stream to print on.
stream_flusher(std::ostream& stream) : m_stream(stream)
{
// Do nothing.
}
/// Flushes the stream.
void operator()()
{
m_stream << std::flush;
}
private:
/// The stream.
std::ostream& m_stream;
};
/// Exits the program.
struct program_exiter {
/// Exits the program.
/// \param exit_code The exit status to return.
void operator()(int exit_code = EXIT_SUCCESS)
{
std::exit(exit_code);
}
};
int main()
{
// Create function objects.
string_printer printer(std::cout);
stream_flusher flusher(std::cout);
program_exiter exiter;
// Create 'after' objects. After x seconds each one will call its function with whatever arguments we pass.
after( 9, flusher);
after( 7, printer, "hello, world\n");
after( 3, printer, "Message: ");
after( 5, flusher);
after(10, exiter, EXIT_SUCCESS);
// Wait for all the threads to finish and the program to exit.
// FIXME: Currently, when they go out of scope, the program breaks. If this was fixed, this loop would be
// unnecessary.
while (true)
;
return 0;
}