Skip to content

Commit 683ba02

Browse files
xiao chengxiao cheng
xiao cheng
authored and
xiao cheng
committed
update delegation pattern
1 parent 96ed5e2 commit 683ba02

File tree

7 files changed

+558
-0
lines changed

7 files changed

+558
-0
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ if(Boost_FOUND)
2323
add_subdirectory(Adaptor)
2424
add_subdirectory(Bridge)
2525
add_subdirectory(Composite)
26+
add_subdirectory(Delegation)
2627
endif()

Delegation/CMakeLists.txt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
3+
project(Delegation)
4+
5+
include_directories(${Boost_INCLUDE_DIRS})
6+
7+
add_executable(${PROJECT_NAME} Delegate.hpp Dispatcher.hpp FunctionDispatcher.hpp main.cpp Utils.hpp)
8+
9+
target_link_libraries(${PROJECT_NAME} PUBLIC
10+
gtest_main
11+
${Boost_LIBRARIES}
12+
)
13+
14+
add_test(
15+
NAME ${PROJECT_NAME}
16+
COMMAND ${PROJECT_NAME}
17+
)
18+
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ../bin)

Delegation/Delegate.hpp

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#pragma once
2+
3+
#include <memory>
4+
5+
// instead of passing function pointer, passing wrapper
6+
template <typename T>
7+
class Delegate;
8+
9+
template <typename Ret, typename... Args>
10+
class Delegate<Ret(Args...)>
11+
{
12+
using CallbackType = Ret (*)(std::shared_ptr<void>, Args...);
13+
14+
public:
15+
// object member function
16+
template <typename T, Ret (T::*funcPtr)(Args...)>
17+
static Delegate create(std::shared_ptr<T> obj)
18+
{
19+
return Delegate{obj, &memberCaller<T, funcPtr>};
20+
}
21+
22+
template <Ret (*funcPtr)(Args...)>
23+
static Delegate create()
24+
{
25+
// global function has no class, hence it is nullptr
26+
return Delegate{nullptr, &globalCaller<funcPtr>};
27+
}
28+
29+
// can be functors, lambdas, std::function objects.
30+
template <typename T>
31+
static Delegate create(std::shared_ptr<T> t)
32+
{
33+
return Delegate{t, &functorCaller<T>};
34+
}
35+
36+
Ret operator()(Args... args)
37+
{
38+
return callback(callee, args...);
39+
}
40+
41+
bool operator==(const Delegate &other)
42+
{
43+
return callee == other.callee && callback == other.callback;
44+
}
45+
46+
private:
47+
std::shared_ptr<void> callee{nullptr};
48+
CallbackType callback{nullptr};
49+
50+
private:
51+
Delegate(std::shared_ptr<void> obj, CallbackType funcPtr) : callee{obj}, callback{funcPtr}
52+
{
53+
}
54+
55+
template <typename T, Ret (T::*funcPtr)(Args...)>
56+
static Ret memberCaller(std::shared_ptr<void> callee, Args... args)
57+
{
58+
return (static_cast<T *>(callee.get())->*funcPtr)(args...);
59+
}
60+
61+
template <Ret (*funcPtr)(Args...)>
62+
static Ret globalCaller(std::shared_ptr<void>, Args... args)
63+
{
64+
return funcPtr(args...);
65+
}
66+
67+
template <typename T>
68+
static Ret functorCaller(std::shared_ptr<void> functor, Args... args)
69+
{
70+
return (*static_cast<T *>(functor.get()))(args...);
71+
}
72+
};

