Skip to content

Commit cd10352

Browse files
committed
- Initial commit
0 parents  commit cd10352

File tree

19 files changed

+809
-0
lines changed

19 files changed

+809
-0
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CMakeLists.txt.user
2+
CMakeCache.txt
3+
CMakeFiles
4+
CMakeScripts
5+
Testing
6+
Makefile
7+
cmake_install.cmake
8+
install_manifest.txt
9+
compile_commands.json
10+
CTestTestfile.cmake
11+
_deps
12+
.idea/
13+
lib/*.a
14+
bin/
15+
patterns.cbp
16+
test/gtest

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "lib/googletest"]
2+
path = lib/googletest
3+
url = https://github.com/google/googletest.git

CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
cmake_minimum_required(VERSION 3.9)
2+
project(patterns)
3+
set(CMAKE_ROOT_)
4+
5+
set(CMAKE_CXX_STANDARD 17)
6+
set(CMAKE_CXX_EXTENSIONS OFF)
7+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
8+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
9+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
10+
11+
include_directories(include)
12+
13+
add_subdirectory(lib/googletest)
14+
add_subdirectory(test)
15+
16+
option(USE_CLANG "Build using Clang++" ON)
17+
if (USE_CLANG)
18+
set(CMAKE_CXX_COMPILER clang++)
19+
endif(USE_CLANG)

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Design Patterns C++17
2+
3+
Design Patterns Headers-only Library for C++17
4+
5+
6+
## Build
7+
8+
git clone --recurse-submodules http://github.com/svdev/design-patterns-cpp17
9+
cd design-patterns-cpp17
10+
cmake -G "Unix Makefiles" .
11+
make
12+
13+
14+
## Test
15+
16+
make check
17+
18+
19+
## Author
20+
21+
svdev - http://github.com/svdev

include/behavioral/observer.hpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#ifndef DESIGN_PATTERN_OBSERVER_HPP
2+
#define DESIGN_PATTERN_OBSERVER_HPP
3+
4+
#include <iostream>
5+
#include <memory>
6+
#include <vector>
7+
8+
namespace design_patterns {
9+
namespace behavioral {
10+
11+
template<typename... _NotificationTypes>
12+
class observer;
13+
14+
template<typename _NotificationType>
15+
class observer<_NotificationType> {
16+
public:
17+
virtual void handle(_NotificationType& notification) = 0;
18+
};
19+
20+
template<typename _N, typename... _NotificationTypes>
21+
class observer<_N, _NotificationTypes...> : public observer<_NotificationTypes...>{
22+
public:
23+
using observer<_NotificationTypes...>::handle;
24+
virtual void handle(_N& notification) = 0;
25+
};
26+
27+
template <typename _TObserver>
28+
class observable {
29+
public:
30+
typedef std::weak_ptr<_TObserver> observer_weak_ptr;
31+
32+
~observable() {}
33+
34+
/**
35+
* Add an observer to the list.
36+
* @param observer
37+
*/
38+
void add_observer(std::shared_ptr<_TObserver>& observer)
39+
{
40+
for (const auto& o : observers)
41+
if (o.lock() == observer)
42+
return;
43+
observer_weak_ptr wo(observer);
44+
observers.push_back(wo);
45+
}
46+
47+
/**
48+
* Remove a particular observer from the list.
49+
* @param observer
50+
*/
51+
void remove_observer(const observer_weak_ptr& observer)
52+
{
53+
for(auto it = observers.begin(); it!=observers.end(); ++it) {
54+
auto ptr = (*it).lock();
55+
if (ptr == observer.lock()) {
56+
observers.erase(it);
57+
return;
58+
}
59+
}
60+
}
61+
62+
/**
63+
* Clear all observers from the list.
64+
*/
65+
void clear_observers() { observers.clear(); }
66+
67+
/**
68+
* Returns the number of observers.
69+
* @return
70+
*/
71+
std::size_t count_observers() const { return observers.size(); }
72+
73+
/**
74+
* Notify all of the observers, sending them the notification.
75+
* TNotification is the notification type.
76+
* @tparam _TNotification
77+
* @param notification
78+
*/
79+
template<typename _NotificationType>
80+
void notify(_NotificationType& notification)
81+
{
82+
auto it = observers.begin();
83+
while(it!=observers.end()) {
84+
auto ptr = (*it).lock();
85+
if(ptr) {
86+
ptr->handle(notification);
87+
it++;
88+
} else {
89+
it = observers.erase(it);
90+
}
91+
}
92+
}
93+
94+
private:
95+
/// The list of observers.
96+
std::vector<observer_weak_ptr> observers;
97+
98+
};
99+
100+
/**
101+
* Observer factory method
102+
* @tparam T Observer type
103+
* @tparam Args Observer constructor arguments types
104+
* @param args Observer arguments
105+
* @return Observer instance
106+
*/
107+
template <typename T, typename... Args>
108+
static std::shared_ptr<T> make_observer(Args&& ...args)
109+
{
110+
//@TODO: Check T is derived from observer<N...>
111+
return std::make_shared<T>(std::forward<Args>(args)...);
112+
}
113+
114+
}
115+
}
116+
#endif // DESIGN_PATTERN_OBSERVER_HPP

