-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathunique.h
More file actions
107 lines (105 loc) · 2.88 KB
/
unique.h
File metadata and controls
107 lines (105 loc) · 2.88 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
#pragma once
#include <memory>
#include <set>
#include <mutex>
#include <atomic>
#include <optional>
#include <type_traits>
#include <boost/intrusive_ptr.hpp>
#include "onDestroy.h"
namespace theExpressionEngine
{
template<bool BTHREADED>
struct realConstant;
template<bool BTHREADED>
struct factory;
template<bool BTHREADED>
struct expression;
template<bool BTHREADED>
boost::intrusive_ptr<const expression<BTHREADED> > collapse(const expression<BTHREADED> &, const factory<BTHREADED>&);
/// 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>
class unique
{ public:
typedef typename std::conditional<
BTHREADED,
std::recursive_mutex,
NullMutex
>::type MUTEX;
typedef typename std::conditional<
BTHREADED,
std::atomic<std::size_t>,
std::size_t
>::type ATOMIC;
private:
/// does not need to be std::atomic as protected by a mutex
mutable ATOMIC m_sRefCount = std::size_t();
public:
unique(void) = default;
unique(const unique&) = delete;
unique(unique&&) = delete;
unique&operator=(const unique&) = delete;
unique&operator=(unique&&) = delete;
/// 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:
static MUTEX&getMutex(void)
{ return getSet().second;
}
template<typename DERIVED, typename ...ARGS>
static boost::intrusive_ptr<const T> _create(ARGS&&..._r)
{ const auto s = boost::intrusive_ptr<const T>(new onDestroy<DERIVED>(std::forward<ARGS>(_r)...));
std::lock_guard<MUTEX> sLock(getSet().second);
return *getSet().first.insert(s.get()).first;
}
template<typename DERIVED, typename ...REST>
static boost::intrusive_ptr<const T> create(const factory<BTHREADED>&_rF, REST&&..._r)
{ return collapse<BTHREADED>(*_create<DERIVED>(std::forward<REST>(_r)...), _rF);
}
/// the factory method
private:
/// called by boost::intrusive_ptr<const T>
/// 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;
}
}
};
}