[pygobject] cache refactoring: Move PyGIHashCache and related marshaling into new file



commit 4a6bf3be49cc5aec7287c41ec02c78d60df1d44c
Author: Simon Feltman <sfeltman src gnome org>
Date:   Fri Oct 11 17:39:31 2013 -0700

    cache refactoring: Move PyGIHashCache and related marshaling into new file
    
    Re-organize hash table arg cache and its marshaling by moving all
    related code fragments into an isolated file where most of it is made
    static. pygi-hashtable.h exposes a single function:
    pygi_arg_hash_table_new_from_info. This is all the caching system needs to
    produce the proper bits for handling hash table marshaling.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=709700

 gi/Makefile.am            |    4 +-
 gi/pygi-cache.c           |  103 +-----------
 gi/pygi-cache.h           |   21 ++-
 gi/pygi-hashtable.c       |  413 +++++++++++++++++++++++++++++++++++++++++++++
 gi/pygi-hashtable.h       |   35 ++++
 gi/pygi-marshal-cleanup.c |   63 -------
 gi/pygi-marshal-cleanup.h |   10 -
 gi/pygi-marshal-from-py.c |  125 --------------
 gi/pygi-marshal-from-py.h |    6 -
 gi/pygi-marshal-to-py.c   |   85 ---------
 gi/pygi-marshal-to-py.h   |    4 -
 11 files changed, 471 insertions(+), 398 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index fa1ce9a..c2fcd5c 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -102,7 +102,9 @@ _gi_la_SOURCES = \
        pygi-marshal-to-py.c \
        pygi-marshal-to-py.h \
        pygi-marshal-cleanup.c \
-       pygi-marshal-cleanup.h
+       pygi-marshal-cleanup.h \
+       pygi-hashtable.c \
+       pygi-hashtable.h
 _gi_la_CFLAGS = \
        $(extension_cppflags) \
        $(GLIB_CFLAGS) \
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index f476501..0c6b94c 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -19,22 +19,16 @@
  * USA
  */
 
+#include <girepository.h>
+
 #include "pygi-info.h"
 #include "pygi-cache.h"
 #include "pygi-marshal-to-py.h"
 #include "pygi-marshal-from-py.h"
 #include "pygi-marshal-cleanup.h"
 #include "pygi-type.h"
-#include <girepository.h>
+#include "pygi-hashtable.h"
 
-PyGIArgCache * _arg_cache_new (GITypeInfo *type_info,
-                               GIArgInfo *arg_info,
-                               GITransfer transfer,
-                               PyGIDirection direction,
-                               /* will be removed */
-                               gssize c_arg_index,
-                               gssize py_arg_index,
-                               PyGICallableCache *callable_cache);
 
 PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
                                              GITypeInfo *type_info,
@@ -127,7 +121,7 @@ pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
 
 
 /* cleanup */
-static void
+void
 _pygi_arg_cache_free (PyGIArgCache *cache)
 {
     if (cache == NULL)
@@ -154,15 +148,6 @@ _interface_cache_free_func (PyGIInterfaceCache *cache)
     }
 }
 
-static void
-_hash_cache_free_func (PyGIHashCache *cache)
-{
-    if (cache != NULL) {
-        _pygi_arg_cache_free (cache->key_cache);
-        _pygi_arg_cache_free (cache->value_cache);
-        g_slice_free (PyGIHashCache, cache);
-    }
-}
 
 static void
 _sequence_cache_free_func (PyGISequenceCache *cache)
@@ -261,53 +246,6 @@ _sequence_cache_new (GITypeInfo *type_info,
 
     return sc;
 }
