]>
Commit | Line | Data |
---|---|---|
8e260fc0 TT |
1 | /* Macros for general registry objects. |
2 | ||
1d506c26 | 3 | Copyright (C) 2011-2024 Free Software Foundation, Inc. |
8e260fc0 TT |
4 | |
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #ifndef REGISTRY_H | |
21 | #define REGISTRY_H | |
22 | ||
5f6e90a0 TT |
23 | #include <type_traits> |
24 | ||
08b8a139 | 25 | template<typename T> class registry; |
6b81941e | 26 | |
08b8a139 | 27 | /* An accessor class that is used by registry_key. |
8e260fc0 | 28 | |
08b8a139 TT |
29 | Normally, a container class has a registry<> field named |
30 | "registry_fields". In this case, the default accessor is used, as | |
31 | it simply returns the object. | |
6b81941e | 32 | |
08b8a139 TT |
33 | However, a container may sometimes need to store the registry |
34 | elsewhere. In this case, registry_accessor can be specialized to | |
35 | perform the needed indirection. */ | |
6b81941e | 36 | |
08b8a139 TT |
37 | template<typename T> |
38 | struct registry_accessor | |
39 | { | |
40 | /* Given a container of type T, return its registry. */ | |
41 | static registry<T> *get (T *obj) | |
42 | { | |
43 | return &obj->registry_fields; | |
44 | } | |
45 | }; | |
8e260fc0 | 46 | |
08b8a139 TT |
47 | /* In gdb, sometimes there is a need for one module (e.g., the Python |
48 | Type code) to attach some data to another object (e.g., an | |
49 | objfile); but it's also desirable that this be done such that the | |
50 | base object (the objfile in this example) not need to know anything | |
51 | about the attaching module (the Python code). | |
aa0fbdd8 | 52 | |
08b8a139 | 53 | This is handled using the registry system. |
aa0fbdd8 | 54 | |
08b8a139 TT |
55 | A class needing to allow this sort registration can add a registry |
56 | field. For example, you would write: | |
aa0fbdd8 | 57 | |
08b8a139 | 58 | class some_container { registry<some_container> registry_fields; }; |
aa0fbdd8 | 59 | |
08b8a139 TT |
60 | The name of the field matters by default, see registry_accessor. |
61 | ||
62 | A module wanting to attach data to instances of some_container uses | |
63 | the "key" class to register a key. This key can then be passed to | |
64 | the "get" and "set" methods to handle this module's data. */ | |
aa0fbdd8 | 65 | |
08b8a139 TT |
66 | template<typename T> |
67 | class registry | |
68 | { | |
69 | public: | |
70 | ||
71 | registry () | |
72 | : m_fields (get_registrations ().size ()) | |
73 | { | |
74 | } | |
75 | ||
76 | ~registry () | |
77 | { | |
78 | clear_registry (); | |
79 | } | |
80 | ||
81 | DISABLE_COPY_AND_ASSIGN (registry); | |
82 | ||
83 | /* A type-safe registry key. | |
84 | ||
85 | The registry itself holds just a "void *". This is not always | |
86 | convenient to manage, so this template class can be used instead, | |
87 | to provide a type-safe interface, that also helps manage the | |
88 | lifetime of the stored objects. | |
89 | ||
90 | When the container is destroyed, this key arranges to destroy the | |
91 | underlying data using Deleter. This defaults to | |
92 | std::default_delete. */ | |
93 | ||
94 | template<typename DATA, typename Deleter = std::default_delete<DATA>> | |
95 | class key | |
96 | { | |
97 | public: | |
98 | ||
99 | key () | |
100 | : m_key (registry<T>::new_key (cleanup)) | |
101 | { | |
102 | } | |
103 | ||
104 | DISABLE_COPY_AND_ASSIGN (key); | |
105 | ||
106 | /* Fetch the data attached to OBJ that is associated with this key. | |
107 | If no such data has been attached, nullptr is returned. */ | |
108 | DATA *get (T *obj) const | |
109 | { | |
110 | registry<T> *reg_obj = registry_accessor<T>::get (obj); | |
111 | return (DATA *) reg_obj->get (m_key); | |
112 | } | |
113 | ||
114 | /* Attach DATA to OBJ, associated with this key. Note that any | |
115 | previous data is simply dropped -- if destruction is needed, | |
116 | 'clear' should be called. */ | |
117 | void set (T *obj, DATA *data) const | |
118 | { | |
119 | registry<T> *reg_obj = registry_accessor<T>::get (obj); | |
8b154043 | 120 | reg_obj->set (m_key, (typename std::remove_const<DATA> *) data); |
08b8a139 TT |
121 | } |
122 | ||
123 | /* If this key uses the default deleter, then this method is | |
124 | available. It emplaces a new instance of the associated data | |
125 | type and attaches it to OBJ using this key. The arguments, if | |
126 | any, are forwarded to the constructor. */ | |
127 | template<typename Dummy = DATA *, typename... Args> | |
128 | typename std::enable_if<std::is_same<Deleter, | |
129 | std::default_delete<DATA>>::value, | |
130 | Dummy>::type | |
131 | emplace (T *obj, Args &&...args) const | |
132 | { | |
133 | DATA *result = new DATA (std::forward<Args> (args)...); | |
134 | set (obj, result); | |
135 | return result; | |
136 | } | |
137 | ||
138 | /* Clear the data attached to OBJ that is associated with this KEY. | |
139 | Any existing data is destroyed using the deleter, and the data is | |
140 | reset to nullptr. */ | |
141 | void clear (T *obj) const | |
142 | { | |
143 | DATA *datum = get (obj); | |
144 | if (datum != nullptr) | |
145 | { | |
146 | cleanup (datum); | |
147 | set (obj, nullptr); | |
148 | } | |
149 | } | |
150 | ||
151 | private: | |
152 | ||
153 | /* A helper function that is called by the registry to delete the | |
154 | contained object. */ | |
155 | static void cleanup (void *arg) | |
156 | { | |
157 | DATA *datum = (DATA *) arg; | |
158 | Deleter d; | |
159 | d (datum); | |
160 | } | |
161 | ||
162 | /* The underlying key. */ | |
8126c055 | 163 | const unsigned m_key; |
08b8a139 TT |
164 | }; |
165 | ||
166 | /* Clear all the data associated with this container. This is | |
167 | dangerous and should not normally be done. */ | |
168 | void clear_registry () | |
169 | { | |
170 | /* Call all the free functions. */ | |
8126c055 TT |
171 | std::vector<registry_data_callback> ®istrations |
172 | = get_registrations (); | |
173 | unsigned last = registrations.size (); | |
174 | for (unsigned i = 0; i < last; ++i) | |
08b8a139 | 175 | { |
8126c055 | 176 | void *elt = m_fields[i]; |
08b8a139 TT |
177 | if (elt != nullptr) |
178 | { | |
8126c055 TT |
179 | registrations[i] (elt); |
180 | m_fields[i] = nullptr; | |
08b8a139 TT |
181 | } |
182 | } | |
183 | } | |
184 | ||
185 | private: | |
186 | ||
187 | /* Registry callbacks have this type. */ | |
188 | typedef void (*registry_data_callback) (void *); | |
189 | ||
08b8a139 TT |
190 | /* Get a new key for this particular registry. FREE is a callback. |
191 | When the container object is destroyed, all FREE functions are | |
192 | called. The data associated with the container object is passed | |
193 | to the callback. */ | |
8126c055 | 194 | static unsigned new_key (registry_data_callback free) |
08b8a139 | 195 | { |
8126c055 | 196 | std::vector<registry_data_callback> ®istrations |
08b8a139 | 197 | = get_registrations (); |
8126c055 TT |
198 | unsigned result = registrations.size (); |
199 | registrations.push_back (free); | |
200 | return result; | |
08b8a139 TT |
201 | } |
202 | ||
203 | /* Set the datum associated with KEY in this container. */ | |
8126c055 | 204 | void set (unsigned key, void *datum) |
08b8a139 | 205 | { |
8126c055 | 206 | m_fields[key] = datum; |
08b8a139 TT |
207 | } |
208 | ||
209 | /* Fetch the datum associated with KEY in this container. If 'set' | |
210 | has not been called for this key, nullptr is returned. */ | |
8126c055 | 211 | void *get (unsigned key) |
08b8a139 | 212 | { |
8126c055 | 213 | return m_fields[key]; |
08b8a139 TT |
214 | } |
215 | ||
216 | /* The data stored in this instance. */ | |
217 | std::vector<void *> m_fields; | |
218 | ||
219 | /* Return a reference to the vector of all the registrations that | |
8126c055 TT |
220 | have been made. */ |
221 | static std::vector<registry_data_callback> &get_registrations () | |
08b8a139 | 222 | { |
8126c055 | 223 | static std::vector<registry_data_callback> registrations; |
08b8a139 TT |
224 | return registrations; |
225 | } | |
5f6e90a0 | 226 | }; |
8e260fc0 TT |
227 | |
228 | #endif /* REGISTRY_H */ |