<repo_name>Alesh/Squall-CXX<file_sep>/demo/hello_cb.cxx
#include <iostream>
#include <squall/EventLoop.hxx>

using squall::Event;
using squall::EventLoop;

int main(int argc, char const* argv[]) {

    int cnt = 0;
    EventLoop event_loop;

    event_loop.setup_timer([](int revents) {
        if (revents == Event::Timeout)
            std::cout << "Hello, Alesh! (" << revents << ")" << std::endl;
        return true;
    }, 1.0);

    event_loop.setup_timer([&cnt](int revents) {
        if (revents == Event::Timeout) {
            std::cout << "Hello, World! (" << revents << ")" << std::endl;
            cnt++;
        }
        return (cnt < 3);
    }, 2.5);

    event_loop.setup_signal([&event_loop](int revents) {
        if (revents == Event::Signal) {
            std::cout << "\nGot SIGINT. Bye! (" << revents << ")" << std::endl;
            event_loop.stop();            
        }
        return false;
    }, SIGINT);

    event_loop.start();
    return 0;
}<file_sep>/include/squall/base/EventLoop.hxx
#ifndef SQUALL__BASE__EVENT_LOOP__HXX
#define SQUALL__BASE__EVENT_LOOP__HXX
#include <ev.h>
#include <memory>
#include <functional>
#include <unordered_map>

namespace squall {

/**
 * Event codes
 */
enum Event : int {
    Read = EV_READ,
    Write = EV_WRITE,
    Timeout = EV_TIMER,
    Signal = EV_SIGNAL,
    Error = EV_ERROR,
    Cleanup = EV_CLEANUP,
};

namespace base {


/**
 * Base template class that implement an event loop.
 */
template <typename Context>
class EventLoop {
    using OnEvent = std::function<void(Context context, int revents) noexcept>;

    OnEvent _on_event;
    bool _running = false;
    struct ev_loop* _p_loop;
    std::unordered_map<Context, std::unique_ptr<ev_io>> _io_watchers;
    std::unordered_map<Context, std::unique_ptr<ev_timer>> _timer_watchers;
    std::unordered_map<Context, std::unique_ptr<ev_signal>> _signal_watchers;

    template <typename Watcher>
    static void callback(struct ev_loop* p_loop, Watcher* p_watcher, int revents) {
        auto p_event_loop = static_cast<EventLoop<Context>*>(ev_userdata(p_loop));
        auto p_context = static_cast<Context*>(p_watcher->data);
        p_event_loop->_on_event(*p_context, revents);
    }

  public:
    /* Constructor 
     * `on_event` is the callback that will be called to transmit occurred events. */
    EventLoop(const OnEvent& on_event) : _on_event(on_event) {
        _p_loop = ev_loop_new(0);
        ev_set_userdata(_p_loop, static_cast<void*>(this));
    };

    /* Destructor */
    virtual ~EventLoop() {
        ev_loop_destroy(_p_loop);
    }

    /* Return true if an event dispatching is active. */
    bool is_running() {
        return _running;
    }

    /* Starts event dispatching.*/
    void start() {
        _running = true;
        while (_running)
            ev_run(_p_loop, EVRUN_ONCE);
        while (_io_watchers.size())
            cancel_io(_io_watchers.begin()->first);
        while (_timer_watchers.size())
            cancel_timer(_timer_watchers.begin()->first);
        while (_signal_watchers.size())
            cancel_signal(_signal_watchers.begin()->first);
    }

    /* Stops event dispatching.*/
    void stop() {
        if (_running) {
            _running = false;
            ev_break(_p_loop, EVBREAK_ONE);
        }
    }

    /* Setup to call `on_event` for a given `context` 
     * when the I/O device with a given `fd` would be to read and/or write `mode`. */
    bool setup_io(Context context, int fd, int mode) {
        auto p_watcher = new ev_io();
        ev_io_init(p_watcher, EventLoop::template callback<ev_io>, fd, mode);
        ev_io_start(_p_loop, p_watcher);
        if (ev_is_active(p_watcher)) {
            auto result = _io_watchers.insert(std::make_pair(context, std::unique_ptr<ev_io>(p_watcher)));
            if (!result.second) {
                cancel_io(result.first->first);
                result = _io_watchers.insert(std::make_pair(context, std::unique_ptr<ev_io>(p_watcher)));
            }
            if (result.second) {
                result.first->second.get()->data = (void*)(&(result.first->first));
                return true;
            }
        }
        return false;
    }