-static PyGIHashCache *
-_hash_cache_new (GITypeInfo *type_info,
-                 GIDirection direction,
-                 GITransfer transfer)
-{
-    PyGIHashCache *hc;
-    GITypeInfo *key_type_info;
-    GITypeInfo *value_type_info;
-    GITransfer item_transfer;
-
-    hc = g_slice_new0 (PyGIHashCache);
-    ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
-    key_type_info = g_type_info_get_param_type (type_info, 0);
-    value_type_info = g_type_info_get_param_type (type_info, 1);
-
-    item_transfer =
-        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
-
-    hc->key_cache = _arg_cache_new (key_type_info,
-                                    NULL,
-                                    item_transfer,
-                                    direction,
-                                    0, 0,
-                                    NULL);
-
-    if (hc->key_cache == NULL) {
-        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
-        return NULL;
-    }
-
-    hc->value_cache = _arg_cache_new (value_type_info,
-                                      NULL,
-                                      item_transfer,
-                                      direction,
-                                      0, 0,
-                                      NULL);
-
-    if (hc->value_cache == NULL) {
-        _pygi_arg_cache_free ( (PyGIArgCache *)hc);
-        return NULL;
-    }
-
-    g_base_info_unref( (GIBaseInfo *)key_type_info);
-    g_base_info_unref( (GIBaseInfo *)value_type_info);
-
-    return hc;
-}
 
 static PyGICallbackCache *
 _callback_cache_new (GIArgInfo *arg_info,
@@ -512,20 +450,6 @@ _arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache,
 }
 
 static void
