#include <functional>
#include <type_traits>
#include <utility>
#include <memory>

template <std::size_t... Is>
struct indices {};

template <std::size_t N, std::size_t... Is>
struct build_indices
    : build_indices<N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...>{};

template<int I> struct placeholder{};

namespace std{
    template<int I>
    struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::

namespace detail{
    template<std::size_t... Is, class F, class... Args>
    auto easy_bind(indices<Is...>, F const& f, Args&&... args)
        -> decltype(std::bind(f, std::forward<Args>(args)..., placeholder<1 + Is>{}...))
    {
        return std::bind(f, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
    }
} // detail::

template<class F, class... FArgs, class... Args>
auto easy_bind(F const& f, Args&&... args)
-> decltype(detail::easy_bind(build_indices<sizeof...(FArgs)-sizeof...(Args)>{}, f, std::forward<Args>(args)...))
{
    return detail::easy_bind(build_indices<sizeof...(FArgs)-sizeof...(Args)>{}, f, std::forward<Args>(args)...);
}

/*
*   Event
*
*       Event()
*       ~Event()
*       //  don't destroy an event while executing it
*
*       void clear()
*       void reverse()
*
*       Event::id reg(function, args...)

*       Event::id->enable = true|false;
*       Event::id->unreg();
*       Event::id->replace(function, args...)
*
*       void exec()
*           -   runs all functions on Event
*/

template<typename... Params>
class Event
{
    struct Node;
   
public:
    /*
    *   Types
    */
    typedef Node* id;
   
private:
   
    /*
    *    Structures
    */
    struct Node
    {
        std::function<void(Params...)> dat;
        bool enable;
        bool destroy;
        Node* next;
        Node* prev;
        Event* event;

        inline void unreg()
        {
            destroy = true;
        } //unreg

        template<class T, class... Args>
        void replace(T&& func, Args&&... args)
        {
            dat = easy_bindEx<T, Params..., Args...>(func, args...);
        } //replace
    }; //Node

    /*
    *   Fields
    */
    Node* first;
    Node* last;

    bool reversed;

    void unreg(id eventId)
    {
        if (eventId->next)
        {
            eventId->next->prev = eventId->prev;
        } //if
        else
        {
            last = eventId->prev;
        } //else
        if (eventId->prev)
        {
            eventId->prev->next = eventId->next;
        }
        else
        {
            first = eventId->next;
        } //else
    } //unreg

public:
    /*
    *   Constructors
    */
    Event()
    {
        first = NULL;
        last = NULL;

        reversed = false;
    } //Event

    ~Event()
    {
        Node* next;

        while (first)
        {
            next = first->next;
            delete first;
            first = next;
        } //while

        last = NULL;
    } //~Event

    /*
    *   Data Manipulation Operations
    */
    template<class T, class... Args>
    id reg(T&& func, Args&&... args)
    {
        Node* node = new Node();
        node->dat = easy_bindEx<T, Params..., Args...>(func, args...);
        node->event = this;
        node->enable = true;
        node->destroy = false;

        if (reversed)
        {
            node->prev = NULL;
            node->next = first;

            if (first == NULL)
            {
                last = node;
            } //if
            else
            {
                first->prev = node;
            } //else

            first = node;
        } //if
        else
        {
            node->next = NULL;
            node->prev = last;

            if (last == NULL)
            {
                first = node;
            } //if
            else
            {
                last->next = node;
            } //else

            last = node;
        } //else

        return node;
    } //reg

    /*
    template<class... P, class... Args>
    id regEvent(Event<P...>& event, Args&&... args)
    {
        easy_bind(std::function<void(Event<P...>&, P...)>([](Event<P...>& event, Args&&... args, Params&&... params) { event.exec(forward<Args>(args)..., forward<Params>(params)...);}), event, args...);
        return NULL;
        //return reg(easy_bind(std::function<void(Event<P...>&, P...)>([](Event<P...>& event, Args&&... args, Params&&... params) { event.exec(forward<Args>(args)..., forward<Params>(params)...);}), event, args...));
    } //regEvent
    */

    void clear()
    {
        for (Node* node = first; node; node = node->next)
        {
            node->unreg();
        } //for
    } //clear

    /*
    *   Structure Manipulation Operations
    *
    */
    void reverse()
    {
        if (first)
        {
            Node* node = first;
            Node* next = node->next;

            while (next)
            {
                node->next = node->prev;
                node->prev = next;
                node = next;
                next = node->next;
            } //while

            last->next = last->prev;
            last->prev = next;

            node = last;
            last = first;
            first = node;

            reversed = !reversed;
        } //if
    } //reverse
   
