Add class 'MessageManager'.
This commit is contained in:
parent
ef8d5b0b03
commit
bf5854addf
@ -2,9 +2,16 @@ find_package(Boost REQUIRED COMPONENTS log log_setup)
|
|||||||
|
|
||||||
add_library(Universal
|
add_library(Universal
|
||||||
BoostLog.h BoostLog.inl BoostLog.cpp
|
BoostLog.h BoostLog.inl BoostLog.cpp
|
||||||
|
IoContext.h IoContext.cpp
|
||||||
|
MessageManager.h MessageManager.inl MessageManager.cpp
|
||||||
|
Singleton.h
|
||||||
StreamFormat.h StreamFormat.inl StreamFormat.cpp
|
StreamFormat.h StreamFormat.inl StreamFormat.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_include_directories(Universal
|
||||||
|
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(Universal
|
target_link_libraries(Universal
|
||||||
PRIVATE ${Boost_LIBRARIES}
|
PUBLIC ${Boost_LIBRARIES}
|
||||||
)
|
)
|
128
Universal/FunctionTraits.h
Normal file
128
Universal/FunctionTraits.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#ifndef FUNCTIONTRAITS_H
|
||||||
|
#define FUNCTIONTRAITS_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class FunctionTraits;
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
struct IsTuple : std::false_type {
|
||||||
|
enum {
|
||||||
|
num = 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
struct IsTuple<std::tuple<T...>> : std::true_type {
|
||||||
|
enum {
|
||||||
|
num = std::tuple_size<std::tuple<T...>>::value,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
struct IsTuple<std::pair<T...>> : std::true_type {
|
||||||
|
enum {
|
||||||
|
num = std::tuple_size<std::pair<T...>>::value,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Ret, typename... Args>
|
||||||
|
class FunctionTraits<Ret(Args...)> {
|
||||||
|
public:
|
||||||
|
enum { arity = sizeof...(Args), Results = IsTuple<Ret>::num };
|
||||||
|
using FunctionType = Ret(Args...);
|
||||||
|
using FunctionPointerType = FunctionType *;
|
||||||
|
using ReturnType = Ret;
|
||||||
|
using StlFunctionType = std::function<FunctionType>;
|
||||||
|
using Arguments = std::tuple<Args...>;
|
||||||
|
|
||||||
|
template <size_t I>
|
||||||
|
class Argument {
|
||||||
|
public:
|
||||||
|
static_assert(I < arity, "index is out of range, index must less than sizeof Args...");
|
||||||
|
using Type = std::tuple_element_t<I, Arguments>;
|
||||||
|
};
|
||||||
|
|
||||||
|
using FirstArgumentType = typename Argument<0>::Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Ret>
|
||||||
|
class FunctionTraits<Ret()> {
|
||||||
|
public:
|
||||||
|
enum { arity = 0, Results = IsTuple<Ret>::num };
|
||||||
|
using FunctionType = Ret();
|
||||||
|
using FunctionPointerType = FunctionType *;
|
||||||
|
using ReturnType = Ret;
|
||||||
|
using StlFunctionType = std::function<FunctionType>;
|
||||||
|
using Arguments = std::tuple<>;
|
||||||
|
using FirstArgumentType = void;
|
||||||
|
template <size_t I>
|
||||||
|
class Argument {
|
||||||
|
public:
|
||||||
|
using Type = void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class FunctionTraits<std::nullptr_t> {
|
||||||
|
public:
|
||||||
|
using Arguments = std::tuple<>;
|
||||||
|
using FirstArgumentType = void;
|
||||||
|
template <size_t I>
|
||||||
|
class Argument {
|
||||||
|
public:
|
||||||
|
using Type = void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Ret, typename... Args>
|
||||||
|
class FunctionTraits<Ret (*)(Args...)> : public FunctionTraits<Ret(Args...)> {};
|
||||||
|
|
||||||
|
template <typename Ret, typename... Args>
|
||||||
|
class FunctionTraits<std::function<Ret(Args...)>> : public FunctionTraits<Ret(Args...)> {};
|
||||||
|
|
||||||
|
template <typename Ret, typename ClassType, typename... Args>
|
||||||
|
class FunctionTraits<Ret (ClassType::*)(Args...)> : public FunctionTraits<Ret(Args...)> {};
|
||||||
|
|
||||||
|
template <typename Ret, typename ClassType, typename... Args>
|
||||||
|
class FunctionTraits<Ret (ClassType::*)(Args...) volatile> : public FunctionTraits<Ret(Args...)> {};
|
||||||
|
|
||||||
|
template <typename Ret, typename ClassType, typename... Args>
|
||||||
|
class FunctionTraits<Ret (ClassType::*)(Args...) const> : public FunctionTraits<Ret(Args...)> {};
|
||||||
|
|
||||||
|
template <typename Ret, typename ClassType, typename... Args>
|
||||||
|
class FunctionTraits<Ret (ClassType::*)(Args...) const volatile> : public FunctionTraits<Ret(Args...)> {};
|
||||||
|
|
||||||
|
// std::bind for object methods rclcpp/rclcpp/include/rclcpp/function_traits.hpp
|
||||||
|
template <typename ClassT, typename ReturnTypeT, typename... Args, typename... FArgs>
|
||||||
|
#if defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
|
||||||
|
struct FunctionTraits<std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>>
|
||||||
|
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
|
||||||
|
struct FunctionTraits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args...)>(FArgs...)>>
|
||||||
|
#elif defined _MSC_VER // MS Visual Studio
|
||||||
|
struct FunctionTraits<std::_Binder<std::_Unforced, ReturnTypeT (ClassT::*)(Args...), FArgs...>>
|
||||||
|
#elif defined __clang__
|
||||||
|
struct FunctionTraits<std::__bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>>
|
||||||
|
#else
|
||||||
|
#error "Unsupported C++ compiler / standard library"
|
||||||
|
#endif
|
||||||
|
: FunctionTraits<ReturnTypeT(Args...)> {
|
||||||
|
};
|
||||||
|
|
||||||
|
// template <typename ClassT, typename ReturnTypeT, typename... Args, typename... FArgs>
|
||||||
|
// class FunctionTraits<std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>>
|
||||||
|
// : public FunctionTraits<decltype(std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>::operator())> {};
|
||||||
|
|
||||||
|
template <typename Callable>
|
||||||
|
class FunctionTraits : public FunctionTraits<decltype(&Callable::operator())> {};
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
typename FunctionTraits<std::decay_t<Function>>::StlFunctionType makeStlFunction(Function &&lambda) {
|
||||||
|
return static_cast<typename FunctionTraits<std::decay_t<Function>>::StlFunctionType>(
|
||||||
|
std::forward<Function>(lambda));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FUNCTIONTRAITS_H
|
28
Universal/IoContext.cpp
Normal file
28
Universal/IoContext.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "IoContext.h"
|
||||||
|
#include <boost/asio/executor_work_guard.hpp>
|
||||||
|
#include <boost/scope_exit.hpp>
|
||||||
|
|
||||||
|
IoContext::~IoContext() {
|
||||||
|
m_ioContext->stop();
|
||||||
|
if (m_thread.joinable()) m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IoContext::runIoContext() {
|
||||||
|
LOG(info) << "asio context started ...";
|
||||||
|
BOOST_SCOPE_EXIT(void) {
|
||||||
|
LOG(info) << "asio context exited ...";
|
||||||
|
}
|
||||||
|
BOOST_SCOPE_EXIT_END
|
||||||
|
try {
|
||||||
|
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work(m_ioContext->get_executor());
|
||||||
|
m_ioContext->run();
|
||||||
|
} catch (const boost::log::system_error &error) {
|
||||||
|
LOG(error) << error.what();
|
||||||
|
} catch (const std::out_of_range &e) {
|
||||||
|
LOG(error) << e.what();
|
||||||
|
} catch (const boost::exception &e) {
|
||||||
|
LOG(error) << boost::diagnostic_information(e);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
LOG(error) << e.what();
|
||||||
|
}
|
||||||
|
}
|
36
Universal/IoContext.h
Normal file
36
Universal/IoContext.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef IOCONTEXT_H
|
||||||
|
#define IOCONTEXT_H
|
||||||
|
|
||||||
|
#include "Singleton.h"
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
class IoContext {
|
||||||
|
public:
|
||||||
|
enum class Mode {
|
||||||
|
Synchronous,
|
||||||
|
Asynchronous,
|
||||||
|
};
|
||||||
|
friend class Amass::Singleton<IoContext, Amass::LocalInstance>;
|
||||||
|
std::shared_ptr<boost::asio::io_context> ioContext() const { return m_ioContext; }
|
||||||
|
template <Mode mode = Mode::Asynchronous>
|
||||||
|
void run() {
|
||||||
|
if constexpr (mode == Mode::Asynchronous) {
|
||||||
|
m_thread = std::thread(&IoContext::runIoContext, this);
|
||||||
|
} else {
|
||||||
|
runIoContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~IoContext();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename... Args>
|
||||||
|
IoContext(Args &&... args) : m_ioContext(std::make_shared<boost::asio::io_context>(std::forward<Args>(args)...)) {}
|
||||||
|
void runIoContext();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::thread m_thread;
|
||||||
|
std::shared_ptr<boost::asio::io_context> m_ioContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IOCONTEXT_H
|
37
Universal/MessageManager.cpp
Normal file
37
Universal/MessageManager.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "MessageManager.h"
|
||||||
|
|
||||||
|
MessageManager::MessageManager() {
|
||||||
|
m_thread = std::thread(&MessageManager::run, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageManager::~MessageManager() {
|
||||||
|
m_exit = true;
|
||||||
|
if (m_thread.joinable()) m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageManager::run() {
|
||||||
|
LOG(trace) << "message runner[" << std::this_thread::get_id() << "] start...";
|
||||||
|
while (!m_exit) {
|
||||||
|
if (m_params.empty()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto &[topic, args] = m_params.front();
|
||||||
|
callExecutor(topic, std::move(args));
|
||||||
|
m_params.pop();
|
||||||
|
}
|
||||||
|
LOG(trace) << "message runner exit...";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageManager::callExecutor(const std::string &signature, std::any &¶meter) {
|
||||||
|
auto executors = m_executors.equal_range(signature);
|
||||||
|
for (auto executor = executors.first; executor != executors.second; ++executor) {
|
||||||
|
try {
|
||||||
|
if (!executor->second(parameter)) {
|
||||||
|
LOG(warning) << "topic: " << signature << " execute failed, parameter cast failed.";
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
LOG(error) << e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
Universal/MessageManager.h
Normal file
93
Universal/MessageManager.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#ifndef MESSAGEMANAGER_H
|
||||||
|
#define MESSAGEMANAGER_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <queue>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
|
#ifdef ANDROID
|
||||||
|
#include <boost/any.hpp>
|
||||||
|
#else
|
||||||
|
#include <any>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class MessageManager {
|
||||||
|
#ifdef ANDROID
|
||||||
|
using ParamEntry = boost::any;
|
||||||
|
using BadEntryCast = boost::bad_any_cast;
|
||||||
|
#else
|
||||||
|
using ParamEntry = std::any;
|
||||||
|
using BadEntryCast = std::bad_any_cast;
|
||||||
|
#endif
|
||||||
|
using AsyncParam = std::pair<std::string, ParamEntry>;
|
||||||
|
using Executor = std::function<bool(const ParamEntry &)>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename... Args>
|
||||||
|
class Message {
|
||||||
|
public:
|
||||||
|
explicit constexpr Message(const char *topic) : topic(topic) {
|
||||||
|
}
|
||||||
|
std::string_view topic;
|
||||||
|
};
|
||||||
|
MessageManager();
|
||||||
|
~MessageManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief std::bind() is not recommended,recommended to use lambda. if you must use std::bind(),do not use
|
||||||
|
* placeholders!
|
||||||
|
*
|
||||||
|
* @tparam Function
|
||||||
|
* @param topic
|
||||||
|
* @param f
|
||||||
|
*/
|
||||||
|
template <typename Function>
|
||||||
|
void registerTopic(const std::string_view &topic, Function &&f);
|
||||||
|
|
||||||
|
template <typename Function, typename... Args>
|
||||||
|
void registerTopic(const Message<Args...> &topic, Function &&f);
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
void removeTopic(const std::string_view &topic);
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
size_t topicCount(const std::string_view &topic);
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void sendMessage(const std::string_view &topic, Args &&...args);
|
||||||
|
|
||||||
|
template <typename Function, typename... Args>
|
||||||
|
void sendMessage(const std::string_view &topic, Args &&...args);
|
||||||
|
|
||||||
|
template <typename... TArgs, typename... Args>
|
||||||
|
void sendMessage(const Message<TArgs...> &topic, Args &&...args);
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void sendAsyncMessage(const std::string_view &topic, Args &&...args);
|
||||||
|
|
||||||
|
template <typename Function, typename... Args>
|
||||||
|
void sendAsyncMessage(const std::string_view &topic, Args &&...args);
|
||||||
|
|
||||||
|
template <typename... TArgs, typename... Args>
|
||||||
|
void sendAsyncMessage(const Message<TArgs...> &topic, Args &&...args);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MessageManager(const MessageManager &) = delete;
|
||||||
|
template <typename Function>
|
||||||
|
static Executor executorWrapper(Function &&f);
|
||||||
|
void callExecutor(const std::string &signature, std::any &¶meter);
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_multimap<std::string, Executor> m_executors;
|
||||||
|
std::queue<AsyncParam> m_params;
|
||||||
|
std::thread m_thread;
|
||||||
|
bool m_exit{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "MessageManager.inl"
|
||||||
|
|
||||||
|
#endif // MESSAGEMANAGER_H
|
153
Universal/MessageManager.inl
Normal file
153
Universal/MessageManager.inl
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
#ifndef __MESSAGEMANAGER_INL__
|
||||||
|
#define __MESSAGEMANAGER_INL__
|
||||||
|
|
||||||
|
#include "BoostLog.h"
|
||||||
|
#include "FunctionTraits.h"
|
||||||
|
#include "MessageManager.h"
|
||||||
|
#include <boost/type_index.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
template <typename Args>
|
||||||
|
class Signature;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
class Signature<std::tuple<Args...>> {
|
||||||
|
public:
|
||||||
|
using Type = std::tuple<std::decay_t<Args>...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
static void formatSignature(std::ostringstream &oss, Type &&type) {
|
||||||
|
oss << boost::typeindex::type_id<Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type, typename... Args>
|
||||||
|
static void formatSignature(std::ostringstream &oss, Type &&type, Args &&...args) {
|
||||||
|
oss << boost::typeindex::type_id<Type>() << ",";
|
||||||
|
formatSignature(oss, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ArgTuple, std::size_t... I>
|
||||||
|
static void formatSignature(std::ostringstream &oss, ArgTuple &&args, std::index_sequence<I...>) {
|
||||||
|
formatSignature(oss, std::get<I>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
static std::string formatTopicWithFunction(const std::string_view &topic) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
using Arguments = typename FunctionTraits<std::decay_t<Function>>::Arguments;
|
||||||
|
using Sigs = typename Signature<Arguments>::Type;
|
||||||
|
|
||||||
|
oss << topic << "###[";
|
||||||
|
if constexpr (std::tuple_size<Arguments>::value > 0) {
|
||||||
|
formatSignature<Arguments>(oss, Sigs{}, std::make_index_sequence<std::tuple_size<Arguments>::value>{});
|
||||||
|
} else {
|
||||||
|
oss << "void";
|
||||||
|
}
|
||||||
|
oss << "]";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
static std::string formatTopicWithParameters(const std::string_view &topic, Args &&...args) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << topic << "###[";
|
||||||
|
if constexpr (sizeof...(Args) > 0) {
|
||||||
|
formatSignature(oss, std::forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
|
oss << "void";
|
||||||
|
}
|
||||||
|
|
||||||
|
oss << "]";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
void MessageManager::registerTopic(const std::string_view &topic, Function &&f) {
|
||||||
|
auto signature = formatTopicWithFunction<Function>(topic);
|
||||||
|
m_executors.emplace(signature, executorWrapper(std::move(f)));
|
||||||
|
LOG(debug) << "register message,topic: " << signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function, typename... Args>
|
||||||
|
void MessageManager::registerTopic(const Message<Args...> &topic, Function &&f) {
|
||||||
|
using Arguments = typename FunctionTraits<std::decay_t<Function>>::Arguments;
|
||||||
|
static_assert(std::is_same_v<Arguments, std::tuple<Args...>>, "arguments not same...");
|
||||||
|
registerTopic(topic.topic, std::forward<Function>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
size_t MessageManager::topicCount(const std::string_view &topic) {
|
||||||
|
auto signature = formatTopicWithFunction<Function>(topic);
|
||||||
|
return m_executors.count(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
void MessageManager::removeTopic(const std::string_view &topic) {
|
||||||
|
auto signature = formatTopicWithFunction<Function>(topic);
|
||||||
|
m_executors.erase(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void MessageManager::sendMessage(const std::string_view &topic, Args &&...args) {
|
||||||
|
auto signature = formatTopicWithParameters(topic, std::forward<Args>(args)...);
|
||||||
|
callExecutor(signature, std::make_tuple(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function, typename... Args>
|
||||||
|
void MessageManager::sendMessage(const std::string_view &topic, Args &&...args) {
|
||||||
|
using Arguments = typename FunctionTraits<std::decay_t<Function>>::Arguments;
|
||||||
|
// LOG(debug) << boost::typeindex::type_id<Arguments>();
|
||||||
|
auto signature = formatTopicWithFunction<Function>(topic);
|
||||||
|
callExecutor(signature, Arguments{std::forward<Args>(args)...});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... TArgs, typename... Args>
|
||||||
|
void MessageManager::sendMessage(const Message<TArgs...> &topic, Args &&...args) {
|
||||||
|
using Arguments = typename FunctionTraits<void(TArgs...)>::Arguments;
|
||||||
|
auto signature = formatTopicWithFunction<void(TArgs...)>(topic.topic);
|
||||||
|
callExecutor(signature, Arguments{std::forward<TArgs>(args)...});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void MessageManager::sendAsyncMessage(const std::string_view &topic, Args &&...args) {
|
||||||
|
auto signature = formatTopicWithParameters(topic, std::forward<Args>(args)...);
|
||||||
|
m_params.push({signature, std::make_tuple(std::forward<Args>(args)...)});
|
||||||
|
LOG(debug) << "call async message,topic: " << signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function, typename... Args>
|
||||||
|
void MessageManager::sendAsyncMessage(const std::string_view &topic, Args &&...args) {
|
||||||
|
using Arguments = typename FunctionTraits<std::decay_t<Function>>::Arguments;
|
||||||
|
auto signature = formatTopicWithFunction<Function>(topic);
|
||||||
|
m_params.push({signature, Arguments{std::forward<Args>(args)...}});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... TArgs, typename... Args>
|
||||||
|
void MessageManager::sendAsyncMessage(const Message<TArgs...> &topic, Args &&...args) {
|
||||||
|
using Function = void(TArgs...);
|
||||||
|
using Arguments = typename FunctionTraits<Function>::Arguments;
|
||||||
|
auto signature = formatTopicWithFunction<Function>(topic.topic);
|
||||||
|
m_params.push({signature, Arguments{std::forward<TArgs>(args)...}});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
MessageManager::Executor MessageManager::executorWrapper(Function &&f) {
|
||||||
|
return [executor(std::move(f))](const std::any &args) -> bool {
|
||||||
|
using Arguments = typename FunctionTraits<Function>::Arguments;
|
||||||
|
auto arguments = std::any_cast<Arguments>(&args);
|
||||||
|
if (arguments != nullptr) {
|
||||||
|
std::apply(executor, *arguments);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
using Signature = typename Signature<Arguments>::Type;
|
||||||
|
auto signature = std::any_cast<Signature>(&args);
|
||||||
|
if (signature != nullptr) {
|
||||||
|
std::apply(executor, *signature);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __MESSAGEMANAGER_H__
|
82
Universal/Singleton.h
Normal file
82
Universal/Singleton.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#ifndef SINGLETON_H
|
||||||
|
#define SINGLETON_H
|
||||||
|
|
||||||
|
#include "BoostLog.h"
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Amass {
|
||||||
|
|
||||||
|
using GlobalInstance = std::true_type;
|
||||||
|
using LocalInstance = std::false_type;
|
||||||
|
|
||||||
|
struct Construct {};
|
||||||
|
struct Reference {};
|
||||||
|
struct Register {};
|
||||||
|
|
||||||
|
template <typename T, typename Style = LocalInstance>
|
||||||
|
class Singleton;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Singleton<T, LocalInstance> {
|
||||||
|
public:
|
||||||
|
template <typename Invoke = Reference, typename InstanceType = T, typename... Args>
|
||||||
|
static std::shared_ptr<T> instance(Args &&...args) {
|
||||||
|
// LOG(debug) << typeid(T).name() << " address: " << (size_t)&m_instance;
|
||||||
|
static_assert(std::is_base_of_v<T, InstanceType>, "InstanceType must be child of T ...");
|
||||||
|
if constexpr (std::is_same_v<Invoke, Construct>) {
|
||||||
|
if (!m_instance.expired()) {
|
||||||
|
throw std::runtime_error("an instance have constructed ...");
|
||||||
|
}
|
||||||
|
auto instance = std::shared_ptr<T>(new InstanceType(std::forward<Args>(args)...));
|
||||||
|
m_instance = instance;
|
||||||
|
return instance;
|
||||||
|
} else if constexpr (std::is_same_v<Invoke, Reference>) {
|
||||||
|
return m_instance.expired() ? nullptr : m_instance.lock();
|
||||||
|
} else if constexpr (std::is_same_v<Invoke, Register>) {
|
||||||
|
static_assert(sizeof...(args) == 1, "args must equal to 1...");
|
||||||
|
m_instance = std::get<0>(std::forward_as_tuple(args)...);
|
||||||
|
return std::get<0>(std::forward_as_tuple(args)...);
|
||||||
|
} else {
|
||||||
|
static_assert(!std::is_same_v<Invoke, GlobalInstance>, "Can not to it!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::weak_ptr<T> weakPointer() {
|
||||||
|
return m_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Singleton() = delete;
|
||||||
|
~Singleton() = delete;
|
||||||
|
Singleton(const Singleton &) = delete;
|
||||||
|
Singleton &operator=(const Singleton &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline static std::weak_ptr<T> m_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Singleton<T, GlobalInstance> {
|
||||||
|
public:
|
||||||
|
template <typename... Args>
|
||||||
|
static T *instance(Args &&...args) {
|
||||||
|
if (!m_value) {
|
||||||
|
m_value.reset(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
return m_value.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Singleton() = delete;
|
||||||
|
~Singleton() = delete;
|
||||||
|
Singleton(const Singleton &) = delete;
|
||||||
|
Singleton &operator=(const Singleton &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline static std::shared_ptr<T> m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Amass
|
||||||
|
|
||||||
|
#endif // SINGLETON_H
|
Loading…
Reference in New Issue
Block a user