-_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache)
-{
-    arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash;
-    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash;
-}
-
-static void
-_arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache)
-{
-    arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash;
-    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash;
-}
-
-static void
 _arg_cache_from_py_gerror_setup (PyGIArgCache *arg_cache)
 {
     arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror;
@@ -920,22 +844,11 @@ _arg_cache_new (GITypeInfo *type_info,
                break;
             }
        case GI_TYPE_TAG_GHASH:
-           arg_cache =
-               (PyGIArgCache *)_hash_cache_new (type_info,
-                                                direction,
-                                                transfer);
-
-           if (arg_cache == NULL)
-                   break;
+           arg_cache = pygi_arg_hash_table_new_from_info (type_info, arg_info, transfer, direction);
+           arg_cache->py_arg_index = py_arg_index;
+           arg_cache->c_arg_index = c_arg_index;
+           return arg_cache;
 
-           if (direction & PYGI_DIRECTION_FROM_PYTHON)
-               _arg_cache_from_py_ghash_setup (arg_cache);
-
-           if (direction & PYGI_DIRECTION_TO_PYTHON) {
-               _arg_cache_to_py_ghash_setup (arg_cache);
-           }
-
-           break;
        case GI_TYPE_TAG_INTERFACE:
            {
                GIInterfaceInfo *interface_info = g_type_info_get_interface (type_info);
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
index 7a5be37..e1b0649 100644
--- a/gi/pygi-cache.h
+++ b/gi/pygi-cache.h
@@ -150,13 +150,6 @@ typedef struct _PyGIInterfaceCache
     gchar *type_name;
 } PyGIInterfaceCache;
 
-typedef struct _PyGIHashCache
-{
-    PyGIArgCache arg_cache;
-    PyGIArgCache *key_cache;
-    PyGIArgCache *value_cache;
-} PyGIHashCache;
-
 typedef struct _PyGICallbackCache
 {
     PyGIArgCache arg_cache;
@@ -218,8 +211,18 @@ pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
                           PyGIDirection       direction,
                           GIInterfaceInfo    *iface_info);
 
-void _pygi_arg_cache_clear     (PyGIArgCache *cache);
-void _pygi_callable_cache_free (PyGICallableCache *cache);
+PyGIArgCache * _arg_cache_new (GITypeInfo *type_info,
+                               GIArgInfo *arg_info,
+                               GITransfer transfer,
+                               PyGIDirection direction,
+                               /* will be removed */
+                               gssize c_arg_index,
+                               gssize py_arg_index,
+                               PyGICallableCache *callable_cache);
+
+void _pygi_arg_cache_free       (PyGIArgCache *cache);
+void _pygi_arg_cache_clear      (PyGIArgCache *cache);
+void _pygi_callable_cache_free  (PyGICallableCache *cache);
 
 PyGICallableCache *_pygi_callable_cache_new (GICallableInfo *callable_info,
                                              gboolean is_ccallback);
diff --git a/gi/pygi-hashtable.c b/gi/pygi-hashtable.c
new file mode 100644
index 0000000..f8864f0
--- /dev/null
+++ b/gi/pygi-hashtable.c
@@ -0,0 +1,413 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp redhat com>
+ * Copyright (C) 2014 Simon Feltman <sfeltman gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pygi-hashtable.h"
+#include "pygi-argument.h"
+#include "pygi-private.h"
+
+typedef struct _PyGIHashCache
+{
+    PyGIArgCache arg_cache;
+    PyGIArgCache *key_cache;
+    PyGIArgCache *value_cache;
+} PyGIHashCache;
+
+
+static void
+_hash_cache_free_func (PyGIHashCache *cache)
+{
+    if (cache != NULL) {
+        _pygi_arg_cache_free (cache->key_cache);
+        _pygi_arg_cache_free (cache->value_cache);
+        g_slice_free (PyGIHashCache, cache);
+    }
+}
+
+static gboolean
+_pygi_marshal_from_py_ghash (PyGIInvokeState   *state,
+                             PyGICallableCache *callable_cache,
+                             PyGIArgCache      *arg_cache,
+                             PyObject          *py_arg,
+                             GIArgument        *arg,
+                             gpointer          *cleanup_data)
+{
+    PyGIMarshalFromPyFunc key_from_py_marshaller;
+    PyGIMarshalFromPyFunc value_from_py_marshaller;
+
+    int i;
+    Py_ssize_t length;
+    PyObject *py_keys, *py_values;
+
+    GHashFunc hash_func;
+    GEqualFunc equal_func;
+
+    GHashTable *hash_ = NULL;
+    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+    if (py_arg == Py_None) {
+        arg->v_pointer = NULL;
+        return TRUE;
+    }
+
+    py_keys = PyMapping_Keys (py_arg);
+    if (py_keys == NULL) {
+        PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
+                      py_arg->ob_type->tp_name);
+        return FALSE;
+    }
+
+    length = PyMapping_Length (py_arg);
+    if (length < 0) {
+        Py_DECREF (py_keys);
+        return FALSE;
+    }
+
+    py_values = PyMapping_Values (py_arg);
+    if (py_values == NULL) {
+        Py_DECREF (py_keys);
+        return FALSE;
+    }
+
+    key_from_py_marshaller = hash_cache->key_cache->from_py_marshaller;
+    value_from_py_marshaller = hash_cache->value_cache->from_py_marshaller;
+
+    switch (hash_cache->key_cache->type_tag) {
+        case GI_TYPE_TAG_UTF8:
+        case GI_TYPE_TAG_FILENAME:
+            hash_func = g_str_hash;
+            equal_func = g_str_equal;
+            break;
+        default:
+            hash_func = NULL;
+            equal_func = NULL;
+    }
+
+    hash_ = g_hash_table_new (hash_func, equal_func);
+    if (hash_ == NULL) {
+        PyErr_NoMemory ();
+        Py_DECREF (py_keys);
+        Py_DECREF (py_values);
+        return FALSE;
+    }
+
+    for (i = 0; i < length; i++) {
+        GIArgument key, value;
+        gpointer key_cleanup_data = NULL;
+        gpointer value_cleanup_data = NULL;
+        PyObject *py_key = PyList_GET_ITEM (py_keys, i);
+        PyObject *py_value = PyList_GET_ITEM (py_values, i);
+        if (py_key == NULL || py_value == NULL)
+            goto err;
+
+        if (!key_from_py_marshaller ( state,
+                                      callable_cache,
+                                      hash_cache->key_cache,
+                                      py_key,
+                                     &key,
+                                     &key_cleanup_data))
+            goto err;
+
+        if (!value_from_py_marshaller ( state,
+                                        callable_cache,
+                                        hash_cache->value_cache,
+                                        py_value,
+                                       &value,
+                                       &value_cleanup_data))
+            goto err;
+
+        g_hash_table_insert (hash_,
+                             _pygi_arg_to_hash_pointer (&key, hash_cache->key_cache->type_tag),
+                             _pygi_arg_to_hash_pointer (&value, hash_cache->value_cache->type_tag));
+        continue;
+err:
+        /* FIXME: cleanup hash keys and values */
+        Py_XDECREF (py_key);
+        Py_XDECREF (py_value);
+        Py_DECREF (py_keys);
+        Py_DECREF (py_values);
+        g_hash_table_unref (hash_);
+        _PyGI_ERROR_PREFIX ("Item %i: ", i);
+        return FALSE;
+    }
+
+    arg->v_pointer = hash_;
+
+    if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
+        /* Free everything in cleanup. */
+        *cleanup_data = arg->v_pointer;
+    } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+        /* Make a shallow copy so we can free the elements later in cleanup
+         * because it is possible invoke will free the list before our cleanup. */
+        *cleanup_data = g_hash_table_ref (arg->v_pointer);
+    } else { /* GI_TRANSFER_EVERYTHING */
+        /* No cleanup, everything is given to the callee.
+         * Note that the keys and values will leak for transfer everything because
+         * we do not use g_hash_table_new_full and set key/value_destroy_func. */
+        *cleanup_data = NULL;
+    }
+
+    return TRUE;
+}
+
+static void
+_pygi_marshal_cleanup_from_py_ghash  (PyGIInvokeState *state,
+                                      PyGIArgCache    *arg_cache,
+                                      PyObject        *py_arg,
+                                      gpointer         data,
+                                      gboolean         was_processed)
+{
+    if (data == NULL)
+        return;
+
+    if (was_processed) {
+        GHashTable *hash_;
+        PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+        hash_ = (GHashTable *)data;
+
+        /* clean up keys and values first */
+        if (hash_cache->key_cache->from_py_cleanup != NULL ||
+                hash_cache->value_cache->from_py_cleanup != NULL) {
+            GHashTableIter hiter;
+            gpointer key;
+            gpointer value;
+
+            PyGIMarshalCleanupFunc key_cleanup_func =
+                hash_cache->key_cache->from_py_cleanup;
+            PyGIMarshalCleanupFunc value_cleanup_func =
+                hash_cache->value_cache->from_py_cleanup;
+
+            g_hash_table_iter_init (&hiter, hash_);
+            while (g_hash_table_iter_next (&hiter, &key, &value)) {
+                if (key != NULL && key_cleanup_func != NULL)
+                    key_cleanup_func (state,
+                                      hash_cache->key_cache,
+                                      NULL,
+                                      key,
+                                      TRUE);
+                if (value != NULL && value_cleanup_func != NULL)
+                    value_cleanup_func (state,
+                                        hash_cache->value_cache,
+                                        NULL,
+                                        value,
+                                        TRUE);
+            }
+        }
+
+        g_hash_table_unref (hash_);
+    }
+}
+
+static PyObject *
+_pygi_marshal_to_py_ghash (PyGIInvokeState   *state,
+                           PyGICallableCache *callable_cache,
+                           PyGIArgCache      *arg_cache,
+                           GIArgument        *arg)
+{
+    GHashTable *hash_;
+    GHashTableIter hash_table_iter;
+
+    PyGIMarshalToPyFunc key_to_py_marshaller;
+    PyGIMarshalToPyFunc value_to_py_marshaller;
+
+    PyGIArgCache *key_arg_cache;
+    PyGIArgCache *value_arg_cache;
+    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+    GIArgument key_arg;
+    GIArgument value_arg;
+
+    PyObject *py_obj = NULL;
+
+    hash_ = arg->v_pointer;
+
+    if (hash_ == NULL) {
+        py_obj = Py_None;
+        Py_INCREF (py_obj);
+        return py_obj;
+    }
+
+    py_obj = PyDict_New ();
+    if (py_obj == NULL)
+        return NULL;
+
+    key_arg_cache = hash_cache->key_cache;
+    key_to_py_marshaller = key_arg_cache->to_py_marshaller;
+
+    value_arg_cache = hash_cache->value_cache;
+    value_to_py_marshaller = value_arg_cache->to_py_marshaller;
+
+    g_hash_table_iter_init (&hash_table_iter, hash_);
+    while (g_hash_table_iter_next (&hash_table_iter,
+                                   &key_arg.v_pointer,
+                                   &value_arg.v_pointer)) {
+        PyObject *py_key;
+        PyObject *py_value;
+        int retval;
+
+
+        _pygi_hash_pointer_to_arg (&key_arg, hash_cache->key_cache->type_tag);
+        py_key = key_to_py_marshaller ( state,
+                                      callable_cache,
+                                      key_arg_cache,
+                                     &key_arg);
+
+        if (py_key == NULL) {
+            Py_CLEAR (py_obj);
+            return NULL;
+        }
+
+        _pygi_hash_pointer_to_arg (&value_arg, hash_cache->value_cache->type_tag);
+        py_value = value_to_py_marshaller ( state,
+                                          callable_cache,
+                                          value_arg_cache,
+                                         &value_arg);
+
+        if (py_value == NULL) {
+            Py_CLEAR (py_obj);
+            Py_DECREF(py_key);
+            return NULL;
+        }
+
+        retval = PyDict_SetItem (py_obj, py_key, py_value);
+
+        Py_DECREF (py_key);
+        Py_DECREF (py_value);
+
+        if (retval < 0) {
+            Py_CLEAR (py_obj);
+            return NULL;
+        }
+    }
+
+    return py_obj;
+}
+
+static void
+_pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state,
+                                   PyGIArgCache    *arg_cache,
+                                   PyObject        *dummy,
+                                   gpointer         data,
+                                   gboolean         was_processed)
+{
+    if (data == NULL)
+        return;
+
+    /* assume hashtable has boxed key and value */
+    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || arg_cache->transfer == GI_TRANSFER_CONTAINER)
+        g_hash_table_unref ( (GHashTable *)data);
+}
+
+static void
+_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache)
+{
+    arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash;
+    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash;
+}
+
+static void
+_arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache)
+{
+    arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash;
+    arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash;
+}
+
+static gboolean
+pygi_arg_hash_table_setup_from_info (PyGIHashCache *hc,
+                                     GITypeInfo    *type_info,
+                                     GIArgInfo     *arg_info,
+                                     GITransfer     transfer,
+                                     PyGIDirection  direction)
+{
+    GITypeInfo *key_type_info;
+    GITypeInfo *value_type_info;
+    GITransfer item_transfer;
+
+    if (!pygi_arg_base_setup ((PyGIArgCache *)hc, type_info, arg_info, transfer, direction))
+        return FALSE;
+
+    ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
+    key_type_info = g_type_info_get_param_type (type_info, 0);
+    value_type_info = g_type_info_get_param_type (type_info, 1);
+
+    item_transfer =
+        transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+    hc->key_cache = _arg_cache_new (key_type_info,
+                                    NULL,
+                                    item_transfer,
+                                    direction,
+                                    0, 0,
+                                    NULL);
+
+    if (hc->key_cache == NULL) {
+        return FALSE;
+    }
+
+    hc->value_cache = _arg_cache_new (value_type_info,
+                                      NULL,
+                                      item_transfer,
+                                      direction,
+                                      0, 0,
+                                      NULL);
+
+    if (hc->value_cache == NULL) {
+        return FALSE;
+    }
+
+    g_base_info_unref( (GIBaseInfo *)key_type_info);
+    g_base_info_unref( (GIBaseInfo *)value_type_info);
+
+    if (direction & PYGI_DIRECTION_FROM_PYTHON) {
+        _arg_cache_from_py_ghash_setup ((PyGIArgCache *)hc);
+    }
+
+    if (direction & PYGI_DIRECTION_TO_PYTHON) {
+        _arg_cache_to_py_ghash_setup ((PyGIArgCache *)hc);
+    }
+
+    return TRUE;
+}
+
+PyGIArgCache *
+pygi_arg_hash_table_new_from_info (GITypeInfo   *type_info,
+                                   GIArgInfo    *arg_info,
+                                   GITransfer    transfer,
+                                   PyGIDirection direction)
+{
+    gboolean res = FALSE;
+    PyGIHashCache *hc = NULL;
+
+    hc = g_slice_new0 (PyGIHashCache);
+    if (hc == NULL)
+        return NULL;
+
+    res = pygi_arg_hash_table_setup_from_info (hc,
+                                               type_info,
+                                               arg_info,
+                                               transfer,
+                                               direction);
+    if (res) {
+        return (PyGIArgCache *)hc;
+    } else {
+        _pygi_arg_cache_free ((PyGIArgCache *)hc);
+        return NULL;
+    }
+}
diff --git a/gi/pygi-hashtable.h b/gi/pygi-hashtable.h
new file mode 100644
index 0000000..a42aaf0
--- /dev/null
+++ b/gi/pygi-hashtable.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2013 Simon Feltman <sfeltman gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PYGI_HASHTABLE_H__
+#define __PYGI_HASHTABLE_H__
+
+#include <girepository.h>
+#include "pygi-cache.h"
+
+G_BEGIN_DECLS
+
+PyGIArgCache *pygi_arg_hash_table_new_from_info (GITypeInfo    *type_info,
+                                                 GIArgInfo     *arg_info,   /* may be null */
+                                                 GITransfer     transfer,
+                                                 PyGIDirection  direction);
+
+G_END_DECLS
+
+#endif /*__PYGI_HASHTABLE_H__*/
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index 33d0339..38783d9 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -548,66 +548,3 @@ _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
     }
 }
 
