TachyonUI
0.1.0
High-performance UI for building tools.
Toggle main menu visibility
Loading...
Searching...
No Matches
gui_element_data_store.h
Go to the documentation of this file.
1
#pragma once
2
3
#include <
gui_core/gui_id.h
>
4
5
#include <assert.h>
6
#include <stddef.h>
7
#include <new>
8
#include <typeindex>
9
#include <typeinfo>
10
#include <unordered_map>
11
#include <utility>
12
13
namespace
tachyon
14
{
17
22
class
ElementDataStore
23
{
24
public
:
25
ElementDataStore
() =
default
;
26
ElementDataStore
(
const
ElementDataStore
&) =
delete
;
27
ElementDataStore
&
operator=
(
const
ElementDataStore
&) =
delete
;
28
31
template
<
typename
T,
typename
... Args>
32
T&
GetOrCreate
(
ID
id
, Args&&... args);
33
35
template
<
typename
T>
36
T*
Get
(
ID
id
);
37
39
void
Touch
(
ID
id
);
40
41
void
Remove
(
ID
id
);
42
43
void
Clear
();
44
46
void
BeginFrame
();
47
49
void
EndFrame
();
50
51
size_t
EntryCount
()
const
{
return
m_entries.size(); }
52
53
private
:
55
static
constexpr
size_t
kInlineSize = 80;
56
57
struct
Entry
58
{
59
uint64_t touchedFrame = 0;
60
std::type_index typeIdx{
typeid
(void) };
61
62
alignas
(std::max_align_t) std::byte inlineBuffer[kInlineSize];
63
65
void
* data =
nullptr
;
66
void (*destroyer)(
void
*) =
nullptr
;
67
bool
heapAllocated =
false
;
68
69
Entry() =
default
;
70
Entry(
const
Entry&) =
delete
;
71
Entry& operator=(
const
Entry&) =
delete
;
73
Entry(Entry&&) =
delete
;
74
Entry& operator=(Entry&&) =
delete
;
75
76
~Entry() { Reset(); }
77
78
void
Reset()
79
{
80
if
(!data)
return
;
81
destroyer(data);
// also frees heap storage, with the type's own alignment
82
data =
nullptr
;
83
destroyer =
nullptr
;
84
heapAllocated =
false
;
85
typeIdx = std::type_index(
typeid
(
void
));
86
}
87
};
88
89
std::unordered_map<ID, Entry> m_entries;
90
uint64_t m_currentFrame = 1;
91
};
92
93
template
<
typename
T,
typename
... Args>
94
T&
ElementDataStore::GetOrCreate
(
ID
id
, Args&&... args)
95
{
96
// try_emplace constructs in place; Entry is non-movable.
97
auto
[it, _] = m_entries.try_emplace(
id
);
98
Entry& entry = it->second;
99
const
std::type_index wanted{
typeid
(T) };
100
101
assert((!entry.data || entry.typeIdx == wanted) &&
"ID collision between different handler types"
);
102
103
if
(entry.data && entry.typeIdx == wanted)
104
{
105
entry.touchedFrame = m_currentFrame;
106
return
*
static_cast<
T*
>
(entry.data);
107
}
108
109
// Wrong-type entry (assertion violated in debug); rebuild for release.
110
entry.Reset();
111
112
void
* mem;
113
if
constexpr
(
sizeof
(T) <= kInlineSize &&
alignof
(T) <=
alignof
(std::max_align_t))
114
{
115
mem = entry.inlineBuffer;
116
entry.heapAllocated =
false
;
117
}
118
else
119
{
120
mem = ::operator
new
(
sizeof
(T), std::align_val_t{
alignof
(T) });
121
entry.heapAllocated =
true
;
122
}
123
124
T* ptr = ::new (mem) T(std::forward<Args>(args)...);
125
entry.data = ptr;
126
if
(entry.heapAllocated)
127
entry.destroyer = +[](
void
* p)
128
{
129
static_cast<
T*
>
(p)->~T();
130
::operator
delete
(p, std::align_val_t{
alignof
(T) });
131
};
132
else
133
entry.destroyer = +[](
void
* p) {
static_cast<
T*
>
(p)->~T(); };
134
entry.typeIdx = wanted;
135
entry.touchedFrame = m_currentFrame;
136
return
*ptr;
137
}
138
139
template
<
typename
T>
140
T*
ElementDataStore::Get
(
ID
id
)
141
{
142
auto
it = m_entries.find(
id
);
143
if
(it == m_entries.end())
return
nullptr
;
144
const
std::type_index wanted{
typeid
(T) };
145
assert(it->second.typeIdx == wanted &&
"ID collision between different handler types"
);
146
if
(it->second.typeIdx != wanted)
return
nullptr
;
147
it->second.touchedFrame = m_currentFrame;
148
return
static_cast<
T*
>
(it->second.data);
149
}
150
151
}
tachyon::ElementDataStore::ElementDataStore
ElementDataStore()=default
tachyon::ElementDataStore::ElementDataStore
ElementDataStore(const ElementDataStore &)=delete
tachyon::ElementDataStore::Clear
void Clear()
tachyon::ElementDataStore::Remove
void Remove(ID id)
tachyon::ElementDataStore::operator=
ElementDataStore & operator=(const ElementDataStore &)=delete
tachyon::ElementDataStore::EntryCount
size_t EntryCount() const
Definition
gui_element_data_store.h:51
tachyon::ElementDataStore::BeginFrame
void BeginFrame()
Starts a frame; call before any Get, GetOrCreate or Touch of the frame.
tachyon::ElementDataStore::EndFrame
void EndFrame()
Destroys the entries not touched since BeginFrame.
tachyon::ElementDataStore::Touch
void Touch(ID id)
Keeps id's entry alive through this frame's EndFrame.
tachyon::ElementDataStore::GetOrCreate
T & GetOrCreate(ID id, Args &&... args)
The T stored for id, constructed from args when absent.
Definition
gui_element_data_store.h:94
tachyon::ElementDataStore::Get
T * Get(ID id)
The T stored for id, or nullptr (also on a type mismatch). Touches the entry if found.
Definition
gui_element_data_store.h:140
gui_id.h
tachyon
Definition
gui_logging.h:24
tachyon::ID
A 64-bit element ID whose bit layout depends on its IDMode.
Definition
gui_id.h:23
gui_core
elements
gui_element_data_store.h
Generated by
1.18.0