Merge branch 'master' into merge-job
[deliverable/binutils-gdb.git] / gdb / registry.h
index 423caa6d0321a443db100bf06d1854df9e2eb69f..09e2b67c938dbc8b6605bf247b67472910966d00 100644 (file)
@@ -1,7 +1,6 @@
 /* Macros for general registry objects.
 
-   Copyright (C) 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2011-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -21,6 +20,8 @@
 #ifndef REGISTRY_H
 #define REGISTRY_H
 
+#include <type_traits>
+
 /* The macros here implement a template type and functions for
    associating some user data with a container object.
 
    
    - register_TAG_data_with_cleanup(TAG, SAVE, FREE)
    Get a new key for the container type TAG.
-   SAVE and FREE are defined as void (*) (struct TAG *, void *)
-   When the container is destroyed, first all registered SAVE
+   SAVE and FREE are defined as void (*) (struct TAG *object, void *data)
+   When the container object OBJECT is destroyed, first all registered SAVE
    functions are called.
    Then all FREE functions are called.
-   Either or both may be NULL.
+   Either or both may be NULL.  DATA is the data associated with the
+   container object OBJECT.
    
    - clear_TAG_data(TAG, OBJECT)
    Clear all the data associated with OBJECT.  Should be called by the
@@ -85,48 +87,83 @@ struct registry_fields
 #define REGISTRY_ACCESS_FIELD(CONTAINER) \
   (CONTAINER)
 
+/* Opaque type representing a container type with a registry.  This
+   type is never defined.  This is used to factor out common
+   functionality of all struct tag names into common code.  IOW,
+   "struct tag name" pointers are cast to and from "struct
+   registry_container" pointers when calling the common registry
+   "backend" functions.  */
+struct registry_container;
+
+/* Registry callbacks have this type.  */
+typedef void (*registry_data_callback) (struct registry_container *, void *);
+
+struct registry_data
+{
+  unsigned index;
+  registry_data_callback save;
+  registry_data_callback free;
+};
+
+struct registry_data_registration
+{
+  struct registry_data *data;
+  struct registry_data_registration *next;
+};
+
+struct registry_data_registry
+{
+  struct registry_data_registration *registrations;
+  unsigned num_registrations;
+};
+
+/* Registry backend functions.  Client code uses the frontend
+   functions defined by DEFINE_REGISTRY below instead.  */
+
+const struct registry_data *register_data_with_cleanup
+  (struct registry_data_registry *registry,
+   registry_data_callback save,
+   registry_data_callback free);
+
+void registry_alloc_data (struct registry_data_registry *registry,
+                         struct registry_fields *registry_fields);
+
+/* Cast FUNC and CONTAINER to the real types, and call FUNC, also
+   passing DATA.  */
+typedef void (*registry_callback_adaptor) (registry_data_callback func,
+                                          struct registry_container *container,
+                                          void *data);
+
+void registry_clear_data (struct registry_data_registry *data_registry,
+                         registry_callback_adaptor adaptor,
+                         struct registry_container *container,
+                         struct registry_fields *fields);
+
+void registry_container_free_data (struct registry_data_registry *data_registry,
+                                  registry_callback_adaptor adaptor,
+                                  struct registry_container *container,
+                                  struct registry_fields *fields);
+
+void registry_set_data (struct registry_fields *fields,
+                       const struct registry_data *data,
+                       void *value);
+
+void *registry_data (struct registry_fields *fields,
+                    const struct registry_data *data);
+
 /* Define a new registry implementation.  */
 
 #define DEFINE_REGISTRY(TAG, ACCESS)                                   \
-struct TAG ## _data                                                    \
-{                                                                      \
-  unsigned index;                                                      \
-  void (*save) (struct TAG *, void *);                                 \
-  void (*free) (struct TAG *, void *);                                 \
-};                                                                     \
-                                                                       \
-struct TAG ## _data_registration                                       \
-{                                                                      \
-  struct TAG ## _data *data;                                           \
-  struct TAG ## _data_registration *next;                              \
-};                                                                     \
-                                                                       \
-struct TAG ## _data_registry                                           \
-{                                                                      \
-  struct TAG ## _data_registration *registrations;                     \
-  unsigned num_registrations;                                          \
-};                                                                     \
-                                                                       \
-struct TAG ## _data_registry TAG ## _data_registry = { NULL, 0 };      \
+struct registry_data_registry TAG ## _data_registry = { NULL, 0 };     \
                                                                        \
 const struct TAG ## _data *                                            \
 register_ ## TAG ## _data_with_cleanup (void (*save) (struct TAG *, void *), \