-void
-_pygi_marshal_cleanup_from_py_ghash  (PyGIInvokeState *state,
-                                      PyGIArgCache    *arg_cache,
-                                      PyObject        *py_arg,
-                                      gpointer         data,
-                                      gboolean         was_processed)
-{
-    if (data == NULL)
-        return;
-
-    if (was_processed) {
-        GHashTable *hash_;
-        PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
-
-        hash_ = (GHashTable *)data;
-
-        /* clean up keys and values first */
-        if (hash_cache->key_cache->from_py_cleanup != NULL ||
-                hash_cache->value_cache->from_py_cleanup != NULL) {
-            GHashTableIter hiter;
-            gpointer key;
-            gpointer value;
-
-            PyGIMarshalCleanupFunc key_cleanup_func =
-                hash_cache->key_cache->from_py_cleanup;
-            PyGIMarshalCleanupFunc value_cleanup_func =
-                hash_cache->value_cache->from_py_cleanup;
-
-            g_hash_table_iter_init (&hiter, hash_);
-            while (g_hash_table_iter_next (&hiter, &key, &value)) {
-                if (key != NULL && key_cleanup_func != NULL)
-                    key_cleanup_func (state,
-                                      hash_cache->key_cache,
-                                      NULL,
-                                      key,
-                                      TRUE);
-                if (value != NULL && value_cleanup_func != NULL)
-                    value_cleanup_func (state,
-                                        hash_cache->value_cache,
-                                        NULL,
-                                        value,
-                                        TRUE);
-            }
-        }
-
-        g_hash_table_unref (hash_);
-    }
-}
-
-void
-_pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state,
-                                   PyGIArgCache    *arg_cache,
-                                   PyObject        *dummy,
-                                   gpointer         data,
-                                   gboolean         was_processed)
-{
-    if (data == NULL)
-        return;
-
-    /* assume hashtable has boxed key and value */
-    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || arg_cache->transfer == GI_TRANSFER_CONTAINER)
-        g_hash_table_unref ( (GHashTable *)data);
-}
diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h
index 3acfbeb..70a91c8 100644
--- a/gi/pygi-marshal-cleanup.h
+++ b/gi/pygi-marshal-cleanup.h
@@ -100,16 +100,6 @@ void _pygi_marshal_cleanup_to_py_glist                    (PyGIInvokeState *stat
                                                            PyObject        *dummy,
                                                            gpointer         data,
                                                            gboolean         was_processed);