Delegation/Dispatcher.hpp

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include "Delegate.hpp"
5+
6+
template <typename T>
7+
class Dispatcher;
8+
9+
template <typename Ret, typename... Args>
10+
class Dispatcher<Ret(Args...)>
11+
{
12+
public:
13+
// for global function
14+
template <Ret (*funcPtr)(Args...)>
15+
bool add()
16+
{
17+
return add(Delegate<Ret(Args...)>::template create<funcPtr>());
18+
}
19+
20+
template <Ret (*funcPtr)(Args...)>
21+
bool remove()
22+
{
23+
return remove(Delegate<Ret(Args...)>::template create<funcPtr>());
24+
}
25+
26+
// for class member function
27+
template <typename T, Ret (T::*funcPtr)(Args...)>
28+
bool add(std::shared_ptr<T> obj)
29+
{
30+
return add(Delegate<Ret(Args...)>::template create<T, funcPtr>(obj));
31+
}
32+
33+
template <typename T, Ret (T::*funcPtr)(Args...)>
34+
bool remove(std::shared_ptr<T> obj)
35+
{
36+
return remove(Delegate<Ret(Args...)>::template create<T, funcPtr>(obj));
37+
}
38+
39+
// can be functors, lambdas, std::function objects.
40+
template <typename T>
41+
bool add(std::shared_ptr<T> t)
42+
{
43+
return add(Delegate<Ret(Args...)>::template create(t));
44+
}
45+
46+
template <typename T>
47+
bool remove(std::shared_ptr<T> t)
48+
{
49+
return remove(Delegate<Ret(Args...)>::template create(t));
50+
}
51+
52+
void operator()(Args... args)
53+
{
54+
for (auto &delegate : delegates)
55+
{
56+
delegate(args...);
57+
};
58+
}
59+
60+
bool add(Delegate<Ret(Args...)> delegate)
61+
{
62+
if (find(delegates.begin(), delegates.end(), delegate) != delegates.end())
63+
{
64+
return false;
65+
}
66+
67+
delegates.push_back(delegate);
68+
69+
return true;
70+
}
71+
72+
bool remove(Delegate<Ret(Args...)> delegate)
73+
{
74+
auto it = find(delegates.begin(), delegates.end(), delegate);
75+
if (it == delegates.end())
76+
{
77+
return false;
78+
}
79+
80+
delegates.erase(it);
81+
82+
return true;
83+
}
84+
85+
private:
86+
std::vector<Delegate<Ret(Args...)>> delegates;
87+
};

Delegation/FunctionDispatcher.hpp

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#pragma once
2+
3+
#include <functional>
4+
#include <type_traits>
5+
#include <memory>
6+
#include <string>
7+
#include <vector>
8+
9+
template <size_t>
10+
struct MyPlaceholder
11+
{
12+
};
13+
14+
namespace std
15+
{
16+
template <size_t N>
17+
struct is_placeholder<MyPlaceholder<N>> : public integral_constant<size_t, N>
18+
{
19+
};
20+
} // namespace std
21+
22+
template <typename T>
23+
class FunctionDispatcher;
24+
25+
template <typename Ret, typename... Args>
26+
class FunctionDispatcher<Ret(Args...)>
27+
{
28+
public:
29+
template <Ret (*funcPtr)(Args...)>
30+
bool add(const std::string &tag)
31+
{
32+
addImpl(tag, funcPtr);
33+
return true;
34+
}
35+
36+
template <typename T, Ret (T::*funcPtr)(Args...)>
37+
bool add(const std::string &tag, std::shared_ptr<T> obj)
38+
{
39+
addImpl(tag, bindImpl(obj.get(), funcPtr, std::index_sequence_for<Args...>{}));
40+
return true;
41+
}
42+
43+
template <typename T>
44+
bool add(const std::string &tag, std::shared_ptr<T> t)
45+
{
46+
addImpl(tag, *t.get());
47+
return true;
48+
}
49+
50+
bool remove(const std::string &tag)
51+
{
52+
auto it = find(tags.begin(), tags.end(), tag);
53+
if (it == tags.end())
54+
{
55+
return false;
56+
}
57+
58+
auto index{distance(tags.begin(), it)};
59+
tags.erase(it);
60+
61+
delegates.erase(delegates.begin() + index);
62+
63+
return true;
64+
}
65+
66+
void operator()(Args... args)
67+
{
68+
for (auto &delegate : delegates)
69+
{
70+
delegate(args...);
71+
};
72+
}
73+
74+
private:
75+
bool addImpl(const std::string &tag, std::function<Ret(Args...)> delegate)
76+
{
77+
if (find(tags.begin(), tags.end(), tag) != tags.end())
78+
{
79+
return false;
80+
}
81+
82+
delegates.push_back(delegate);
83+
tags.push_back(tag);
84+
85+
return true;
86+
}
87+
88+
template <typename T, size_t... Idx>
89+
std::function<Ret(Args...)> bindImpl(T *obj, Ret (T::*funcPtr)(Args...), std::index_sequence<Idx...>)
90+
{
91+
return std::bind(funcPtr, obj, getPlaceholder<Idx>()...);
92+
}
93+
94+
template <size_t N>
95+
MyPlaceholder<N + 1> getPlaceholder()
96+
{
97+
return {};
98+
}
99+
100+
private:
101+
std::vector<std::function<Ret(Args...)>> delegates;
102+
std::vector<std::string> tags;
103+
};

Delegation/Utils.hpp

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
#include <memory>
4+
#include <type_traits>
5+
#include <utility>
6+
7+
template <typename T, typename L = typename std::decay<T>::type>
8+
std::shared_ptr<L> make_shared_lambda(T &&t)
9+
{
10+
return std::make_shared<L>(std::forward<T>(t));
11+
}

0 commit comments

Comments
 (0)