1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * vim: tabstop=4 shiftwidth=4 expandtab
4 * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
5 * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library 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 GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 #include "pygi-hashtable.h"
23 #include "pygi-argument.h"
24 #include "pygi-private.h"
26 typedef struct _PyGIHashCache
28 PyGIArgCache arg_cache;
29 PyGIArgCache *key_cache;
30 PyGIArgCache *value_cache;
35 _hash_cache_free_func (PyGIHashCache *cache)
38 pygi_arg_cache_free (cache->key_cache);
39 pygi_arg_cache_free (cache->value_cache);
40 g_slice_free (PyGIHashCache, cache);
45 _pygi_marshal_from_py_ghash (PyGIInvokeState *state,
46 PyGICallableCache *callable_cache,
47 PyGIArgCache *arg_cache,
50 gpointer *cleanup_data)
52 PyGIMarshalFromPyFunc key_from_py_marshaller;
53 PyGIMarshalFromPyFunc value_from_py_marshaller;
57 PyObject *py_keys, *py_values;
60 GEqualFunc equal_func;
62 GHashTable *hash_ = NULL;
63 PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
65 if (py_arg == Py_None) {
66 arg->v_pointer = NULL;
70 py_keys = PyMapping_Keys (py_arg);
71 if (py_keys == NULL) {
72 PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
73 py_arg->ob_type->tp_name);
77 length = PyMapping_Length (py_arg);
83 py_values = PyMapping_Values (py_arg);
84 if (py_values == NULL) {
89 key_from_py_marshaller = hash_cache->key_cache->from_py_marshaller;
90 value_from_py_marshaller = hash_cache->value_cache->from_py_marshaller;
92 switch (hash_cache->key_cache->type_tag) {
93 case GI_TYPE_TAG_UTF8:
94 case GI_TYPE_TAG_FILENAME:
95 hash_func = g_str_hash;
96 equal_func = g_str_equal;
103 hash_ = g_hash_table_new (hash_func, equal_func);
107 Py_DECREF (py_values);
111 for (i = 0; i < length; i++) {
112 GIArgument key, value;
113 gpointer key_cleanup_data = NULL;
114 gpointer value_cleanup_data = NULL;
115 PyObject *py_key = PyList_GET_ITEM (py_keys, i);
116 PyObject *py_value = PyList_GET_ITEM (py_values, i);
117 if (py_key == NULL || py_value == NULL)
120 if (!key_from_py_marshaller ( state,
122 hash_cache->key_cache,
128 if (!value_from_py_marshaller ( state,
130 hash_cache->value_cache,
133 &value_cleanup_data))
136 g_hash_table_insert (hash_,
137 _pygi_arg_to_hash_pointer (&key, hash_cache->key_cache->type_tag),
138 _pygi_arg_to_hash_pointer (&value, hash_cache->value_cache->type_tag));
141 /* FIXME: cleanup hash keys and values */
143 Py_XDECREF (py_value);
145 Py_DECREF (py_values);
146 g_hash_table_unref (hash_);
147 _PyGI_ERROR_PREFIX ("Item %i: ", i);
151 arg->v_pointer = hash_;
153 if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
154 /* Free everything in cleanup. */
155 *cleanup_data = arg->v_pointer;
156 } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
157 /* Make a shallow copy so we can free the elements later in cleanup
158 * because it is possible invoke will free the list before our cleanup. */
159 *cleanup_data = g_hash_table_ref (arg->v_pointer);
160 } else { /* GI_TRANSFER_EVERYTHING */
161 /* No cleanup, everything is given to the callee.
162 * Note that the keys and values will leak for transfer everything because
163 * we do not use g_hash_table_new_full and set key/value_destroy_func. */
164 *cleanup_data = NULL;
171 _pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state,
172 PyGIArgCache *arg_cache,
175 gboolean was_processed)
182 PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
184 hash_ = (GHashTable *)data;
186 /* clean up keys and values first */
187 if (hash_cache->key_cache->from_py_cleanup != NULL ||
188 hash_cache->value_cache->from_py_cleanup != NULL) {
189 GHashTableIter hiter;
193 PyGIMarshalCleanupFunc key_cleanup_func =
194 hash_cache->key_cache->from_py_cleanup;
195 PyGIMarshalCleanupFunc value_cleanup_func =
196 hash_cache->value_cache->from_py_cleanup;
198 g_hash_table_iter_init (&hiter, hash_);
199 while (g_hash_table_iter_next (&hiter, &key, &value)) {
200 if (key != NULL && key_cleanup_func != NULL)
201 key_cleanup_func (state,
202 hash_cache->key_cache,
206 if (value != NULL && value_cleanup_func != NULL)
207 value_cleanup_func (state,
208 hash_cache->value_cache,
215 g_hash_table_unref (hash_);
220 _pygi_marshal_to_py_ghash (PyGIInvokeState *state,
221 PyGICallableCache *callable_cache,
222 PyGIArgCache *arg_cache,
226 GHashTableIter hash_table_iter;
228 PyGIMarshalToPyFunc key_to_py_marshaller;
229 PyGIMarshalToPyFunc value_to_py_marshaller;
231 PyGIArgCache *key_arg_cache;
232 PyGIArgCache *value_arg_cache;
233 PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
236 GIArgument value_arg;
238 PyObject *py_obj = NULL;
240 hash_ = arg->v_pointer;
248 py_obj = PyDict_New ();
252 key_arg_cache = hash_cache->key_cache;
253 key_to_py_marshaller = key_arg_cache->to_py_marshaller;
255 value_arg_cache = hash_cache->value_cache;
256 value_to_py_marshaller = value_arg_cache->to_py_marshaller;
258 g_hash_table_iter_init (&hash_table_iter, hash_);
259 while (g_hash_table_iter_next (&hash_table_iter,
261 &value_arg.v_pointer)) {
267 _pygi_hash_pointer_to_arg (&key_arg, hash_cache->key_cache->type_tag);
268 py_key = key_to_py_marshaller ( state,
273 if (py_key == NULL) {
278 _pygi_hash_pointer_to_arg (&value_arg, hash_cache->value_cache->type_tag);
279 py_value = value_to_py_marshaller ( state,
284 if (py_value == NULL) {
290 retval = PyDict_SetItem (py_obj, py_key, py_value);
293 Py_DECREF (py_value);
305 _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state,
306 PyGIArgCache *arg_cache,
309 gboolean was_processed)
314 /* assume hashtable has boxed key and value */
315 if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || arg_cache->transfer == GI_TRANSFER_CONTAINER)
316 g_hash_table_unref ( (GHashTable *)data);
320 _arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache)
322 arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash;
323 arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash;
327 _arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache)
329 arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash;
330 arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash;
334 pygi_arg_hash_table_setup_from_info (PyGIHashCache *hc,
335 GITypeInfo *type_info,
338 PyGIDirection direction,
339 PyGICallableCache *callable_cache)
341 GITypeInfo *key_type_info;
342 GITypeInfo *value_type_info;
343 GITransfer item_transfer;
345 if (!pygi_arg_base_setup ((PyGIArgCache *)hc, type_info, arg_info, transfer, direction))
348 ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
349 key_type_info = g_type_info_get_param_type (type_info, 0);
350 value_type_info = g_type_info_get_param_type (type_info, 1);
353 transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
355 hc->key_cache = pygi_arg_cache_new (key_type_info,
362 if (hc->key_cache == NULL) {
366 hc->value_cache = pygi_arg_cache_new (value_type_info,
373 if (hc->value_cache == NULL) {
377 g_base_info_unref( (GIBaseInfo *)key_type_info);
378 g_base_info_unref( (GIBaseInfo *)value_type_info);
380 if (direction & PYGI_DIRECTION_FROM_PYTHON) {
381 _arg_cache_from_py_ghash_setup ((PyGIArgCache *)hc);
384 if (direction & PYGI_DIRECTION_TO_PYTHON) {
385 _arg_cache_to_py_ghash_setup ((PyGIArgCache *)hc);
392 pygi_arg_hash_table_new_from_info (GITypeInfo *type_info,
395 PyGIDirection direction,
396 PyGICallableCache *callable_cache)
398 gboolean res = FALSE;
399 PyGIHashCache *hc = NULL;
401 hc = g_slice_new0 (PyGIHashCache);
405 res = pygi_arg_hash_table_setup_from_info (hc,
412 return (PyGIArgCache *)hc;
414 pygi_arg_cache_free ((PyGIArgCache *)hc);