]> Git Repo - binutils.git/blob - gdb/registry.h
Automatic date update in version.in
[binutils.git] / gdb / registry.h
1 /* Macros for general registry objects.
2
3    Copyright (C) 2011-2022 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> &registrations
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> &registrations
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 */
This page took 0.036361 seconds and 4 git commands to generate.