1 /* Macros for general registry objects. 2 3 Copyright (C) 2011-2023 Free Software Foundation, Inc. 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 23 #include <type_traits> 24 25 template<typename T> class registry; 26 27 /* An accessor class that is used by registry_key. 28 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. 32 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. */ 36 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 }; 46 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). 52 53 This is handled using the registry system. 54 55 A class needing to allow this sort registration can add a registry 56 field. For example, you would write: 57 58 class some_container { registry<some_container> registry_fields; }; 59 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. */ 65 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); 120 reg_obj->set (m_key, (typename std::remove_const<DATA> *) data); 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. */ 163 const unsigned m_key; 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. */ 171 std::vector<registry_data_callback> ®istrations 172 = get_registrations (); 173 unsigned last = registrations.size (); 174 for (unsigned i = 0; i < last; ++i) 175 { 176 void *elt = m_fields[i]; 177 if (elt != nullptr) 178 { 179 registrations[i] (elt); 180 m_fields[i] = nullptr; 181 } 182 } 183 } 184 185 private: 186 187 /* Registry callbacks have this type. */ 188 typedef void (*registry_data_callback) (void *); 189 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. */ 194 static unsigned new_key (registry_data_callback free) 195 { 196 std::vector<registry_data_callback> ®istrations 197 = get_registrations (); 198 unsigned result = registrations.size (); 199 registrations.push_back (free); 200 return result; 201 } 202 203 /* Set the datum associated with KEY in this container. */ 204 void set (unsigned key, void *datum) 205 { 206 m_fields[key] = datum; 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. */ 211 void *get (unsigned key) 212 { 213 return m_fields[key]; 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 220 have been made. */ 221 static std::vector<registry_data_callback> &get_registrations () 222 { 223 static std::vector<registry_data_callback> registrations; 224 return registrations; 225 } 226 }; 227 228 #endif /* REGISTRY_H */ 229