    /*
    *   Execution Operations
    */
    void exec(Params&&... args)
    {
        Node* node = first;
        Node* next;

        while (node)
        {
            next = node->next;

            if (node->destroy)
            {
                unreg(node);
                delete node;
            } //if
            else if (node->enable)
            {
                node->dat(args...);
            } //else if

            node = next;
        } //while
    } //exec
}; //Event

template<>
class Event<void>
{
    struct Node;
   
public:
    /*
    *   Types
    */
    typedef Node* id;
   
private:
   
    /*
    *    Structures
    */
    struct Node
    {
        std::function<void()> dat;
        bool enable;
        bool destroy;
        Node* next;
        Node* prev;
        Event* event;

        inline void unreg()
        {
            destroy = true;
        } //unreg

        template<class T, class... Args>
        void replace(T&& func, Args&&... args)
        {
            dat = easy_bindEx<T, Args...>(func, args...);
        } //replace
    }; //Node

    /*
    *   Fields
    */
    Node* first;
    Node* last;

    bool reversed;

    void unreg(id eventId)
    {
        if (eventId->next)
        {
            eventId->next->prev = eventId->prev;
        } //if
        else
        {
            last = eventId->prev;
        } //else
        if (eventId->prev)
        {
            eventId->prev->next = eventId->next;
        }
        else
        {
            first = eventId->next;
        } //else
    } //unreg

public:
    /*
    *   Constructors
    */
    Event()
    {
        first = NULL;
        last = NULL;

        reversed = false;
    } //Event

    ~Event()
    {
        Node* next;

        while (first)
        {
            next = first->next;
            delete first;
            first = next;
        } //while

        last = NULL;
    } //~Event

    /*
    *   Data Manipulation Operations
    */
    template<class T, class... Args>
    id reg(T&& func, Args&&... args)
    {
        Node* node = new Node();
        node->dat = easy_bindEx<T, Args...>(func, args...);
        node->event = this;
        node->enable = true;
        node->destroy = false;

        if (reversed)
        {
            node->prev = NULL;
            node->next = first;

            if (first == NULL)
            {
                last = node;
            } //if
            else
            {
                first->prev = node;
            } //else

            first = node;
        } //if
        else
        {
            node->next = NULL;
            node->prev = last;

            if (last == NULL)
            {
                first = node;
            } //if
            else
            {
                last->next = node;
            } //else

            last = node;
        } //else

        return node;
    } //reg

    void clear()
    {
        for (Node* node = first; node; node = node->next)
        {
            node->unreg();
        } //for
    } //clear

    /*
    *   Structure Manipulation Operations
    *
    */
    void reverse()
    {
        if (first)
        {
            Node* node = first;
            Node* next = node->next;

            while (next)
            {
                node->next = node->prev;
                node->prev = next;
                node = next;
                next = node->next;
            } //while

            last->next = last->prev;
            last->prev = next;

            node = last;
            last = first;
            first = node;

            reversed = !reversed;
        } //if
    } //reverse
   
    /*
    *   Execution Operations
    */
    void exec()
    {
        Node* node = first;
        Node* next;

        while (node)
        {
            next = node->next;

            if (node->destroy)
            {
                unreg(node);
                delete node;
            } //if
            else if (node->enable)
            {
                node->dat();
            } //else if

            node = next;
        } //while
    } //exec
}; //Event


#include <functional>
#include <vector>

void myF1(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF2(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF3(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF4(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF5(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF6(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF7(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF8(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF9(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}

void myF10(std::vector<int>& v, int, int)
{
    v.push_back(v.back() + 1);
}


#include <ctime>
#include <iostream>
#include <chrono>
#include <random>


int main()
{
    Event<std::vector<int>&, int, int> ev;

    auto ev1P = ev.reg(myF1);
    auto ev2P = ev.reg(myF2);
    auto ev3P = ev.reg(myF3);
    auto ev4P = ev.reg(myF4);
    auto ev5P = ev.reg(myF5);
    auto ev6P = ev.reg(myF6);
    auto ev7P = ev.reg(myF7);
    auto ev8P = ev.reg(myF8);
    auto ev9P = ev.reg(myF9);
    auto ev10P = ev.reg(myF10);

    std::vector<int> v;
    v.reserve(10000000);

    std::vector<int> rNums;
    rNums.reserve(v.capacity());

    std::mt19937 mTwist(std::chrono::high_resolution_clock::now().time_since_epoch().count());
    std::uniform_int_distribution<> uDist;

    for(int i = 0; i < v.capacity(); ++i)
    {
        rNums.push_back(uDist(mTwist));
    }

	auto now = std::chrono::high_resolution_clock::now();

    for(int i = 0; i < 100000; ++i)
    {
        ev.exec(v, rNums[i], rNums[i]);
    }
	
	auto after = std::chrono::high_resolution_clock::now();

    std::cout << "calling 100,000 fires took " <<
		std::chrono::duration_cast<std::chrono::microseconds>(after - now).count() << " milliseconds\n";

    std::cout << "size: " << v.size() << "\n";

    std::cin.get();
}