    /* Updates I/O mode for event watchig extablished with method `setup_io` for a given `context`. */
    bool update_io(Context context, int mode) {
        auto found = _io_watchers.find(context);
        if (found != _io_watchers.end()) {
            auto p_watcher = found->second.get();
            if (_running && ev_is_active(p_watcher))
                ev_io_stop(_p_loop, p_watcher);
            ev_io_set(p_watcher, p_watcher->fd, mode);
            ev_io_start(_p_loop, p_watcher);
            if (ev_is_active(p_watcher))
                return true;
        }
        return false;
    }    

    /* Cancels an event watchig extablished with method `setup_io` for a given `context`. */
    bool cancel_io(Context context) {
        auto found = _io_watchers.find(context);
        if (found != _io_watchers.end()) {
            auto p_watcher = found->second.get();
            if (ev_is_active(p_watcher))
                ev_io_stop(_p_loop, p_watcher);
            _io_watchers.erase(found);
            return true;
        }
        return false;
    }

    /* Setup to call `on_event` for a given `context` every `seconds`. */
    bool setup_timer(Context context, double seconds) {
        auto p_watcher = new ev_timer();
        ev_timer_init(p_watcher, EventLoop::template callback<ev_timer>, seconds, seconds);
        ev_timer_start(_p_loop, p_watcher);
        if (ev_is_active(p_watcher)) {
            auto result = _timer_watchers.insert(std::make_pair(context, std::unique_ptr<ev_timer>(p_watcher)));
            if (!result.second) {
                cancel_timer(result.first->first);
                result = _timer_watchers.insert(std::make_pair(context, std::unique_ptr<ev_timer>(p_watcher)));
            }
            if (result.second) {
                result.first->second.get()->data = (void*)(&(result.first->first));
                return true;
            }
        }
        return false;
    }

    /* Cancels an event watchig extablished with method `setup_timer` for a given `context`. */
    bool cancel_timer(Context context) {
        auto found = _timer_watchers.find(context);
        if (found != _timer_watchers.end()) {
            auto p_watcher = found->second.get();
            if (ev_is_active(p_watcher))
                ev_timer_stop(_p_loop, p_watcher);
            _timer_watchers.erase(found);
            return true;
        }
        return false;
    }

    /* Setup to call `on_event` for a given `context` 
     * when the system signal with a given `signum` recieved. */
    bool setup_signal(Context context, int signum) {
        auto p_watcher = new ev_signal();
        ev_signal_init(p_watcher, EventLoop::template callback<ev_signal>, signum);
        ev_signal_start(_p_loop, p_watcher);
        if (ev_is_active(p_watcher)) {
            auto result = _signal_watchers.insert(std::make_pair(context, std::unique_ptr<ev_signal>(p_watcher)));
            if (!result.second) {
                cancel_signal(result.first->first);
                result = _signal_watchers.insert(std::make_pair(context, std::unique_ptr<ev_signal>(p_watcher)));
            }
            if (result.second) {
                result.first->second.get()->data = (void*)(&(result.first->first));
                return true;
            }
        }
        return false;
    }    

    /* Cancels an event watchig extablished with method `setup_signal` for a given `context`. */
    bool cancel_signal(Context context) {
        auto found = _signal_watchers.find(context);
        if (found != _signal_watchers.end()) {
            auto p_watcher = found->second.get();
            if (ev_is_active(p_watcher))
                ev_signal_stop(_p_loop, p_watcher);
            _signal_watchers.erase(found);
            return true;
        }
        return false;
    }

};

} // end of base
} // end of squall
#endif
<file_sep>/Default.cmake
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++11")
include(FindPackageHandleStandardArgs)
find_library(LIBEV_LIBRARY NAMES ev)
find_path(LIBEV_INCLUDE_DIR ev.h PATH_SUFFIXES include/ev)
find_package_handle_standard_args(libev DEFAULT_MSG LIBEV_LIBRARY LIBEV_INCLUDE_DIR)
include_directories(${CMAKE_HOME_DIRECTORY}/include)<file_sep>/setup.py
import sys
import os.path
from setuptools import setup, Extension

try:
    from Cython.Build import cythonize
except ImportError:
    cythonize = None

if sys.version_info[:2] < (3, 5):
    raise NotImplementedError("Required python version 3.5 or greater")

include_dirs = [os.path.join(os.path.dirname(__file__), "include")]

settings = {
    'name': 'Squall-Core.cython',
    'version': '0.1.dev27',
    'author': '<NAME>',
    'author_email': '<EMAIL>',
    'description': "This is Squall-Core optimized module which implements"
                   "the cooperative multitasking based on event-driven"
                   "switching async/await coroutines.",
    'namespace_packages': ['squall'],
    'package_dir': {'squall': 'python/squall'},
    'ext_modules': cythonize([Extension('squall.core_cython',
                                        ['python/squall/core_cython.pyx'],
                                        include_dirs=include_dirs,
                                        language="c++", libraries=['ev'],
                                        extra_compile_args=["-std=c++11"])]),
    'zip_safe': False
}

