]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/registry.h
[gdb/python] Make gdb.UnwindInfo.add_saved_register more robust (fixup)
[thirdparty/binutils-gdb.git] / gdb / registry.h
CommitLineData
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 25template<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
37template<typename T>
38struct 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
66template<typename T>
67class registry
68{
69public:
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> &registrations
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
185private:
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> &registrations
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 */