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
|
||||
BoostLog.h BoostLog.inl BoostLog.cpp
|
||||
IoContext.h IoContext.cpp
|
||||
MessageManager.h MessageManager.inl MessageManager.cpp
|
||||
Singleton.h
|
||||
StreamFormat.h StreamFormat.inl StreamFormat.cpp
|
||||
)
|
||||
|
||||
target_include_directories(Universal
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
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