setup(**settings)<file_sep>/tests/test_EventLoop.cpp
#include "../include/squall/base/EventLoop.hxx"
#include "../include/squall/EventLoop.hxx"
#include "catch.hpp"


TEST_CASE("squall::base::EventLoop<const char*>", "[EventLoop]") {

    using squall::Event;
    using EventLoop = squall::base::EventLoop<const char*>;

    int cnt = 0;
    std::string result;
    const char* A = "A";
    const char* B = "B";
    const char* W = "W";

    EventLoop event_loop([&cnt, &result, &B, &W, &event_loop](const char* Ch, int revents) {
        result += Ch;
        if (Ch[0] == 'A') {
            cnt++;
            if (cnt==1)
                event_loop.setup_io(W, 0, Event::Write);
            else if (cnt==6)
                event_loop.cancel_timer(B);
            else if (cnt==10)
                event_loop.stop();
        }
        else if (Ch[0] == 'W')
            event_loop.cancel_io(W);
    });

    event_loop.setup_timer(A, 0.1);
    event_loop.setup_timer(B, 0.26);
    event_loop.start();

    REQUIRE(result == "AWABAAABAAAAA");
}


TEST_CASE("squall::EventLoop", "[EventLoop]") {
    using squall::Event;
    using squall::EventLoop;

    int A = 0;
    int B = 0;
    std::string result;
    EventLoop event_loop;

    event_loop.setup_timer([&](int revents){
        A++;
        result += 'A';
        if (A == 1) {
            event_loop.setup_io([&](int revents){
                result += 'W';
                return false;
            }, 0, Event::Write);
        }
        else if (A == 10)
            event_loop.stop();
        return true;
    }, 0.1);    

    event_loop.setup_timer([&](int revents){
        B = B + 1;
        result += "B";
        return (B < 2);
    }, 0.26);

    event_loop.start();
    REQUIRE(result == "AWABAAABAAAAA");    
}<file_sep>/include/Squall.hxx
/**
 * The Squall is template library which provides 
 * the event-driven and async network primitives.
 */
#ifndef SQUALL__HXX
#define SQUALL__HXX
#endif<file_sep>/demo/hello_cp.cxx
#include <iostream>
#include <squall/base/EventLoop.hxx>


using squall::Event;
using EventLoop = squall::base::EventLoop<const char*>;


int main(int argc, char const* argv[]) {
    EventLoop event_loop([&event_loop](const char* name, int revents) {
        if (revents == Event::Timeout) {
            std::cout << "Hello, " << name << "! (" << revents << ")" << std::endl;
        } else 
        if (revents == Event::Signal) {
            std::cout << "\nGot " << name << ". Bye! (" << revents << ")" << std::endl;
            event_loop.stop();            
        }
    });

    event_loop.setup_timer("Alesh", 1.0);
    event_loop.setup_timer("World", 2.5);
    event_loop.setup_signal("SIGINT", SIGINT);
    event_loop.start();
    return 0;
}<file_sep>/include/squall/EventLoop.hxx
#ifndef SQUALL__EVENT_LOOP__HXX
#define SQUALL__EVENT_LOOP__HXX

#include "base/EventLoop.hxx"

namespace squall {

using namespace std::placeholders;
using Callback = std::function<bool(int revents) noexcept>;


/**
 * Event loop implementation  for callback.
 */
class EventLoop : base::EventLoop<std::shared_ptr<Callback>> {
    using Base = base::EventLoop<std::shared_ptr<Callback>>;

    void _base_on_event(std::shared_ptr<Callback> handle, int revents) noexcept {
        auto callback = *handle.get();
        if(!callback(revents) && is_running()) {
            cancel_io(handle);
            cancel_timer(handle);
            cancel_signal(handle);
        }
    }

  public:
    EventLoop()
        : Base(std::bind(&EventLoop::_base_on_event, this, _1, _2)) {}

    /* Return true if an event dispatching is active. */
    bool is_running() {
        return Base::is_running();
    }

    /* Starts event dispatching.*/
    void start() {
        Base::start();
    }        

    /* Stops event dispatching.*/
    void stop() {
        Base::stop();
    }        

    /* Setup to call `callback` when the I/O device
     * with a given `fd` would be to read and/or write `mode`. */
    std::shared_ptr<Callback> setup_io(const Callback& callback, int fd, int mode) {
        auto handle = std::shared_ptr<Callback>(new Callback(callback));
        if (Base::setup_io(handle, fd, mode)) 
            return handle;
        else
            return std::shared_ptr<Callback>(nullptr);
    }

