-
Notifications
You must be signed in to change notification settings - Fork 1
/
resource_manager.cpp
134 lines (119 loc) · 2.98 KB
/
resource_manager.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>
#include <memory>
#include <vector>
#include <utility>
#include <tuple>
#include <algorithm>
#include <mutex>
template <
class K,
class V,
class KeyEquals = std::equal_to<K>
>
class SharedResourceManager
{
public:
template
<typename... Args>
std::shared_ptr<V> obtain(K key, Args&&... args)
{
std::lock_guard<std::mutex> lock(m_mutex);
auto it = std::find_if(
m_resources.begin(),
m_resources.end(),
[key, this](const value_type& iv)
{
return m_key_equals(std::get<0>(iv), key);
}
);
// Resource didn't exist. Allocate new one
// and own it by default
if (it == m_resources.end())
{
res_shared_ptr new_owned_resource = std::make_shared<V>(std::forward<Args>(args)...);
res_weak_ptr unowned_res = new_owned_resource;
m_resources.emplace_back(
std::make_tuple(
key,
new_owned_resource,
unowned_res
)
);
return new_owned_resource;
}
value_type& val = *it;
res_shared_ptr& result = std::get<1>(val);
// This resource is still owned by this manager!
if (result)
{
return result;
}
// Ok the resource isn't owned by this manager.
// Try to see if the weak pointer can be promoted
// ie. The object is still alive somewhere
res_weak_ptr& weak_res = std::get<2>(val);
result = weak_res.lock();
if (result)
{
// Re-acquisition of ownership was a success!
return result;
}
// Need to reallocate object. Weak pointer was invalid
result = std::make_shared<V>(std::forward<Args>(args)...);
weak_res = result;
return result;
}
// Give up ownership of the object
// corresponding to this key
void relinquish(K key)
{
std::lock_guard<std::mutex> lock(m_mutex);
auto it = std::find_if(
m_resources.begin(),
m_resources.end(),
[key, this](const value_type& iv)
{
return m_key_equals(std::get<0>(iv), key);
}
);
if (it != m_resources.end())
{
value_type& val = *it;
res_shared_ptr owned_ptr = std::get<1>(val);
owned_ptr.reset();
}
}
// Givup and release all memory to the object
// corresponding to this key
// However, if someone outside this manager is
// holding an active shared_ptr, the object
// will continue to survive
void unload(K key)
{
std::lock_guard<std::mutex> lock(m_mutex);
auto it = std::remove_if(
m_resources.begin(),
m_resources.end(),
[key, this](const value_type& iv)
{
return m_key_equals(std::get<0>(iv), key);
}
);
m_resources.erase(it, m_resources.end());
}
private:
using res_weak_ptr = std::weak_ptr<V>;
using res_shared_ptr = std::shared_ptr<V>;
using value_type = std::tuple<K, res_shared_ptr, res_weak_ptr>;
using collection_type = std::vector<value_type>;
collection_type m_resources;
std::mutex m_mutex;
KeyEquals m_key_equals;
};
int main()
{
SharedResourceManager<int, int> int_mgr;
auto iptr = int_mgr.obtain(0, 1);
std::cout << *iptr << "\n";
return 0;
}