Skip to content

Commit b0db226

Browse files
xiao chengxiao cheng
xiao cheng
authored and
xiao cheng
committed
add two more patterns
1 parent 3681800 commit b0db226

File tree

6 files changed

+283
-0
lines changed

6 files changed

+283
-0
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ if(Boost_FOUND)
1515
add_subdirectory(Singleton)
1616
add_subdirectory(DependencyInjection)
1717
add_subdirectory(BuildPattern)
18+
add_subdirectory(Proto)
19+
add_subdirectory(ObjectPool)
1820
endif()

ObjectPool/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(ObjectPool)
4+
5+
include_directories(${Boost_INCLUDE_DIRS})
6+
7+
add_executable(${PROJECT_NAME} ObjectPool.hpp main.cpp)
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)

ObjectPool/ObjectPool.hpp

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include <functional>
2+
#include <iostream>
3+
#include <memory>
4+
#include <stack>
5+
#include <tuple>
6+
7+
using namespace std;
8+
9+
class IPoolableObject
10+
{
11+
public:
12+
virtual ~IPoolableObject() = default;
13+
virtual void reset() = 0;
14+
15+
protected:
16+
IPoolableObject() = default;
17+
};
18+
19+
class UsedObject : public IPoolableObject
20+
{
21+
public:
22+
UsedObject(int init_num = 0) : _num{init_num}, _init_num{init_num} {};
23+
void increment() { ++_num; }
24+
25+
void print() { std::cout << "My number is: " << _num << std::endl; }
26+
void reset() override { _num = _init_num; }
27+
28+
private:
29+
int _num;
30+
int _init_num;
31+
};
32+
33+
// parameter pack , can accept any number of arguments
34+
// Variadic templates
35+
template <typename T, typename... Args>
36+
class ObjectPool
37+
{
38+
public:
39+
template <typename P>
40+
using pointer_type = std::unique_ptr<P, std::function<void(P *)>>;
41+
42+
ObjectPool(std::size_t init_size = 0, std::size_t max_size = 10, Args &&... args)
43+
: _max_size{max_size}, _available{max_size}, _size{0}, _args{args...} // store pack parameter into tuples for later use
44+
{
45+
static_assert(std::is_base_of<IPoolableObject, T>::value, "Must be poolable object");
46+
initialize(init_size);
47+
}
48+
49+
pointer_type<T> get()
50+
{
51+
if (_pool.empty())
52+
{
53+
if (_available == 0)
54+
{
55+
return nullptr;
56+
}
57+
add();
58+
}
59+
--_available;
60+
auto inst = std::move(_pool.top());
61+
_pool.pop();
62+
return std::move(inst);
63+
}
64+
65+
std::size_t free() { return _available; }
66+
std::size_t max_size() { return _max_size; }
67+
std::size_t size() { return _size; }
68+
bool empty() { return _pool.empty(); }
69+
70+
private:
71+
// Adds a new object to the pool
72+
void add(T *ptr = nullptr)
73+
{
74+
if (ptr == nullptr)
75+
{
76+
ptr = create_with_params(std::index_sequence_for<Args...>());
77+
++_size;
78+
}
79+
else
80+
{
81+
ptr->reset();
82+
++_available;
83+
}
84+
85+
pointer_type<T> inst(ptr, [this](T *ptr) {
86+
// This is the custom deleter of the unique_ptr.
87+
// When the object is deleted in the callers context, it will be
88+
// returned back to the pool by utilizing the add function
89+
add(ptr);
90+
});
91+
92+
_pool.push(std::move(inst));
93+
}
94+
95+
template <std::size_t... Is>
96+
T *create_with_params(const std::index_sequence<Is...> &)
97+
{
98+
return new T(std::get<Is>(_args)...);
99+
}
100+
101+
// Initializes the pool
102+
void initialize(std::size_t init_size)
103+
{
104+
for (std::size_t i = 0; i < init_size; ++i)
105+
{
106+
add();
107+
}
108+
}
109+
110+
std::size_t _max_size;
111+
std::size_t _available;
112+
std::size_t _size;
113+
std::stack<pointer_type<T>> _pool;
114+
std::tuple<Args...> _args;
115+
};

