[ create a new paste ] login | about

Link: http://codepad.org/Deu3k1CX    [ raw code | fork ]

C++, pasted on May 20:
#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;
}


Create a new paste based on this one


Comments: