| /* Macros for general registry objects. | 
 |  | 
 |    Copyright (C) 2011-2024 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #ifndef GDB_REGISTRY_H | 
 | #define GDB_REGISTRY_H | 
 |  | 
 | #include <type_traits> | 
 |  | 
 | template<typename T> class registry; | 
 |  | 
 | /* An accessor class that is used by registry_key. | 
 |  | 
 |    Normally, a container class has a registry<> field named | 
 |    "registry_fields".  In this case, the default accessor is used, as | 
 |    it simply returns the object. | 
 |  | 
 |    However, a container may sometimes need to store the registry | 
 |    elsewhere.  In this case, registry_accessor can be specialized to | 
 |    perform the needed indirection.  */ | 
 |  | 
 | template<typename T> | 
 | struct registry_accessor | 
 | { | 
 |   /* Given a container of type T, return its registry.  */ | 
 |   static registry<T> *get (T *obj) | 
 |   { | 
 |     return &obj->registry_fields; | 
 |   } | 
 | }; | 
 |  | 
 | /* In gdb, sometimes there is a need for one module (e.g., the Python | 
 |    Type code) to attach some data to another object (e.g., an | 
 |    objfile); but it's also desirable that this be done such that the | 
 |    base object (the objfile in this example) not need to know anything | 
 |    about the attaching module (the Python code). | 
 |  | 
 |    This is handled using the registry system. | 
 |  | 
 |    A class needing to allow this sort registration can add a registry | 
 |    field.  For example, you would write: | 
 |  | 
 |    class some_container { registry<some_container> registry_fields; }; | 
 |  | 
 |    The name of the field matters by default, see registry_accessor. | 
 |  | 
 |    A module wanting to attach data to instances of some_container uses | 
 |    the "key" class to register a key.  This key can then be passed to | 
 |    the "get" and "set" methods to handle this module's data.  */ | 
 |  | 
 | template<typename T> | 
 | class registry | 
 | { | 
 | public: | 
 |  | 
 |   registry () | 
 |     : m_fields (get_registrations ().size ()) | 
 |   { | 
 |   } | 
 |  | 
 |   ~registry () | 
 |   { | 
 |     clear_registry (); | 
 |   } | 
 |  | 
 |   DISABLE_COPY_AND_ASSIGN (registry); | 
 |  | 
 |   /* A type-safe registry key. | 
 |  | 
 |      The registry itself holds just a "void *".  This is not always | 
 |      convenient to manage, so this template class can be used instead, | 
 |      to provide a type-safe interface, that also helps manage the | 
 |      lifetime of the stored objects. | 
 |  | 
 |      When the container is destroyed, this key arranges to destroy the | 
 |      underlying data using Deleter.  This defaults to | 
 |      std::default_delete.  */ | 
 |  | 
 |   template<typename DATA, typename Deleter = std::default_delete<DATA>> | 
 |   class key | 
 |   { | 
 |   public: | 
 |  | 
 |     key () | 
 |       : m_key (registry<T>::new_key (cleanup)) | 
 |     { | 
 |     } | 
 |  | 
 |     DISABLE_COPY_AND_ASSIGN (key); | 
 |  | 
 |     /* Fetch the data attached to OBJ that is associated with this key. | 
 |        If no such data has been attached, nullptr is returned.  */ | 
 |     DATA *get (T *obj) const | 
 |     { | 
 |       registry<T> *reg_obj = registry_accessor<T>::get (obj); | 
 |       return (DATA *) reg_obj->get (m_key); | 
 |     } | 
 |  | 
 |     /* Attach DATA to OBJ, associated with this key.  Note that any | 
 |        previous data is simply dropped -- if destruction is needed, | 
 |        'clear' should be called.  */ | 
 |     void set (T *obj, DATA *data) const | 
 |     { | 
 |       registry<T> *reg_obj = registry_accessor<T>::get (obj); | 
 |       reg_obj->set (m_key, (typename std::remove_const<DATA> *) data); | 
 |     } | 
 |  | 
 |     /* If this key uses the default deleter, then this method is | 
 |        available.  It emplaces a new instance of the associated data | 
 |        type and attaches it to OBJ using this key.  The arguments, if | 
 |        any, are forwarded to the constructor.  */ | 
 |     template<typename Dummy = DATA *, typename... Args> | 
 |     typename std::enable_if<std::is_same<Deleter, | 
 | 					 std::default_delete<DATA>>::value, | 
 | 			    Dummy>::type | 
 |     emplace (T *obj, Args &&...args) const | 
 |     { | 
 |       DATA *result = new DATA (std::forward<Args> (args)...); | 
 |       set (obj, result); | 
 |       return result; | 
 |     } | 
 |  | 
 |     /* Clear the data attached to OBJ that is associated with this KEY. | 
 |        Any existing data is destroyed using the deleter, and the data is | 
 |        reset to nullptr.  */ | 
 |     void clear (T *obj) const | 
 |     { | 
 |       DATA *datum = get (obj); | 
 |       if (datum != nullptr) | 
 | 	{ | 
 | 	  cleanup (datum); | 
 | 	  set (obj, nullptr); | 
 | 	} | 
 |     } | 
 |  | 
 |   private: | 
 |  | 
 |     /* A helper function that is called by the registry to delete the | 
 |        contained object.  */ | 
 |     static void cleanup (void *arg) | 
 |     { | 
 |       DATA *datum = (DATA *) arg; | 
 |       Deleter d; | 
 |       d (datum); | 
 |     } | 
 |  | 
 |     /* The underlying key.  */ | 
 |     const unsigned m_key; | 
 |   }; | 
 |  | 
 |   /* Clear all the data associated with this container.  This is | 
 |      dangerous and should not normally be done.  */ | 
 |   void clear_registry () | 
 |   { | 
 |     /* Call all the free functions.  */ | 
 |     std::vector<registry_data_callback> ®istrations | 
 |       = get_registrations (); | 
 |     unsigned last = registrations.size (); | 
 |     for (unsigned i = 0; i < last; ++i) | 
 |       { | 
 | 	void *elt = m_fields[i]; | 
 | 	if (elt != nullptr) | 
 | 	  { | 
 | 	    registrations[i] (elt); | 
 | 	    m_fields[i] = nullptr; | 
 | 	  } | 
 |       } | 
 |   } | 
 |  | 
 | private: | 
 |  | 
 |   /* Registry callbacks have this type.  */ | 
 |   typedef void (*registry_data_callback) (void *); | 
 |  | 
 |   /* Get a new key for this particular registry.  FREE is a callback. | 
 |      When the container object is destroyed, all FREE functions are | 
 |      called.  The data associated with the container object is passed | 
 |      to the callback.  */ | 
 |   static unsigned new_key (registry_data_callback free) | 
 |   { | 
 |     std::vector<registry_data_callback> ®istrations | 
 |       = get_registrations (); | 
 |     unsigned result = registrations.size (); | 
 |     registrations.push_back (free); | 
 |     return result; | 
 |   } | 
 |  | 
 |   /* Set the datum associated with KEY in this container.  */ | 
 |   void set (unsigned key, void *datum) | 
 |   { | 
 |     m_fields[key] = datum; | 
 |   } | 
 |  | 
 |   /* Fetch the datum associated with KEY in this container.  If 'set' | 
 |      has not been called for this key, nullptr is returned.  */ | 
 |   void *get (unsigned key) | 
 |   { | 
 |     return m_fields[key]; | 
 |   } | 
 |  | 
 |   /* The data stored in this instance.  */ | 
 |   std::vector<void *> m_fields; | 
 |  | 
 |   /* Return a reference to the vector of all the registrations that | 
 |      have been made.  */ | 
 |   static std::vector<registry_data_callback> &get_registrations () | 
 |   { | 
 |     static std::vector<registry_data_callback> registrations; | 
 |     return registrations; | 
 |   } | 
 | }; | 
 |  | 
 | #endif /* GDB_REGISTRY_H */ |