ObjectPool/main.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "ObjectPool.hpp"
2+
#include <cassert>
3+
#include <iostream>
4+
5+
int main() {
6+
ObjectPool<UsedObject, int> pool(0, 2, 5);
7+
std::cout << "Initialized object pool with max size of " << pool.max_size() << std::endl;
8+
std::cout << "Size of the pool: " << pool.size() << std::endl;
9+
std::cout << "Available objects: " << pool.free() << std::endl;
10+
11+
auto inst = pool.get();
12+
inst->increment();
13+
inst->print();
14+
15+
std::cout << "Available objects: " << pool.free() << std::endl;
16+
std::cout << "Size of the pool: " << pool.size() << std::endl;
17+
{
18+
auto inst2 = pool.get();
19+
inst->increment();
20+
inst->print();
21+
std::cout << "Instance 2 pointer is " << inst2.get() << std::endl;
22+
std::cout << "Available objects: " << pool.free() << std::endl;
23+
std::cout << "Size of the pool: " << pool.size() << std::endl;
24+
}
25+
26+
std::cout << "Available objects: " << pool.free() << std::endl;
27+
std::cout << "Size of the pool: " << pool.size() << std::endl;
28+
auto inst2 = pool.get();
29+
std::cout << "Instance 2 pointer is " << inst2.get() << std::endl;
30+
31+
auto inst3 = pool.get();
32+
assert(inst3 == nullptr);
33+
assert(pool.empty());
34+
std::cout << "Pool is empty, all objects are in use" << std::endl;
35+
}

Proto/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(Proto)
4+
5+
include_directories(${Boost_INCLUDE_DIRS})
6+
7+
add_executable(${PROJECT_NAME} Proto.cpp)
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)

Proto/Proto.cpp

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#include <iostream>
2+
#include <vector>
3+
#include <algorithm>
4+
#include <functional>
5+
6+
using namespace std;
7+
const int N = 4;
8+
9+
// Prototype
10+
class Document
11+
{
12+
public:
13+
virtual Document *clone() const = 0;
14+
virtual void store() const = 0;
15+
virtual ~Document() {}
16+
};
17+
18+
// Concrete prototypes : xmlDoc, plainDoc, spreadsheetDoc
19+
20+
class xmlDoc : public Document
21+
{
22+
public:
23+
Document *clone() const { return new xmlDoc; }
24+
void store() const { cout << "xmlDoc\n"; }
25+
};
26+
27+
class plainDoc : public Document
28+
{
29+
public:
30+
Document *clone() const { return new plainDoc; }
31+
void store() const { cout << "plainDoc\n"; }
32+
};
33+
34+
class spreadsheetDoc : public Document
35+
{
36+
public:
37+
Document *clone() const { return new spreadsheetDoc; }
38+
void store() const { cout << "spreadsheetDoc\n"; }
39+
};
40+
41+
// makeDocument() calls Concrete Portotype's clone() method
42+
// inherited from Prototype
43+
class DocumentManager
44+
{
45+
public:
46+
static Document *makeDocument(int choice);
47+
~DocumentManager() {}
48+
49+
private:
50+
static Document *mDocTypes[N];
51+
};
52+
53+
Document *DocumentManager::mDocTypes[] =
54+
{
55+
0, new xmlDoc, new plainDoc, new spreadsheetDoc};
56+
57+
Document *DocumentManager::makeDocument(int choice)
58+
{
59+
return mDocTypes[choice]->clone();
60+
}
61+
62+
// for_each op ()
63+
struct Destruct
64+
{
65+
void operator()(Document *a) const
66+
{
67+
delete a;
68+
}
69+
};
70+
71+
// Client
72+
int main()
73+
{
74+
vector<Document *> docs(N);
75+
int choice;
76+
cout << "quit(0), xml(1), plain(2), spreadsheet(3): \n";
77+
while (true)
78+
{
79+
cout << "Type in your choice (0-3)\n";
80+
cin >> choice;
81+
if (choice <= 0 || choice >= N)
82+
break;
83+
docs[choice] = DocumentManager::makeDocument(choice);
84+
}
85+
86+
for (int i = 1; i < docs.size(); ++i)
87+
if (docs[i])
88+
docs[i]->store();
89+
90+
Destruct d;
91+
// this calls Destruct::operator()
92+
for_each(docs.begin(), docs.end(), d);
93+
94+
return 0;
95+
}

0 commit comments

Comments
 (0)