TachyonUI 0.1.0
High-performance UI for building tools.
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
13namespace tachyon
14{
17
23 {
24 public:
25 ElementDataStore() = default;
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>
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}
ElementDataStore(const ElementDataStore &)=delete
ElementDataStore & operator=(const ElementDataStore &)=delete
size_t EntryCount() const
Definition gui_element_data_store.h:51
void BeginFrame()
Starts a frame; call before any Get, GetOrCreate or Touch of the frame.
void EndFrame()
Destroys the entries not touched since BeginFrame.
void Touch(ID id)
Keeps id's entry alive through this frame's EndFrame.
T & GetOrCreate(ID id, Args &&... args)
The T stored for id, constructed from args when absent.
Definition gui_element_data_store.h:94
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
Definition gui_logging.h:24
A 64-bit element ID whose bit layout depends on its IDMode.
Definition gui_id.h:23