-                                   void (*free) (struct TAG *, void *)) \
+                                       void (*free) (struct TAG *, void *)) \
 {                                                                      \
-  struct TAG ## _data_registration **curr;                             \
-                                                                       \
-  /* Append new registration.  */                                      \
-  for (curr = &TAG ## _data_registry.registrations;                    \
-       *curr != NULL; curr = &(*curr)->next);                          \
-                                                                       \
-  *curr = XMALLOC (struct TAG ## _data_registration);                  \
-  (*curr)->next = NULL;                                                        \
-  (*curr)->data = XMALLOC (struct TAG ## _data);                       \
-  (*curr)->data->index = TAG ## _data_registry.num_registrations++;    \
-  (*curr)->data->save = save;                                          \
-  (*curr)->data->free = free;                                          \
-                                                                       \
-  return (*curr)->data;                                                        \
+  return (struct TAG ## _data *)                                       \
+    register_data_with_cleanup (&TAG ## _data_registry,                        \
+                               (registry_data_callback) save,          \
+                               (registry_data_callback) free);         \
 }                                                                      \
                                                                        \
 const struct TAG ## _data *                                            \
@@ -139,77 +176,134 @@ static void                                                              \
 TAG ## _alloc_data (struct TAG *container)                             \
 {                                                                      \
   struct registry_fields *rdata = &ACCESS (container)->registry_data;  \
-  gdb_assert (rdata->data == NULL);                                    \
-  rdata->num_data = TAG ## _data_registry.num_registrations;           \
-  rdata->data = XCALLOC (rdata->num_data, void *);                     \
+                                                                       \
+  registry_alloc_data (&TAG ## _data_registry, rdata);                 \
 }                                                                      \
                                                                        \
-void                                                                   \
-clear_ ## TAG ## _data (struct TAG *container)                         \
+static void                                                            \
+TAG ## registry_callback_adaptor (registry_data_callback func,         \
+                                 struct registry_container *container, \
+                                 void *data)                           \
 {                                                                      \
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;  \
-  struct TAG ## _data_registration *registration;                      \
-  int i;                                                               \
-                                                                       \
-  gdb_assert (rdata->data != NULL);                                    \
+  struct TAG *tagged_container = (struct TAG *) container;             \
                                                                        \
-  /* Process all the save handlers.  */                                        \
+  registry_ ## TAG ## _callback tagged_func                            \
+    = (registry_ ## TAG ## _callback) func;                            \
                                                                        \
-  for (registration = TAG ## _data_registry.registrations, i = 0;      \
-       i < rdata->num_data;                                            \
-       registration = registration->next, i++)                         \
-    if (rdata->data[i] != NULL && registration->data->save != NULL)    \
-      registration->data->save (container, rdata->data[i]);            \
-                                                                       \
-  /* Now process all the free handlers.  */                            \
+  tagged_func (tagged_container, data);                                        \
+}                                                                      \
                                                                        \
-  for (registration = TAG ## _data_registry.registrations, i = 0;      \
-       i < rdata->num_data;                                            \
-       registration = registration->next, i++)                         \
-    if (rdata->data[i] != NULL && registration->data->free != NULL)    \
-      registration->data->free (container, rdata->data[i]);            \
+void                                                                   \
+clear_ ## TAG ## _data (struct TAG *container)                         \
+{                                                                      \
+  struct registry_fields *rdata = &ACCESS (container)->registry_data;  \
                                                                        \
-  memset (rdata->data, 0, rdata->num_data * sizeof (void *));          \
+  registry_clear_data (&TAG ## _data_registry,                         \
+                      TAG ## registry_callback_adaptor,                \
+                      (struct registry_container *) container,         \
+                      rdata);                                          \
 }                                                                      \
                                                                        \
 static void                                                            \
 TAG ## _free_data (struct TAG *container)                              \
 {                                                                      \
   struct registry_fields *rdata = &ACCESS (container)->registry_data;  \
-  gdb_assert (rdata->data != NULL);                                    \
-  clear_ ## TAG ## _data (container);                                  \
-  xfree (rdata->data);                                                 \
-  rdata->data = NULL;                                                  \
+                                                                       \
+  registry_container_free_data (&TAG ## _data_registry,                        \
+                               TAG ## registry_callback_adaptor,       \
+                               (struct registry_container *) container, \
+                               rdata);                                 \
 }                                                                      \
                                                                        \
 void                                                                   \
-set_ ## TAG ## _data (struct TAG *container, const struct TAG ## _data *data, \
-                 void *value)                                          \
+set_ ## TAG ## _data (struct TAG *container,                           \
+                     const struct TAG ## _data *data,                  \
+                     void *value)                                      \
 {                                                                      \
   struct registry_fields *rdata = &ACCESS (container)->registry_data;  \
-  gdb_assert (data->index < rdata->num_data);                          \
-  rdata->data[data->index] = value;                                    \
+                                                                       \
+  registry_set_data (rdata,                                            \
+                    (struct registry_data *) data,                     \
+                    value);                                            \
 }                                                                      \
                                                                        \
 void *                                                                 \
 TAG ## _data (struct TAG *container, const struct TAG ## _data *data)  \
 {                                                                      \
   struct registry_fields *rdata = &ACCESS (container)->registry_data;  \
-  gdb_assert (data->index < rdata->num_data);                          \
-  return rdata->data[data->index];                                     \
+                                                                       \
+  return registry_data (rdata,                                         \
+                       (struct registry_data *) data);                 \
 }
 
 
 /* External declarations for the registry functions.  */
 
 #define DECLARE_REGISTRY(TAG)                                          \
+struct TAG ## _data;                                                   \
+typedef void (*registry_ ## TAG ## _callback) (struct TAG *, void *);  \
 extern const struct TAG ## _data *register_ ## TAG ## _data (void);    \
 extern const struct TAG ## _data *register_ ## TAG ## _data_with_cleanup \
- (void (*save) (struct TAG *, void *), void (*free) (struct TAG *, void *)); \
-extern void clear_ ## TAG ## _data (struct TAG *);             \
-extern void set_ ## TAG ## _data (struct TAG *,                        \
-                              const struct TAG ## _data *data, void *value); \
-extern void *TAG ## _data (struct TAG *,                       \
-                          const struct TAG ## _data *data);
+ (registry_ ## TAG ## _callback save, registry_ ## TAG ## _callback free); \
+extern void clear_ ## TAG ## _data (struct TAG *);                     \
+extern void set_ ## TAG ## _data (struct TAG *,                                \
+                                 const struct TAG ## _data *data,      \
+                                 void *value);                         \
+extern void *TAG ## _data (struct TAG *,                               \
+                          const struct TAG ## _data *data);            \
+                                                                       \
+template<typename DATA, typename Deleter = std::default_delete<DATA>>  \
+class TAG ## _key                                                      \
+{                                                                      \
+public:                                                                        \
+                                                                       \
+  TAG ## _key ()                                                       \
+    : m_key (register_ ## TAG ## _data_with_cleanup (nullptr,          \
+                                                    cleanup))          \
+  {                                                                    \
+  }                                                                    \
+                                                                       \
+  DATA *get (struct TAG *obj) const                                    \
+  {                                                                    \
+    return (DATA *) TAG ## _data (obj, m_key);                         \
+  }                                                                    \
+                                                                       \
+  void set (struct TAG *obj, DATA *data) const                         \
+  {                                                                    \
+    set_ ## TAG ## _data (obj, m_key, data);                           \
+  }                                                                    \
+                                                                       \
+  template<typename Dummy = DATA *, typename... Args>                  \
+  typename std::enable_if<std::is_same<Deleter,                                \
+                                      std::default_delete<DATA>>::value, \
+                         Dummy>::type                                  \
+  emplace (struct TAG *obj, Args &&...args) const                      \
+  {                                                                    \
+    DATA *result = new DATA (std::forward<Args> (args)...);            \
+    set (obj, result);                                                 \
+    return result;                                                     \
+  }                                                                    \
+                                                                       \
+  void clear (struct TAG *obj) const                                   \
+  {                                                                    \
+    DATA *datum = get (obj);                                           \
+    if (datum != nullptr)                                              \
+      {                                                                        \
+       cleanup (obj, datum);                                           \
+       set (obj, nullptr);                                             \
+      }                                                                        \
+  }                                                                    \
+                                                                       \
+private:                                                               \
+                                                                       \
+  static void cleanup (struct TAG *obj, void *arg)                     \
+  {                                                                    \
+    DATA *datum = (DATA *) arg;                                                \
+    Deleter d;                                                         \
+    d (datum);                                                         \
+  }                                                                    \
+                                                                       \
+  const struct TAG ## _data *m_key;                                    \
+};
 
 #endif /* REGISTRY_H */
This page took 0.029815 seconds and 4 git commands to generate.