From 7f121cf0fc967515f91dbe33e1d4ca558995039f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=98=E4=B8=8D=E5=A6=82=E4=B8=80=E5=8F=AA=E7=8C=AA?= =?UTF-8?q?=E5=A8=81=E6=AD=A6?= Date: Fri, 23 Feb 2024 16:49:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0AOP=E3=80=81IoC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 7 +- src/base/any.h | 86 +++++++++ src/base/function_traits.h | 82 +++++++++ src/bus/message_bus.h | 81 ++++++++ src/ioc/container.h | 107 +++++++++++ src/main.cpp | 368 ++++++++++++++++++------------------- 6 files changed, 539 insertions(+), 192 deletions(-) create mode 100644 src/base/any.h create mode 100644 src/base/function_traits.h create mode 100644 src/bus/message_bus.h create mode 100644 src/ioc/container.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a59ff02..b044f84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) project(cpp_start LANGUAGES CXX VERSION 1.0.0) # 设置编译器参数 -set(CMAKE_CXX_FLAGS "-fno-elide-constructors") # 关闭编译优化 +#set(CMAKE_CXX_FLAGS "-fno-elide-constructors") # 关闭编译优化 # 消息提示 message(STATUS "message from cmake file!") @@ -23,16 +23,19 @@ add_executable(${PROJECT_NAME} src/main.cpp) aux_source_directory(src/aspect ASPECT_DIR) aux_source_directory(src/base BASE_DIR) aux_source_directory(src/util UTIL_DIR) +aux_source_directory(src/ioc IOC_DIR) +aux_source_directory(src/bus BUS_DIR) aux_source_directory(src/test TEST_DIR) target_include_directories(${PROJECT_NAME} PRIVATE - ) target_sources(${PROJECT_NAME} PRIVATE ${ASPECT_DIR} ${TEST_DIR} ${BASE_DIR} + ${IOC_DIR} + ${BUS_DIR} ${UTIL_DIR} ) diff --git a/src/base/any.h b/src/base/any.h new file mode 100644 index 0000000..45da4fe --- /dev/null +++ b/src/base/any.h @@ -0,0 +1,86 @@ + +#ifndef CPP_START_ANY_H +#define CPP_START_ANY_H + +#include +#include +#include +#include +#include + +using namespace std; + +struct Any { + Any() : m_tpIndex(std::type_index(typeid(void))) {} + + Any(const Any &that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex) {} + + Any(Any &&that) noexcept: m_ptr(std::move(that.m_ptr)), m_tpIndex(that.m_tpIndex) {} + + //创建智能指针时,对于一般的类型,通过std::decay来移除引用和cv符,从而获取原始类型 + template::type, Any>::value, U>::type> + Any(U &&value) : m_ptr(new Derived::type>(std::forward(value))), + m_tpIndex(type_index(typeid(typename std::decay::type))) {} + + bool IsNull() const { return !bool(m_ptr); } + + template + bool Is() const { + return m_tpIndex == type_index(typeid(U)); + } + + //将Any转换为实际的类型 + template + U &AnyCast() { + if (!Is()) { + cout << "can not cast " << typeid(U).name() << " to " << m_tpIndex.name() << endl; + throw bad_cast(); + } + + auto derived = dynamic_cast *> (m_ptr.get()); + return derived->m_value; + } + + Any &operator=(const Any &a) { + if (m_ptr == a.m_ptr) + return *this; + + m_ptr = a.Clone(); + m_tpIndex = a.m_tpIndex; + return *this; + } + +private: + struct Base; + typedef std::unique_ptr BasePtr; + + struct Base { + virtual ~Base() = default; + + virtual BasePtr Clone() const = 0; + }; + + template + struct Derived : Base { + template + Derived(U &&value) : m_value(std::forward(value)) {} + + BasePtr Clone() const override { + return BasePtr(new Derived(m_value)); + } + + T m_value; + }; + + BasePtr Clone() const { + if (m_ptr != nullptr) + return m_ptr->Clone(); + + return nullptr; + } + + BasePtr m_ptr; + std::type_index m_tpIndex; +}; + +#endif //CPP_START_ANY_H diff --git a/src/base/function_traits.h b/src/base/function_traits.h new file mode 100644 index 0000000..78e9bf2 --- /dev/null +++ b/src/base/function_traits.h @@ -0,0 +1,82 @@ + +#ifndef CPP_START_FUNCTION_TRAITS_H +#define CPP_START_FUNCTION_TRAITS_H + +#include +#include + +//function_traits 获取普通函数、函数指针、std::function、函数对象以及成员函数的函数类型、返回类型、参数个数和参数的具体类型。 + +//转换为std::function和函数指针 +template +struct function_traits; + +//普通函数 +//返回类型Ret 参数列表Args +template +struct function_traits { +public: + enum { + arity = sizeof...(Args) + }; //enum 定义参数列表的个数arity常量 + //定义别名 + typedef Ret function_type(Args...); + + typedef Ret return_type; + using std_function_type = std::function; + + typedef Ret (*pointer)(Args...); + + template + struct args { + //static_assert(常量表达式,错误提示字符串) 静态断言, + static_assert(I < arity, "index is out of range,index less than sizeof Args"); + + //std::tuple_element 获取元素的类型 + using type = typename std::tuple_element>::type; + }; +}; + +template +struct function_traits : function_traits { +}; + +template +struct function_traits> : function_traits { +}; + +#define FUNCTION_TRAITS(...) \ + template \ + struct function_traits:function_traits{}; \ + +FUNCTION_TRAITS() +FUNCTION_TRAITS(const) +FUNCTION_TRAITS(volatile) +FUNCTION_TRAITS(const volatile) + +//函数对象 +template +//decltype 类型说明符 作用时选择并返回操作数的数据类型. +struct function_traits : function_traits { +}; + +// lambda表达式是一个匿名类,使用一个lambda表达式,实际就是使用一个匿名类的匿名对象,匿名类内部包含operator()调用符。 +// operator()的返回类型、形参列表以及 函数体与lambda表达式相对应,因此可像函数调用一样使用lambda表达式。 +//可通过function_traits获取lambda表达式的operator()类型,之后再将其转换为std::function + +template +typename function_traits::std_function_type to_function(const Function &lambda) { + return static_cast::std_function_type>(lambda); +} + +template +typename function_traits::std_function_type to_function(Function &&lamdba) { + return static_cast::std_function_type>(std::forward(lamdba)); +} + +template +typename function_traits::pointer to_function_pointer(const Function &lambda) { + return static_cast::pointer>(lambda); +} + +#endif //CPP_START_FUNCTION_TRAITS_H diff --git a/src/bus/message_bus.h b/src/bus/message_bus.h new file mode 100644 index 0000000..00a092e --- /dev/null +++ b/src/bus/message_bus.h @@ -0,0 +1,81 @@ + +#ifndef CPP_START_MESSAGE_BUS_H +#define CPP_START_MESSAGE_BUS_H + +#include +#include +#include +#include "../base/any.h" +#include "../base/function_traits.h" +#include "../base/non_copy_able.h" + +using namespace std; + +class MessageBus : public NonCopyAble { +public: + //注册消息 + template + void Attach(F &&f, const string &strTopic = "") { + auto func = to_function(std::forward(f)); + Add(strTopic, std::move(func)); + } + + //发送消息 + template + //无参数 + void SendReq(const string &strTopic = "") { + //std::function 函数对象类,包装了满足该函数模板类型的任意函数对象,这些目标实体包括普通函数、Lambda表达式、函数指针、模函数、类成员函数、类静态函数以及其它的函数对象 + using function_type = std::function; + string strMsgType = strTopic + string("##") + typeid(function_type).name(); + + std::pair::iterator, std::multimap::iterator> range = m_map.equal_range( + strMsgType); + for (Iterator it = range.first; it != range.second; ++it) { + auto f = it->second.AnyCast(); + f(); + } + } + + template + //有参数 + void SendReq(Args &&... args, const string &strTopic = "") { + using function_type = std::function; + string strMsgType = strTopic + string("##") + typeid(function_type).name(); + cout << "send Msg: " << strMsgType << endl; + auto range = m_map.equal_range(strMsgType); + for (Iterator it = range.first; it != range.second; ++it) { + auto f = it->second.AnyCast(); + f(std::forward(args)...); + } + } + + //移除某个主题,需要主题和消息类型 + template + void Remove(const string &strTopic = "") { + using function_type = std::function; + string strMsgType = strTopic + string("##") + typeid(function_type).name(); + cout << "remove message: " << strMsgType << endl; + int count = m_map.count(strMsgType); + auto range = m_map.equal_range(strMsgType); + m_map.erase(range.first, range.second); + } + +private: + template + void Add(const string &strTopic, F &&f) { + string strMsgType = strTopic + string("##") + typeid(F).name();//主题 + + //emplace 插入操作,相比inset,其能就地通过参数构造对象,不需要拷贝或者移动内存,使容器插入元素的性能得到进一步提升。 + m_map.emplace(std::move(strMsgType), std::forward(f)); + + cout << "register message: " << strMsgType << endl; + } + +private: + + std::multimap m_map; //存储注册的消息 + typedef std::multimap::iterator Iterator; + +}; + +#endif //CPP_START_MESSAGE_BUS_H diff --git a/src/ioc/container.h b/src/ioc/container.h new file mode 100644 index 0000000..eef4e6a --- /dev/null +++ b/src/ioc/container.h @@ -0,0 +1,107 @@ + +#ifndef CPP_START_CONTAINER_H +#define CPP_START_CONTAINER_H + +#include +#include "../base/any.h" +#include "../base/non_copy_able.h" + +#include +#include +#include +#include + +using namespace std; + +class IocContainer : NonCopyAble { +public: + IocContainer() {} + + ~IocContainer() {} + + // 注册需要创建对象的构造函数 + template + void RegisterType(const string &strKey) { + // 注意,这里创建的是依赖的对象!不再是创建对象! + // 通过闭包擦除了Depend参数类型 + std::function function = [](Args... args) { return new T(new Depend(args...)); }; + RegisterType(strKey, function); + } + + // 根据唯一标识查找对应的构造函数,并创建指针对象 + template + T *Resolve(const string &strKey, Args... args) { + if (m_creatorMap.find(strKey) == m_creatorMap.end()) { + return nullptr; + } + + Any resolver = m_creatorMap[strKey]; + // 将查找到的Any转换为function + std::function function = resolver.AnyCast>(); + + return function(args...); + } + + // 创建智能指针对象 + template + std::shared_ptr ResolveShared(const string &strKey, Args... args) { + T *ptr = Resolve(strKey, args...); + return std::shared_ptr(ptr); + } + + void RegisterType(const string &strKey, Any constructor) { + if (m_creatorMap.find(strKey) != m_creatorMap.end()) { + throw std::invalid_argument("this key has already exist!"); + } + // 通过Any擦除不同类型的构造器 + m_creatorMap.emplace(strKey, constructor); + } + +private: + unordered_map m_creatorMap; +}; + + +/* +class Container : NonCopyAble { + +private: + std::unordered_map mCreatorMap; + +public: + Container() {}; + + ~Container() {}; + + template + void registerType(const std::string &key) { + std::function func = [](Args... args) { + return new T(new Depend(args...)); + }; + registerType(key, func); + } + + template + T *resolve(const std::string &key, Args ... args) { + if (mCreatorMap.find(key) == mCreatorMap.end()) { + return nullptr; + } + Any constructor = mCreatorMap[key]; + std::function function = constructor.cast>(); + return function(args...); + } + +private: + void registerType(const std::string &key, Any constructor) { + auto it = mCreatorMap.find(key); + auto end = mCreatorMap.end(); + if (mCreatorMap.find(key) != mCreatorMap.end()) { + // TODO 多次添加 + throw std::invalid_argument("this key has aleady exist!"); + } + mCreatorMap.emplace(key, constructor); + } + +}; +*/ +#endif //CPP_START_CONTAINER_H diff --git a/src/main.cpp b/src/main.cpp index c038eb8..aafcb3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,133 +1,6 @@ #include -#include #include -template -class iterator { -public: - using value_type = T; - using size_type = size_t; - -private: - size_type cursor_; - const value_type step_; - value_type value_; - -public: - - iterator(size_type cur_satrt, value_type begin_val, value_type step_val) - : - cursor_(cur_satrt), - step_(step_val), - value_(begin_val) { - - }; - - value_type operator*() const { - return value_; - }; - - bool operator!=(const iterator &rhs) const { - return (cursor_ != rhs.cursor_); - }; - - iterator *operator++() { - value_ += step_; - ++cursor_; - return (*this); - }; -}; - - -void foreach() { - std::map mm = { - {"a", 1}, - {"b", 2}, - {"c", 3} - }; - - for (const auto &m: mm) { - std::cout << m.first << " -> " << m.second << std::endl; - } -} - -int g_constructCount = 0; -int g_copy_constructCount = 0; -int g_destructCount = 0; - -class A { - -public: - A() { - std::cout << "construct: " << ++g_constructCount << std::endl; - } - - A(const A &a) { - std::cout << "copy construct: " << ++g_copy_constructCount << std::endl; - } - - ~A() { - std::cout << "destruct: " << ++g_destructCount << std::endl; - } - -}; - -A getA() { - return A{}; -} - - -template -struct GetLeftSize : std::integral_constant { - -}; - -template -void f(T ... args) { - std::cout << sizeof...(args) << std::endl; -} - - -template -void expand(T ... args) { - std::initializer_list{(std::cout << args << std::endl, 0)...}; -} - -template -auto Func(F f, Arg arg) -> decltype(f(arg)) { - return f(arg); -} - - -template -auto GroupBy(const std::vector &vt, Fn &&keySelector) --> std::multimap -{ -typedef decltype(keySelector(*(Arg * ) nullptr)) -key_type; -std::multimap map; -std::for_each(vt -. - -begin(), vt - -. - -end(), - -[&]( -const Arg &arg -){ -map. -insert(make_pair(keySelector(arg), arg) -); -}); -return -map; -} - std::mutex g_lock; void func() { @@ -135,15 +8,31 @@ void func() { std::this_thread::sleep_for(std::chrono::seconds(2)); } +void thread_test() { + auto start = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); + std::cout << "start time: " << start / 1000 << std::endl; + std::thread t0(func); + std::thread t1(func); + std::thread t2(func); + t0.join(); // 阻塞执行 + t1.detach(); // 分离线程何对象,之后就无法何线程发送联系 + t2.join(); + auto end = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); + std::cout << " end time: " << end / 1000 << std::endl; +} + #include "base/sync_queue.h" -void sync_test(){ + +void sync_test() { // 同步队列 auto queue = new SyncQueue(3); // 每2秒取出进行消费 - std::thread producer([&](){ + std::thread producer([&]() { int i = 0; - while (i < 9){ + while (i < 9) { queue->dequeue(i); std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "dequeue: " << i << std::endl; @@ -151,7 +40,7 @@ void sync_test(){ }); // 持续写入 - std::thread consumer([&](){ + std::thread consumer([&]() { for (int i = 0; i < 10; ++i) { queue->enqueue(i); std::cout << "enqueue: " << i << std::endl; @@ -162,59 +51,59 @@ void sync_test(){ consumer.join(); } - #include #include #include "util/stop_watch.h" -void chrono_test(){ +void chrono_test() { StopWatch stopWatch; std::chrono::minutes t1(10); std::chrono::seconds t2(60); std::chrono::seconds t3 = t1 - t2; - std::cout << "duration time: " << t3.count() << std::endl; + std::cout << "duration time: " << t3.count() << std::endl; std::cout << "\ncost time: " << stopWatch.elapsed() << " us\n" << std::endl; std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); // 将 time_point 转为 ctime std::time_t last = std::chrono::system_clock::to_time_t(now - std::chrono::hours(24)); - std::time_t next = std::chrono::system_clock::to_time_t(now + std::chrono::hours (24)); + std::time_t next = std::chrono::system_clock::to_time_t(now + std::chrono::hours(24)); // 使用put_time格式化时间 std::cout - << "One day ago, the time was " - << std::put_time(std::localtime(&last), "%F %T") - << "\n" - << "NExt day ago, the time is " - << std::put_time(std::localtime(&next), "%F %T") + << "One day ago, the time was " + << std::put_time(std::localtime(&last), "%F %T") + << "\n" + << "NExt day ago, the time is " + << std::put_time(std::localtime(&next), "%F %T") - << std::endl; + << std::endl; - std::cout << "\ncost time: " << stopWatch.elapsed() << " ms\n" << std::endl; + std::cout << "\ncost time: " << stopWatch.elapsed() << " ms\n" << std::endl; } #include "base/thread_pool.h" -void thread_test(){ - ThreadPool pool(3,10); - std::thread t0([&pool]{ +void threadpool_test() { + ThreadPool pool(3, 10); + + std::thread t0([&pool] { for (int i = 0; i < 100; ++i) { auto thdId = std::this_thread::get_id(); - pool.add([thdId]{ - std::cout << "thread 1 id:" << thdId << std::endl; + pool.add([thdId] { + std::cout << "thread 1 id:" << thdId << std::endl; }); } }); - std::thread t1([&pool]{ + std::thread t1([&pool] { for (int i = 0; i < 100; ++i) { auto thdId = std::this_thread::get_id(); - pool.add([thdId]{ - std::cout << "thread 2 id:" << thdId << std::endl; + pool.add([thdId] { + std::cout << "thread 2 id:" << thdId << std::endl; }); } }); @@ -227,24 +116,24 @@ void thread_test(){ t1.join(); } - #include "aspect/aspect.h" #include "test/time_elapsed_aspect.h" #include "test/log_aspect.h" -void HT(int a) -{ + +void HT(int a) { std::cout << "real HT function " << a << std::endl; } -void aop_test(){ + +void aop_test() { using namespace std; - aop([](int a){ - std::thread t([a](){ + aop([](int a) { + std::thread t([a]() { std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "run function, arg is " << a << std::endl; }); t.join(); - }, 1); + }, 1); cout << endl; @@ -252,41 +141,140 @@ void aop_test(){ aop(f, 100); } -int main() { - // 同步队列测试 -// sync_test(); - // 时间工具测试 -// chrono_test(); - // 线程池测试 -// thread_test(); - // AOP测试 - aop_test(); +#include "base/any.h" + +void any_test() { + Any n; + auto r = n.IsNull();//true + string s1 = "hello"; + n = s1; + n = "world"; + n.AnyCast(); //can not cast int to string + Any n1 = 1; + n1.Is(); //true +} + +#include "ioc/container.h" + +void ioc_test() { + + struct Base { + virtual ~Base() = default; + + virtual void Func() = 0; + }; + + struct DerivedB : public Base { + DerivedB(int a, double b) : m_a(a), m_b(b) { + } + + ~DerivedB() override = default; + + void Func() override { + cout << "DerivedB run :" << m_a + m_b << endl; + } + + private: + int m_a; + double m_b; + }; + + struct DerivedC : public Base { + ~DerivedC() override = default; + + void Func() override { + std::cout << "DerivedC " << std::endl; + }; + }; + + struct A { + A(Base *ptr) : m_ptr(ptr) { + } + + ~A() { + if (m_ptr != nullptr) { + delete m_ptr; + m_ptr = nullptr; + } + } + + void Func() { + m_ptr->Func(); + } + + private: + Base *m_ptr; + }; + + IocContainer ioc; + + // TODO 可通过CRTP奇怪的重复模板模式进行自动注册 -// auto start = std::chrono::duration_cast( -// std::chrono::system_clock::now().time_since_epoch()).count(); -// std::cout << "start time: " << start / 1000 << std::endl; -// std::thread t0(func); -// std::thread t1(func); -// std::thread t2(func); -// t0.join(); // 阻塞执行 -// t1.detach(); // 分离线程何对象,之后就无法何线程发送联系 -// t2.join(); -// auto end = std::chrono::duration_cast( -// std::chrono::system_clock::now().time_since_epoch()).count(); -// std::cout << " end time: " << end / 1000 << std::endl; - -// A&& a = getA(); -// -// expand(1,2,3,4); -// -// std::cout << GetLeftSize::value << std::endl; -// -// f(); -// f(1); -// f(1,2.5,""); -// -// foreach(); + // 注册依赖关系 + ioc.RegisterType("C"); + ioc.RegisterType("B"); + + // 通过容器进行初始化 + auto pc = ioc.ResolveShared("C"); + // 注意DerivedB的参数int,double + auto pb = ioc.ResolveShared("B", 1, 2.0); + + pc->Func(); + pb->Func(); +} +#include "bus/message_bus.h" + +void message_test() { + MessageBus bus; + //注册消息 + bus.Attach([](int a) { cout << "no reference: " << a << endl; }); + bus.Attach([](int &a) { cout << "lvalue reference: " << a << endl; }); + bus.Attach([](int &&a) { cout << "rvalue reference: " << a << endl; }); + bus.Attach([](const int &a) { cout << "const lvalue reference: " << a << endl; }); + bus.Attach([](int a) { + cout << "no reference has return value and key: " << a << endl; + return a; + }, "a"); + + int i = 2; + bus.SendReq(2); + bus.SendReq(2, "a"); + bus.SendReq(i); + bus.SendReq(2); + bus.SendReq(2); + + bus.Remove(); + bus.Remove("a"); + bus.Remove(); + bus.Remove(); + bus.Remove(); + + bus.SendReq(2); + bus.SendReq(2, "a"); + bus.SendReq(i); + bus.SendReq(2); + bus.SendReq(2); + +} + +int main() { +// 线程测试 + thread_test(); +// 同步队列测试 + sync_test(); +// 时间工具测试 + chrono_test(); +// 线程池测试 + threadpool_test(); +// AOP测试 + aop_test(); +// Any测试 + any_test(); +// IoC测试 + ioc_test(); +// 总线测试 + message_test(); return 0; } \ No newline at end of file