-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMemberStorage.h
134 lines (123 loc) · 3.86 KB
/
MemberStorage.h
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
/*!
* @file MemberStorage.h
* @author Bartłomiej Drozd
*
*/
#pragma once
#include <unordered_map>
#include <mutex>
#include <stdexcept>
#include <typeinfo>
#include <algorithm>
struct MemberTypeBase
{
MemberTypeBase(size_t hash) : class_hash(hash) {}
virtual bool isEqual(const MemberTypeBase* rhs) const = 0;
size_t class_hash;
};
template <typename _ClassType, typename _MemberType>
struct Member_t : MemberTypeBase
{
Member_t(_MemberType _ClassType::*arg)
: member(arg), MemberTypeBase(typeid(_ClassType).hash_code())
{
}
_MemberType _ClassType::*member;
bool isEqual(const MemberTypeBase* rhs) const override
{
if(class_hash == rhs->class_hash)
{
auto* ref =
static_cast<const Member_t<_ClassType, _MemberType>*>(rhs);
if (ref)
return ref->member == member;
}
return false;
}
};
//! @brief member storage base class used to register members.
struct MemberStorageBase
{
public:
//! @brief call this method in derived constructor
//! @tparam T
//! @param
template <typename T>
void callInitMembers(const T*)
{
static std::once_flag register_once;
std::call_once(register_once, &MemberStorageBase::InitMembers, this);
}
virtual void InitMembers() = 0;
protected:
class MemberHasher
{
public:
size_t operator()(const MemberTypeBase* val) const
{
return reinterpret_cast<uintptr_t>(val);
}
};
class MemberEqual
{
public:
bool operator()(const MemberTypeBase* val1,
const MemberTypeBase* val2) const
{
return val1->isEqual(val2);
}
};
};
//! @brief simple storage class to associate StoredType value for every registered data member. Works like a singleton storage for T type
//! @tparam T
//! @tparam StoredType
template <typename T, typename StoredType>
struct MemberStorage : protected virtual MemberStorageBase
{
public:
//! @brief returns stored value for provided data member pointer. Throws runtime_error if arg is not registered
//! @tparam ClassType data member pointer's class owner
//! @tparam MemberType data member pointer's type
//! @param arg data member pointer
//! @return stored value for provided arg
template <typename ClassType, typename MemberType>
static const StoredType& get(MemberType ClassType::*arg)
{
const auto& it = std::find_if(
storage.cbegin(), storage.cend(),
[arg](const std::pair<MemberTypeBase*, StoredType>& _it) -> bool {
if (_it.first->class_hash == typeid(ClassType).hash_code())
{
const auto* ref =
static_cast<const Member_t<ClassType, MemberType>*>(
_it.first);
if (ref)
return ref->member == arg;
}
return false;
});
if (it != storage.cend())
return it->second;
else
throw std::runtime_error("No storage for " +
std::string(typeid(ClassType).name()) + " " +
std::string(typeid(MemberType).name()));
}
protected:
//! @brief register new data member pointer and it's value under T storage
//! @tparam _ClassType
//! @tparam _MemberType
//! @param arg data member pointer
//! @param value value
//! @return
template <typename _ClassType, typename _MemberType>
bool registerMember(_MemberType _ClassType::*arg, const StoredType value)
{
storage[new Member_t(arg)] = value;
return true;
}
protected:
inline static std::unordered_map<MemberTypeBase*, StoredType, MemberHasher,
MemberEqual>
storage;
};