-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathunique.cpp
More file actions
160 lines (151 loc) · 3.96 KB
/
unique.cpp
File metadata and controls
160 lines (151 loc) · 3.96 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <mutex>
#include <set>
#include <atomic>
#include <optional>
#include <type_traits>
#include <boost/intrusive_ptr.hpp>
/// a nullmutex in case of a single threaded environment
class NullMutex
{ public:
void lock(void)
{
}
void unlock(void)
{
}
bool try_lock(void)
{ return true;
}
};
/// the template class to implement the BASE class
/// look for example usage below
/// default is multithreaded using std::recursive_mutex
template<typename T, bool BTHREADED = true>
class unique
{ typedef typename std::conditional<
BTHREADED,
std::recursive_mutex,
NullMutex
>::type MUTEX;
/// does not need to be std::atomic as protected by a mutex
mutable std::size_t m_sRefCount;
public:
unique(void)
:m_sRefCount(std::size_t())
{
}
/// for implementing the static set of registered pointers
struct compare
{ bool operator()(const T*const _p0, const T*const _p1) const
{ return *_p0 < *_p1;
}
};
private:
typedef std::set<const T*, compare> SET;
typedef std::pair<SET, MUTEX> setAndMutex;
static setAndMutex&getSet(void)
{ static setAndMutex s;
return s;
}
public:
/// the factory method
template<typename DERIVED, typename ...ARGS>
static boost::intrusive_ptr<const T> create(ARGS&&..._r)
{ const auto s = boost::intrusive_ptr<const T>(new DERIVED(std::forward<ARGS>(_r)...));
std::lock_guard<MUTEX> sLock(getSet().second);
return *getSet().first.insert(s.get()).first;
}
private:
/// called by boost::intrusive_ptr<const T>
friend void intrusive_ptr_add_ref(const T* const _p) noexcept
{ std::lock_guard<MUTEX> sLock(getSet().second);
++_p->m_sRefCount;
}
/// called by boost::intrusive_ptr<const T>
friend void intrusive_ptr_release(const T* const _p) noexcept
{ std::optional<std::lock_guard<MUTEX> > sLock(getSet().second);
if (!--_p->m_sRefCount)
{ const auto pFind = getSet().first.find(_p);
if (pFind != getSet().first.end() && *pFind == _p)
getSet().first.erase(pFind);
sLock.reset();
delete _p;
}
}
};
#include <typeinfo>
/// an example hierarchy base class
struct expression:unique<expression>
{ virtual ~expression(void) = default;
/// for the set of pointers
/// sorting only by typeinfo
virtual bool operator<(const expression&_r) const
{ return typeid(*this).before(typeid(_r));
}
};
/// one example derived expression
struct integerConstant:expression
{ const int m_i;
integerConstant(const int _i)
:m_i(_i)
{
}
bool operator<(const expression&_r) const override
{ if (this->expression::operator<(_r))
return true;
else
if (_r.expression::operator<(*this))
return false;
else
return m_i < static_cast<const integerConstant&>(_r).m_i;
}
};
/// one example derived expression
struct realConstant:expression
{ const double m_d;
realConstant(const double _d)
:m_d(_d)
{
}
bool operator<(const expression&_r) const override
{ if (this->expression::operator<(_r))
return true;
else
if (_r.expression::operator<(*this))
return false;
else
return m_d < static_cast<const realConstant&>(_r).m_d;
}
};
#include <vector>
#include <thread>
#include <iostream>
int main(int argc, char**argv)
{ if (argc != 3)
{ std::cerr << argv[0] << ": Error: Usage: " << argv[0] << " numberOfObjects numberOfThreads" << std::endl;
return 1;
}
/// all the threads are doing the same
/// creating a local vector of pointers
const auto sCreate = [&](void)
{ std::set<boost::intrusive_ptr<const expression> > sVector;
for (int i = 0; i < 2; ++i)
for (int i = 0, iMax = std::atoi(argv[1]); i < iMax; ++i)
sVector.emplace(
i & 1
? unique<expression>::create<integerConstant>(i)
: unique<expression>::create<realConstant>(i*1.1)
);
};
/// the thread objects
std::vector<std::thread> sThreads;
sThreads.reserve(std::size_t(std::atoi(argv[2])));
/// starting the threads
for (std::size_t i = 0; i < sThreads.capacity(); ++i)
sThreads.emplace_back(sCreate);
/// and waiting for the threads to terminate
while (!sThreads.empty())
{ sThreads.back().join();
sThreads.pop_back();
}
}