-void _pygi_marshal_cleanup_from_py_ghash                  (PyGIInvokeState *state,
-                                                           PyGIArgCache    *arg_cache,
-                                                           PyObject        *py_arg,
-                                                           gpointer         data,
-                                                           gboolean         was_processed);
-void _pygi_marshal_cleanup_to_py_ghash                    (PyGIInvokeState *state,
-                                                           PyGIArgCache    *arg_cache,
-                                                           PyObject        *dummy,
-                                                           gpointer         data,
-                                                           gboolean         was_processed);
 G_END_DECLS
 
 #endif /* __PYGI_MARSHAL_CLEANUP_H__ */
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index 41dcf54..e3b8ae8 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -1142,131 +1142,6 @@ err:
     return TRUE;
 }
 
-gboolean
-_pygi_marshal_from_py_ghash (PyGIInvokeState   *state,
-                             PyGICallableCache *callable_cache,
-                             PyGIArgCache      *arg_cache,
-                             PyObject          *py_arg,
-                             GIArgument        *arg,
-                             gpointer          *cleanup_data)
-{
-    PyGIMarshalFromPyFunc key_from_py_marshaller;
-    PyGIMarshalFromPyFunc value_from_py_marshaller;
-
-    int i;
-    Py_ssize_t length;
-    PyObject *py_keys, *py_values;
-
-    GHashFunc hash_func;
-    GEqualFunc equal_func;
-
-    GHashTable *hash_ = NULL;
-    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
-
-    if (py_arg == Py_None) {
-        arg->v_pointer = NULL;
-        return TRUE;
-    }
-
-    py_keys = PyMapping_Keys (py_arg);
-    if (py_keys == NULL) {
-        PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
-                      py_arg->ob_type->tp_name);
-        return FALSE;
-    }
-
-    length = PyMapping_Length (py_arg);
-    if (length < 0) {
-        Py_DECREF (py_keys);
-        return FALSE;
-    }
-
-    py_values = PyMapping_Values (py_arg);
-    if (py_values == NULL) {
-        Py_DECREF (py_keys);
-        return FALSE;
-    }
-
-    key_from_py_marshaller = hash_cache->key_cache->from_py_marshaller;
-    value_from_py_marshaller = hash_cache->value_cache->from_py_marshaller;
-
-    switch (hash_cache->key_cache->type_tag) {
-        case GI_TYPE_TAG_UTF8:
-        case GI_TYPE_TAG_FILENAME:
-            hash_func = g_str_hash;
-            equal_func = g_str_equal;
-            break;
-        default:
-            hash_func = NULL;
-            equal_func = NULL;
-    }
-
-    hash_ = g_hash_table_new (hash_func, equal_func);
-    if (hash_ == NULL) {
-        PyErr_NoMemory ();
-        Py_DECREF (py_keys);
-        Py_DECREF (py_values);
-        return FALSE;
-    }
-
-    for (i = 0; i < length; i++) {
-        GIArgument key, value;
-        gpointer key_cleanup_data = NULL;
-        gpointer value_cleanup_data = NULL;
-        PyObject *py_key = PyList_GET_ITEM (py_keys, i);
-        PyObject *py_value = PyList_GET_ITEM (py_values, i);
-        if (py_key == NULL || py_value == NULL)
-            goto err;
-
-        if (!key_from_py_marshaller ( state,
-                                      callable_cache,
-                                      hash_cache->key_cache,
-                                      py_key,
-                                     &key,
-                                     &key_cleanup_data))
-            goto err;
-
-        if (!value_from_py_marshaller ( state,
-                                        callable_cache,
-                                        hash_cache->value_cache,
-                                        py_value,
-                                       &value,
-                                       &value_cleanup_data))
-            goto err;
-
-        g_hash_table_insert (hash_,
-                             _pygi_arg_to_hash_pointer (&key, hash_cache->key_cache->type_tag),
-                             _pygi_arg_to_hash_pointer (&value, hash_cache->value_cache->type_tag));
-        continue;
-err:
-        /* FIXME: cleanup hash keys and values */
-        Py_XDECREF (py_key);
-        Py_XDECREF (py_value);
-        Py_DECREF (py_keys);
-        Py_DECREF (py_values);
-        g_hash_table_unref (hash_);
-        _PyGI_ERROR_PREFIX ("Item %i: ", i);
-        return FALSE;
-    }
-
-    arg->v_pointer = hash_;
-
-    if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
-        /* Free everything in cleanup. */
-        *cleanup_data = arg->v_pointer;
-    } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
-        /* Make a shallow copy so we can free the elements later in cleanup
-         * because it is possible invoke will free the list before our cleanup. */
-        *cleanup_data = g_hash_table_ref (arg->v_pointer);
-    } else { /* GI_TRANSFER_EVERYTHING */
-        /* No cleanup, everything is given to the callee.
-         * Note that the keys and values will leak for transfer everything because
-         * we do not use g_hash_table_new_full and set key/value_destroy_func. */
-        *cleanup_data = NULL;
-    }
-
-    return TRUE;
-}
 
 gboolean
 _pygi_marshal_from_py_gerror (PyGIInvokeState   *state,
diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h
index f8e4699..83d074a 100644
--- a/gi/pygi-marshal-from-py.h
+++ b/gi/pygi-marshal-from-py.h
@@ -57,12 +57,6 @@ gboolean _pygi_marshal_from_py_gslist      (PyGIInvokeState   *state,
                                             PyObject          *py_arg,
                                             GIArgument        *arg,
                                             gpointer          *cleanup_data);
-gboolean _pygi_marshal_from_py_ghash       (PyGIInvokeState   *state,
-                                            PyGICallableCache *callable_cache,
-                                            PyGIArgCache      *arg_cache,
-                                            PyObject          *py_arg,
-                                            GIArgument        *arg,
-                                            gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_gerror      (PyGIInvokeState   *state,
                                             PyGICallableCache *callable_cache,
                                             PyGIArgCache      *arg_cache,
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index 9427754..3c7d69e 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -537,91 +537,6 @@ _pygi_marshal_to_py_gslist (PyGIInvokeState   *state,
 }
 
 PyObject *
-_pygi_marshal_to_py_ghash (PyGIInvokeState   *state,
-                           PyGICallableCache *callable_cache,
-                           PyGIArgCache      *arg_cache,
-                           GIArgument        *arg)
-{
-    GHashTable *hash_;
-    GHashTableIter hash_table_iter;
-
-    PyGIMarshalToPyFunc key_to_py_marshaller;
-    PyGIMarshalToPyFunc value_to_py_marshaller;
-
-    PyGIArgCache *key_arg_cache;
-    PyGIArgCache *value_arg_cache;
-    PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
-
-    GIArgument key_arg;
-    GIArgument value_arg;
-
-    PyObject *py_obj = NULL;
-
-    hash_ = arg->v_pointer;
-
-    if (hash_ == NULL) {
-        py_obj = Py_None;
-        Py_INCREF (py_obj);
-        return py_obj;
-    }
-
-    py_obj = PyDict_New ();
-    if (py_obj == NULL)
-        return NULL;
-
-    key_arg_cache = hash_cache->key_cache;
-    key_to_py_marshaller = key_arg_cache->to_py_marshaller;
-
-    value_arg_cache = hash_cache->value_cache;
-    value_to_py_marshaller = value_arg_cache->to_py_marshaller;
-
-    g_hash_table_iter_init (&hash_table_iter, hash_);
-    while (g_hash_table_iter_next (&hash_table_iter,
-                                   &key_arg.v_pointer,
-                                   &value_arg.v_pointer)) {
-        PyObject *py_key;
-        PyObject *py_value;
-        int retval;
-
-
-        _pygi_hash_pointer_to_arg (&key_arg, hash_cache->key_cache->type_tag);
-        py_key = key_to_py_marshaller ( state,
-                                      callable_cache,
-                                      key_arg_cache,
-                                     &key_arg);
-
-        if (py_key == NULL) {
-            Py_CLEAR (py_obj);
-            return NULL;
-        }
-
-        _pygi_hash_pointer_to_arg (&value_arg, hash_cache->value_cache->type_tag);
-        py_value = value_to_py_marshaller ( state,
-                                          callable_cache,
-                                          value_arg_cache,
-                                         &value_arg);
-
-        if (py_value == NULL) {
-            Py_CLEAR (py_obj);
-            Py_DECREF(py_key);
-            return NULL;
-        }
-
-        retval = PyDict_SetItem (py_obj, py_key, py_value);
-
-        Py_DECREF (py_key);
-        Py_DECREF (py_value);
-
-        if (retval < 0) {
-            Py_CLEAR (py_obj);
-            return NULL;
-        }
-    }
-
-    return py_obj;
-}
-
-PyObject *
 _pygi_marshal_to_py_gerror (PyGIInvokeState   *state,
                             PyGICallableCache *callable_cache,
                             PyGIArgCache      *arg_cache,
diff --git a/gi/pygi-marshal-to-py.h b/gi/pygi-marshal-to-py.h
index 1378630..48f1aa2 100644
--- a/gi/pygi-marshal-to-py.h
+++ b/gi/pygi-marshal-to-py.h
@@ -45,10 +45,6 @@ PyObject *_pygi_marshal_to_py_gslist    (PyGIInvokeState   *state,
                                          PyGICallableCache *callable_cache,
                                          PyGIArgCache      *arg_cache,
                                          GIArgument        *arg);
-PyObject *_pygi_marshal_to_py_ghash     (PyGIInvokeState   *state,
-                                         PyGICallableCache *callable_cache,
-                                         PyGIArgCache      *arg_cache,
-                                         GIArgument        *arg);
 PyObject *_pygi_marshal_to_py_gerror    (PyGIInvokeState   *state,
                                          PyGICallableCache *callable_cache,
                                          PyGIArgCache      *arg_cache,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]