-
Notifications
You must be signed in to change notification settings - Fork 0
/
components-template.cpp
111 lines (93 loc) · 2.32 KB
/
components-template.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
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <experimental/optional>
using namespace std;
struct position {
int x, y;
};
struct color {
int r, g, b;
};
template <class T> struct id_helper;
#define COMPONENT_ID(C, N) template <> struct id_helper<C> { enum { value = N }; }
COMPONENT_ID(position, 0);
COMPONENT_ID(color, 1);
auto gen_id() -> int {
static auto id = 0;
return id++;
}
struct storage {
virtual ~storage() = 0;
};
storage::~storage() {}
template <class T>
struct storage_impl : public storage {
unordered_map<int, T> data;
};
struct database {
unordered_map<int, unique_ptr<storage>> storages;
template <class T>
auto get() -> storage_impl<T>& {
if (storages.find(id_helper<T>::value) == end(storages)) {
storages.emplace(id_helper<T>::value, unique_ptr<storage>(new storage_impl<T>));
}
auto ptr = static_cast<storage_impl<T>*>(storages[id_helper<T>::value].get());
return *ptr;
}
template <class T>
auto get(int id) -> experimental::optional<T> {
auto& s = get<T>();
auto it = s.data.find(id);
if (it != end(s.data)) {
return it->second;
} else {
return {};
}
}
template <class T>
auto add(int id, T component) -> void {
auto& s = get<T>();
s.data.emplace(id, component);
}
struct setter {
int obj;
database& db;
setter(int active_object, database& active_db) : obj {active_object}, db(active_db) {}
template <class T>
auto operator<<(T component) -> setter& {
db.add(obj, component);
return *this;
}
};
auto use(int object) -> setter { return {object, *this}; }
};
auto main() -> int {
auto db = database {};
auto obj = gen_id();
auto obj2 = gen_id();
auto c = color {1, 2, 3};
auto p = position {320, 240};
db.use(obj) << c << p;
db.use(obj2) << p;
auto co = db.get<color>(obj2);
if (co) {
cout << co->r << ' ' << co->g << ' ' << co->b << endl;
} else {
cout << obj2 << " has no color" << endl;
}
for (auto c : db.get<color>().data) {
cout << c.first << ": "
<< c.second.r << ", "
<< c.second.g << ", "
<< c.second.b
<< endl;
}
for (auto p : db.get<position>().data) {
cout << p.first << ": "
<< p.second.x << ", "
<< p.second.y
<< endl;
}
}