include/behavioral/visitor.hpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#ifndef DESIGN_PATTERN_VISITOR_HPP
2+
#define DESIGN_PATTERN_VISITOR_HPP
3+
4+
#include <memory>
5+
6+
namespace design_patterns {
7+
namespace behavioral {
8+
9+
10+
template<typename... Types>
11+
class visitor;
12+
13+
template<typename T>
14+
class visitor<T> {
15+
public:
16+
virtual void visit(T & visitable) = 0;
17+
};
18+
19+
20+
template<typename T, typename... Types>
21+
class visitor<T, Types...> : public visitor<Types...> {
22+
public:
23+
using visitor<Types...>::visit;
24+
virtual void visit(T & visitable) = 0;
25+
};
26+
27+
template<typename Derived, typename... Types>
28+
class visitable {
29+
public:
30+
typedef visitor<Types...>& visitor_type;
31+
virtual void accept(visitor<Types...>& visitor) {
32+
visitor.visit(static_cast<Derived&>(*this));
33+
}
34+
};
35+
36+
/**
37+
template<typename Derived, typename... Types>
38+
class VisitableImpl : public Visitable<Types...> {
39+
public:
40+
typedef Visitor<Types...>& VisitorType;
41+
virtual void accept(Visitor<Types...>& visitor) {
42+
visitor.visit(static_cast<Derived&>(*this));
43+
}
44+
};
45+
*/
46+
47+
template <typename T, typename... Args>
48+
static std::shared_ptr<T> make_visitor(Args&& ...args)
49+
{
50+
//@TODO: Check T is derived from visitor<Types...>
51+
return std::make_shared<T>(std::forward<Args>(args)...);
52+
}
53+
54+
}
55+
}
56+
57+
#endif //DESIGN_PATTERN_VISITOR_HPP

