blob: f3c83012430118a838b01d9ce1d5953648aaf361 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#pragma once
#include <cstdlib>
#include <memory>
#include <string_view>
#include <utility>
#include "event2/buffer.h"
#include "event2/bufferevent.h"
#include "event2/event.h"
#include "event2/listener.h"
#include "type_util.h"
using StaticFree = StaticFunction<decltype(std::free), std::free>;
template <typename T>
struct UniqueFreePtr : std::unique_ptr<T, StaticFree> {
using BaseType = std::unique_ptr<T, StaticFree>;
using BaseType::BaseType;
};
struct UniqueEvbufReadln : UniqueFreePtr<char[]> {
UniqueEvbufReadln(evbuffer *buffer, evbuffer_eol_style eol_style)
: UniqueFreePtr(evbuffer_readln(buffer, &length, eol_style)) {}
size_t length;
std::string_view View() { return {get(), length}; }
};
using StaticEvbufFree = StaticFunction<decltype(evbuffer_free), evbuffer_free>;
struct UniqueEvbuf : std::unique_ptr<evbuffer, StaticEvbufFree> {
using BaseType = std::unique_ptr<evbuffer, StaticEvbufFree>;
UniqueEvbuf() : BaseType(evbuffer_new()) {}
explicit UniqueEvbuf(evbuffer *buffer) : BaseType(buffer) {}
};
using StaticEventFree = StaticFunction<decltype(event_free), event_free>;
struct UniqueEvent : std::unique_ptr<event, StaticEventFree> {
using BaseType = std::unique_ptr<event, StaticEventFree>;
UniqueEvent() : BaseType(nullptr) {}
explicit UniqueEvent(event *buffer) : BaseType(buffer) {}
};
template <typename Derived, bool ReadCB = true, bool WriteCB = true, bool EventCB = true>
struct EvbufCallbackBase {
private:
static void readCB(bufferevent *bev, void *ctx) { static_cast<Derived *>(ctx)->OnRead(bev); }
static void writeCB(bufferevent *bev, void *ctx) { static_cast<Derived *>(ctx)->OnWrite(bev); }
static void eventCB(bufferevent *bev, short what, void *ctx) { static_cast<Derived *>(ctx)->OnEvent(bev, what); }
static auto getReadCB() {
if constexpr (ReadCB) {
return readCB;
} else {
return nullptr;
}
}
static auto getWriteCB() {
if constexpr (WriteCB) {
return writeCB;
} else {
return nullptr;
}
}
static auto getEventCB() {
if constexpr (EventCB) {
return eventCB;
} else {
return nullptr;
}
}
public:
void SetCB(bufferevent *bev) {
bufferevent_setcb(bev, getReadCB(), getWriteCB(), getEventCB(), reinterpret_cast<void *>(this));
}
};
template <typename Derived>
struct EventCallbackBase {
private:
static void timerCB(evutil_socket_t fd, short events, void *ctx) { static_cast<Derived *>(ctx)->TimerCB(fd, events); }
public:
event *NewEvent(event_base *base, evutil_socket_t fd, short events) {
return event_new(base, fd, events, timerCB, reinterpret_cast<void *>(this));
}
event *NewTimer(event_base *base) { return evtimer_new(base, timerCB, reinterpret_cast<void *>(this)); }
};
template <typename Derived>
struct EvconnlistenerBase {
private:
template <void (Derived::*cb)(evconnlistener *, evutil_socket_t, sockaddr *, int)>
static void callback(evconnlistener *listener, evutil_socket_t fd, sockaddr *address, int socklen, void *ctx) {
return (reinterpret_cast<Derived *>(ctx)->*cb)(listener, fd, address, socklen);
}
public:
template <void (Derived::*cb)(evconnlistener *, evutil_socket_t, sockaddr *, int)>
evconnlistener *NewEvconnlistener(event_base *base, unsigned flags, int backlog, evutil_socket_t fd) {
return evconnlistener_new(base, callback<cb>, this, flags, backlog, fd);
}
};
namespace details {
template <auto F, typename>
struct EventCallbackImpl;
template <auto F, typename T, typename R, typename... Args>
struct EventCallbackImpl<F, R (T::*)(Args...)> {
static R Func(Args... args, void *ctx) { return (reinterpret_cast<T *>(ctx)->*F)(args...); }
};
} // namespace details
// convert member functions to eventbuffer callbacks
// e.g. for member function `void A::f(int x)` from class A
// EventCallback<&A::f> generate a function
// void EventCallback<&A::f>::Func(int x, void *ctx)
// and put `this` pointer of A to `void *ctx`
template <auto F>
struct EventCallback : details::EventCallbackImpl<F, decltype(F)> {};
template <auto F>
constexpr auto EventCallbackFunc = EventCallback<F>::Func;