    /* Setup to call `callback` every `seconds`. */
    std::shared_ptr<Callback> setup_timer(const Callback& callback, double seconds) {
        auto handle = std::shared_ptr<Callback>(new Callback(callback));
        if (Base::setup_timer(handle, seconds)) 
            return handle;
        else
            return std::shared_ptr<Callback>(nullptr);
    }            

    /* Setup to call `callback` when the system signal
     * with a given `signum` recieved. */
    std::shared_ptr<Callback> setup_signal(const Callback& callback, int signum) {
        auto handle = std::shared_ptr<Callback>(new Callback(callback));
        if (Base::setup_signal(handle, signum)) 
            return handle;
        else
            return std::shared_ptr<Callback>(nullptr);
    }

    /* Updates I/O mode for event watchig extablished with method `setup_io`. */
    bool update_io(std::shared_ptr<Callback> handle, int mode) {
        return Base::update_io(handle, mode);
    }    

    /* Cancels event watchig extablished with method `setup_io`. */
    bool cancel_io(std::shared_ptr<Callback> handle) {
        return Base::cancel_io(handle);
    }    

    /* Cancels event watchig extablished with method `setup_timer`. */
    bool cancel_timer(std::shared_ptr<Callback> handle) {
        return Base::cancel_timer(handle);
    }

    /* Cancels event watchig extablished with method `setup_signal`. */
    bool cancel_signal(std::shared_ptr<Callback> handle) {
        return Base::cancel_signal(handle);
    }
};

} // end of squall
#endif
<file_sep>/CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Squall_CXX)

add_subdirectory(demo)
add_subdirectory(tests)<file_sep>/python/squall/common/EventLoop.hxx
#ifndef SQUALL__PYTHON__EVENT_LOOP__HXX
#define SQUALL__PYTHON__EVENT_LOOP__HXX

#include <Python.h>
#include <squall/base/EventLoop.hxx>

using squall::Event;
using namespace squall;
using namespace std::placeholders;

/* Event loop implementation for python extension. */
class EventLoop : base::EventLoop<PyObject*> {
    using Base = base::EventLoop<PyObject*>;

    PyThreadState* _thread_save;

    void _base_on_event(PyObject* callback, int revents) noexcept {
        PyEval_RestoreThread(_thread_save);
        PyObject* py_arglist = Py_BuildValue("(i)", revents);
        PyObject* py_result = PyObject_CallObject(callback, py_arglist);
        Py_XDECREF(py_arglist);
        Py_XDECREF(py_result);
        _thread_save = PyEval_SaveThread();
    }

  public:
    EventLoop()
        : Base(std::bind(&EventLoop::_base_on_event, this, _1, _2)) {}

    /* Return true if an event dispatching is active. */
    bool is_running() {
        return Base::is_running();
    }

    /* Starts event dispatching.*/
    void start() {
        _thread_save = PyEval_SaveThread();
        Base::start();
        PyEval_RestoreThread(_thread_save);
    }        

    /* Stops event dispatching.*/
    void stop() {
        Base::stop();
    }        

    /* Setup to call `callback` when the I/O device
     * with a given `fd` would be to read and/or write `mode`. */
    bool setup_io(PyObject* callback, int fd, int mode) {
        if (Base::setup_io(callback, fd, mode)) {
            Py_XINCREF(callback);
            return true;
        }
        return false;
    }

    /* Setup to call `callback` every `seconds`. */
    bool setup_timer(PyObject* callback, double seconds) {
        if (Base::setup_timer(callback, seconds)) {
            Py_XINCREF(callback);
            return true;
        }
        return false;
    }            

    /* Setup to call `callback` when the system signal
     * with a given `signum` recieved. */
    bool setup_signal(PyObject* callback, int signum) {
        if (Base::setup_signal(callback, signum)) {
            Py_XINCREF(callback);
            return true;
        }
        return false;
    }

    /* Updates I/O mode for event watchig extablished with method `setup_io`. */
    bool update_io(PyObject* callback, int mode) {
        return Base::update_io(callback, mode);
    }

    /* Cancels event watchig extablished with method `setup_io`. */
    bool cancel_io(PyObject* callback) {
        if (Base::cancel_io(callback)) {
            Py_XDECREF(callback);
            return true;
        }
        return false;
    }    

    /* Cancels event watchig extablished with method `setup_timer`. */
    bool cancel_timer(PyObject* callback) {
        if (Base::cancel_timer(callback)) {
            Py_XDECREF(callback);
            return true;
        }
        return false;
    }

    /* Cancels event watchig extablished with method `setup_signal`. */
    bool cancel_signal(PyObject* callback) {
        if (Base::cancel_signal(callback)) {
            Py_XDECREF(callback);
            return true;
        }
        return false;
    }

};

#endif<file_sep>/README.md
# Squall #

The Squall is template library which provides 
the event-driven and async network primitives.