include/creational/factory.hpp

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#ifndef DESIGN_PATTERN_FACTORY_HPP
2+
#define DESIGN_PATTERN_FACTORY_HPP
3+
4+
#include <memory>
5+
#include <map>
6+
#include <iostream>
7+
#include <typeinfo>
8+
#include <cxxabi.h>
9+
10+
#include "util/color.hpp"
11+
#include "exception.hpp"
12+
13+
namespace design_patterns {
14+
namespace creational {
15+
16+
class factory_exception : public design_pattern_exception {
17+
public:
18+
explicit factory_exception(const std::string& msg):design_pattern_exception(msg) { };
19+
};
20+
21+
class factory_create_exception : public factory_exception {
22+
public:
23+
explicit factory_create_exception(const std::string& tag) :
24+
factory_exception("Unknown type under name '" + tag + "'"){};
25+
};
26+
27+
template<class BaseType, class... Args>
28+
struct map_holder {
29+
static std::map<std::string,
30+
std::unique_ptr<BaseType>(*)(Args&& ...)> functions;
31+
};
32+
33+
template<class BaseType, class... Args>
34+
std::map<std::string, std::unique_ptr<BaseType>(*)(Args&& ...)>map_holder<
35+
BaseType,
36+
Args...>::functions;
37+
38+
template<class T>
39+
class factory {
40+
public:
41+
42+
factory(const factory&) = default;
43+
void operator=(factory const&) = delete;
44+
45+
static factory& get_instance()
46+
{
47+
static factory instance;
48+
return instance;
49+
}
50+
51+
template<class ...Args>
52+
unsigned long registered() const
53+
{
54+
return map_holder<T, Args&& ...>::functions.size();
55+
}
56+
57+
const std::string name() const
58+
{
59+
return demangle(typeid(*this).name());
60+
}
61+
62+
template<class TDerived, typename ...Args>
63+
bool register_type(const std::string& name)
64+
{
65+
66+
if (map_holder<T, Args&& ...>::functions.count(name)==0) {
67+
68+
map_holder<T, Args&& ...>::functions[name] =
69+
&create_func<TDerived, Args...>;
70+
71+
std::cout << "[OK]: " << (*this).name() << ": "
72+
<< FBLU(demangle(typeid(TDerived).name()))
73+
<< " type registered under name " << FGRN(name)
74+
<< std::endl;
75+
/**
76+
std::cout << "Ptr: "
77+
<< &MapHolder<T, Args...>::functions[name]
78+
<< std::endl;
79+
*/
80+
return true;
81+
}
82+
83+
std::cout << "[ERROR]: Type already registered: " << name <<
84+
std::endl;
85+
return false;
86+
}
87+
/**
88+
* Create instance by a registered name
89+
* @param name The name of the registered class type
90+
* @return An instance of the requested class name, or null if not
91+
* found.
92+
*/
93+
template<typename ...Args>
94+
std::unique_ptr<T> create(const std::string& name, Args&& ...args)
95+
{
96+
try {
97+
auto el = map_holder<T, Args&& ...>::functions.at(name);
98+
return el(std::forward<Args>(args)...);
99+
}
100+
catch (std::exception& ex) {
101+
throw factory_create_exception(name);
102+
}
103+
/**
104+
auto it = MapHolder<T, Args&&...>::functions.find(name);
105+
if (it!=MapHolder<T, Args&&...>::functions.end()) {
106+
std::cout << "[OK] factory::create() " << name << std::endl;
107+
std::cout << "Ptr: " << &(*it).second << std::endl;
108+
return (*it).second(std::forward<Args>(args)...);
109+
}
110+
std::cout << "[ERROR]: factory::create() " << name << std::endl;
111+
return std::unique_ptr<T>(nullptr);
112+
*/
113+
}
114+
protected:
115+
static const std::string demangle(const char* name)
116+
{
117+
int status = -4;
118+
char* res = abi::__cxa_demangle(name, nullptr, nullptr, &status);
119+
const char* const demangled_name = (status==0) ? res : name;
120+
std::string ret_val(demangled_name);
121+
free(res);
122+
return ret_val;
123+
}
124+
125+
private:
126+
factory() = default;
127+
128+
template<class TDerived, typename ...Args>
129+
static std::unique_ptr<T> create_func(Args&& ...args)
130+
{
131+
std::cout << "[INFO]: factory::create_func() "
132+
<< typeid(TDerived).name() << std::endl;
133+
return std::make_unique<TDerived>(std::forward<Args>(args)...);
134+
}
135+
136+
};
137+
138+
template<typename T, typename ...Args>
139+
std::unique_ptr<T> make(const std::string& name, Args&& ...args)
140+
{
141+
auto fac = factory<T>::get_instance();
142+
return fac.create(name, std::forward<Args>(args)...);
143+
}
144+
145+
}
146+
}
147+
148+
#endif //DESIGN_PATTERN_FACTORY_HPP

0 commit comments

Comments
 (0)