[vala/wip/issue/1238: 6/6] codegen: Actually free data when using "remove(_all)" on GLib.Queue/(S)List
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/issue/1238: 6/6] codegen: Actually free data when using "remove(_all)" on GLib.Queue/(S)List
- Date: Fri, 15 Oct 2021 11:56:22 +0000 (UTC)
commit 6ac079db81d5847490957c09ae898304862bfe44
Author: Rico Tzschichholz <ricotz ubuntu com>
Date: Thu Oct 14 19:44:55 2021 +0200
codegen: Actually free data when using "remove(_all)" on GLib.Queue/(S)List
When using e.g. GLib.List.remove() there is no context/feedback whether an
item was removed or needed manual free'ing.
Replace such calls with custom wrappers where items required free'ing if
they were found.
Fixes https://gitlab.gnome.org/GNOME/vala/issues/1238
codegen/valaccodemethodcallmodule.vala | 22 ++
tests/Makefile.am | 1 +
tests/basic-types/glists_remove.c-expected | 577 +++++++++++++++++++++++++++++
tests/basic-types/glists_remove.vala | 113 ++++++
vapi/glib-2.0.vapi | 85 +++++
5 files changed, 798 insertions(+)
---
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index ceb9370ec..94c31007b 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -799,6 +799,28 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
}
+ // Transform and add free function argument to GLib.[List,Queue,SList].remove[_all] calls
+ unowned DataType? collection_type = null;
+ if (ma != null && ma.inner != null) {
+ collection_type = ma.inner.value_type;
+ }
+ if (collection_type != null
+ && (collection_type.type_symbol == glist_type || collection_type.type_symbol ==
gslist_type || collection_type.type_symbol == gqueue_type)
+ && (ma.member_name == "remove" || ma.member_name == "remove_all")
+ //FIXME Perform stricter type argument check earlier
+ && collection_type.check_type_arguments (context)) {
+ var remove_method = (Method) collection_type.type_symbol.scope.lookup (ma.member_name
+ "_full");
+ var type_arg = collection_type.get_type_arguments ()[0];
+ if (remove_method != null && requires_destroy (type_arg)) {
+ // only add them once per source file
+ if (add_generated_external_symbol (remove_method)) {
+ visit_method (remove_method);
+ }
+ ccall.call = new CCodeIdentifier (get_ccode_name (remove_method));
+ ccall.add_argument (get_destroy0_func_expression (type_arg));
+ }
+ }
+
if (return_result_via_out_param) {
ccode.add_expression (ccall_expr);
ccall_expr = out_param_ref;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7cd0168b7..bbd5bfcc9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -60,6 +60,7 @@ TESTS = \
basic-types/sizeof.vala \
basic-types/garray.vala \
basic-types/glists.vala \
+ basic-types/glists_remove.vala \
basic-types/gptrarray.vala \
basic-types/gvariants.vala \
basic-types/gvariants-hashtable-missing-type-arguments.test \
diff --git a/tests/basic-types/glists_remove.c-expected b/tests/basic-types/glists_remove.c-expected
new file mode 100644
index 000000000..da44d3ea3
--- /dev/null
+++ b/tests/basic-types/glists_remove.c-expected
@@ -0,0 +1,577 @@
+/* basic_types_glists_remove.c generated by valac, the Vala compiler
+ * generated from basic_types_glists_remove.vala, do not modify */
+
+#include <glib-object.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(VALA_EXTERN)
+#if defined(_MSC_VER)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
+#define TYPE_FOO (foo_get_type ())
+#define FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FOO, Foo))
+#define FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FOO, FooClass))
+#define IS_FOO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FOO))
+#define IS_FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FOO))
+#define FOO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FOO, FooClass))
+
+typedef struct _Foo Foo;
+typedef struct _FooClass FooClass;
+typedef struct _FooPrivate FooPrivate;
+enum {
+ FOO_0_PROPERTY,
+ FOO_NUM_PROPERTIES
+};
+static GParamSpec* foo_properties[FOO_NUM_PROPERTIES];
+#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__,
__LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN,
G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning
(G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__,
__LINE__, G_STRFUNC, msg);
+
+struct _Foo {
+ GObject parent_instance;
+ FooPrivate * priv;
+};
+
+struct _FooClass {
+ GObjectClass parent_class;
+};
+
+static gpointer foo_parent_class = NULL;
+
+VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, g_object_unref)
+VALA_EXTERN Foo* foo_new (void);
+VALA_EXTERN Foo* foo_construct (GType object_type);
+static GType foo_get_type_once (void);
+VALA_EXTERN void test_glist (void);
+static void _g_object_unref0_ (gpointer var);
+static inline void _g_list_free__g_object_unref0_ (GList* self);
+VALA_EXTERN void test_gslist (void);
+static inline void _g_slist_free__g_object_unref0_ (GSList* self);
+VALA_EXTERN void test_gqueue (void);
+static inline void _g_queue_free__g_object_unref0_ (GQueue* self);
+static void _vala_main (void);
+
+Foo*
+foo_construct (GType object_type)
+{
+ Foo * self = NULL;
+ self = (Foo*) g_object_new (object_type, NULL);
+ return self;
+}
+
+Foo*
+foo_new (void)
+{
+ return foo_construct (TYPE_FOO);
+}
+
+static void
+foo_class_init (FooClass * klass,
+ gpointer klass_data)
+{
+ foo_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+foo_instance_init (Foo * self,
+ gpointer klass)
+{
+}
+
+static GType
+foo_get_type_once (void)
+{
+ static const GTypeInfo g_define_type_info = { sizeof (FooClass), (GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL, (GClassInitFunc) foo_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Foo), 0,
(GInstanceInitFunc) foo_instance_init, NULL };
+ GType foo_type_id;
+ foo_type_id = g_type_register_static (G_TYPE_OBJECT, "Foo", &g_define_type_info, 0);
+ return foo_type_id;
+}
+
+GType
+foo_get_type (void)
+{
+ static volatile gsize foo_type_id__volatile = 0;
+ if (g_once_init_enter (&foo_type_id__volatile)) {
+ GType foo_type_id;
+ foo_type_id = foo_get_type_once ();
+ g_once_init_leave (&foo_type_id__volatile, foo_type_id);
+ }
+ return foo_type_id__volatile;
+}
+
+static gpointer
+_g_object_ref0 (gpointer self)
+{
+ return self ? g_object_ref (self) : NULL;
+}
+
+static GList*
+vala_g_list_remove_full (GList* self,
+ gconstpointer data,
+ GFreeFunc func)
+{
+ GList* l = NULL;
+ GList* result = NULL;
+ l = self;
+ while (TRUE) {
+ GList* _tmp0_;
+ GList* _tmp1_;
+ gconstpointer _tmp2_;
+ _tmp0_ = l;
+ if (!(_tmp0_ != NULL)) {
+ break;
+ }
+ _tmp1_ = l;
+ _tmp2_ = ((GList*) _tmp1_)->data;
+ if (_tmp2_ != data) {
+ GList* _tmp3_;
+ GList* _tmp4_;
+ _tmp3_ = l;
+ _tmp4_ = ((GList*) _tmp3_)->next;
+ l = _tmp4_;
+ } else {
+ GList* _tmp5_;
+ gconstpointer _tmp6_;
+ GList* _tmp7_;
+ _tmp5_ = l;
+ _tmp6_ = ((GList*) _tmp5_)->data;
+ func (_tmp6_);
+ _tmp7_ = l;
+ self = g_list_delete_link (self, (GList*) _tmp7_);
+ break;
+ }
+ }
+ result = self;
+ return result;
+}
+
+static void
+_g_object_unref0_ (gpointer var)
+{
+ (var == NULL) ? NULL : (var = (g_object_unref (var), NULL));
+}
+
+static inline void
+_g_list_free__g_object_unref0_ (GList* self)
+{
+ g_list_free_full (self, (GDestroyNotify) _g_object_unref0_);
+}
+
+static GList*
+vala_g_list_remove_all_full (GList* self,
+ gconstpointer data,
+ GFreeFunc func)
+{
+ GList* l = NULL;
+ GList* result = NULL;
+ l = self;
+ while (TRUE) {
+ GList* _tmp0_;
+ GList* _tmp1_;
+ gconstpointer _tmp2_;
+ _tmp0_ = l;
+ if (!(_tmp0_ != NULL)) {
+ break;
+ }
+ _tmp1_ = l;
+ _tmp2_ = ((GList*) _tmp1_)->data;
+ if (_tmp2_ != data) {
+ GList* _tmp3_;
+ GList* _tmp4_;
+ _tmp3_ = l;
+ _tmp4_ = ((GList*) _tmp3_)->next;
+ l = _tmp4_;
+ } else {
+ GList* _tmp5_;
+ gconstpointer _tmp6_;
+ GList* _tmp7_;
+ _tmp5_ = l;
+ _tmp6_ = ((GList*) _tmp5_)->data;
+ func (_tmp6_);
+ _tmp7_ = l;
+ self = g_list_delete_link (self, (GList*) _tmp7_);
+ l = self;
+ }
+ }
+ result = self;
+ return result;
+}
+
+void
+test_glist (void)
+{
+ {
+ GList* list = NULL;
+ Foo* foo = NULL;
+ Foo* _tmp0_;
+ Foo* _tmp1_;
+ list = NULL;
+ _tmp0_ = foo_new ();
+ foo = _tmp0_;
+ _tmp1_ = _g_object_ref0 (foo);
+ list = g_list_append (list, _tmp1_);
+ _vala_assert (g_list_length (list) == ((guint) 1), "list.length () == 1");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
2), "foo.ref_count == 2");
+ list = vala_g_list_remove_full (list, foo, _g_object_unref0_);
+ _vala_assert (g_list_length (list) == ((guint) 0), "list.length () == 0");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
1), "foo.ref_count == 1");
+ _g_object_unref0 (foo);
+ (list == NULL) ? NULL : (list = (_g_list_free__g_object_unref0_ (list), NULL));
+ }
+ {
+ GList* list = NULL;
+ Foo* foo = NULL;
+ Foo* _tmp2_;
+ Foo* _tmp3_;
+ Foo* _tmp4_;
+ list = NULL;
+ _tmp2_ = foo_new ();
+ foo = _tmp2_;
+ _tmp3_ = _g_object_ref0 (foo);
+ list = g_list_append (list, _tmp3_);
+ _tmp4_ = _g_object_ref0 (foo);
+ list = g_list_append (list, _tmp4_);
+ _vala_assert (g_list_length (list) == ((guint) 2), "list.length () == 2");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
3), "foo.ref_count == 3");
+ list = vala_g_list_remove_all_full (list, foo, _g_object_unref0_);
+ _vala_assert (g_list_length (list) == ((guint) 0), "list.length () == 0");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
1), "foo.ref_count == 1");
+ _g_object_unref0 (foo);
+ (list == NULL) ? NULL : (list = (_g_list_free__g_object_unref0_ (list), NULL));
+ }
+ {
+ GList* list = NULL;
+ const gchar* s = NULL;
+ list = NULL;
+ s = "foo";
+ list = g_list_append (list, s);
+ _vala_assert (g_list_length (list) == ((guint) 1), "list.length () == 1");
+ list = g_list_remove (list, s);
+ _vala_assert (g_list_length (list) == ((guint) 0), "list.length () == 0");
+ list = g_list_append (list, s);
+ list = g_list_remove_all (list, s);
+ _vala_assert (g_list_length (list) == ((guint) 0), "list.length () == 0");
+ (list == NULL) ? NULL : (list = (g_list_free (list), NULL));
+ }
+}
+
+static GSList*
+vala_g_slist_remove_full (GSList* self,
+ gconstpointer data,
+ GFreeFunc func)
+{
+ GSList* l = NULL;
+ GSList* result = NULL;
+ l = self;
+ while (TRUE) {
+ GSList* _tmp0_;
+ GSList* _tmp1_;
+ gconstpointer _tmp2_;
+ _tmp0_ = l;
+ if (!(_tmp0_ != NULL)) {
+ break;
+ }
+ _tmp1_ = l;
+ _tmp2_ = ((GSList*) _tmp1_)->data;
+ if (_tmp2_ != data) {
+ GSList* _tmp3_;
+ GSList* _tmp4_;
+ _tmp3_ = l;
+ _tmp4_ = ((GSList*) _tmp3_)->next;
+ l = _tmp4_;
+ } else {
+ GSList* _tmp5_;
+ gconstpointer _tmp6_;
+ GSList* _tmp7_;
+ _tmp5_ = l;
+ _tmp6_ = ((GSList*) _tmp5_)->data;
+ func (_tmp6_);
+ _tmp7_ = l;
+ self = g_slist_delete_link (self, (GSList*) _tmp7_);
+ break;
+ }
+ }
+ result = self;
+ return result;
+}
+
+static inline void
+_g_slist_free__g_object_unref0_ (GSList* self)
+{
+ g_slist_free_full (self, (GDestroyNotify) _g_object_unref0_);
+}
+
+static GSList*
+vala_g_slist_remove_all_full (GSList* self,
+ gconstpointer data,
+ GFreeFunc func)
+{
+ GSList* l = NULL;
+ GSList* result = NULL;
+ l = self;
+ while (TRUE) {
+ GSList* _tmp0_;
+ GSList* _tmp1_;
+ gconstpointer _tmp2_;
+ _tmp0_ = l;
+ if (!(_tmp0_ != NULL)) {
+ break;
+ }
+ _tmp1_ = l;
+ _tmp2_ = ((GSList*) _tmp1_)->data;
+ if (_tmp2_ != data) {
+ GSList* _tmp3_;
+ GSList* _tmp4_;
+ _tmp3_ = l;
+ _tmp4_ = ((GSList*) _tmp3_)->next;
+ l = _tmp4_;
+ } else {
+ GSList* _tmp5_;
+ gconstpointer _tmp6_;
+ GSList* _tmp7_;
+ _tmp5_ = l;
+ _tmp6_ = ((GSList*) _tmp5_)->data;
+ func (_tmp6_);
+ _tmp7_ = l;
+ self = g_slist_delete_link (self, (GSList*) _tmp7_);
+ l = self;
+ }
+ }
+ result = self;
+ return result;
+}
+
+void
+test_gslist (void)
+{
+ {
+ GSList* list = NULL;
+ Foo* foo = NULL;
+ Foo* _tmp0_;
+ Foo* _tmp1_;
+ list = NULL;
+ _tmp0_ = foo_new ();
+ foo = _tmp0_;
+ _tmp1_ = _g_object_ref0 (foo);
+ list = g_slist_append (list, _tmp1_);
+ _vala_assert (g_slist_length (list) == ((guint) 1), "list.length () == 1");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
2), "foo.ref_count == 2");
+ list = vala_g_slist_remove_full (list, foo, _g_object_unref0_);
+ _vala_assert (g_slist_length (list) == ((guint) 0), "list.length () == 0");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
1), "foo.ref_count == 1");
+ _g_object_unref0 (foo);
+ (list == NULL) ? NULL : (list = (_g_slist_free__g_object_unref0_ (list), NULL));
+ }
+ {
+ GSList* list = NULL;
+ Foo* foo = NULL;
+ Foo* _tmp2_;
+ Foo* _tmp3_;
+ Foo* _tmp4_;
+ list = NULL;
+ _tmp2_ = foo_new ();
+ foo = _tmp2_;
+ _tmp3_ = _g_object_ref0 (foo);
+ list = g_slist_append (list, _tmp3_);
+ _tmp4_ = _g_object_ref0 (foo);
+ list = g_slist_append (list, _tmp4_);
+ _vala_assert (g_slist_length (list) == ((guint) 2), "list.length () == 2");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
3), "foo.ref_count == 3");
+ list = vala_g_slist_remove_all_full (list, foo, _g_object_unref0_);
+ _vala_assert (g_slist_length (list) == ((guint) 0), "list.length () == 0");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
1), "foo.ref_count == 1");
+ _g_object_unref0 (foo);
+ (list == NULL) ? NULL : (list = (_g_slist_free__g_object_unref0_ (list), NULL));
+ }
+ {
+ GSList* list = NULL;
+ const gchar* s = NULL;
+ list = NULL;
+ s = "foo";
+ list = g_slist_append (list, s);
+ _vala_assert (g_slist_length (list) == ((guint) 1), "list.length () == 1");
+ list = g_slist_remove (list, s);
+ _vala_assert (g_slist_length (list) == ((guint) 0), "list.length () == 0");
+ list = g_slist_append (list, s);
+ list = g_slist_remove_all (list, s);
+ _vala_assert (g_slist_length (list) == ((guint) 0), "list.length () == 0");
+ (list == NULL) ? NULL : (list = (g_slist_free (list), NULL));
+ }
+}
+
+static gboolean
+vala_g_queue_remove_full (GQueue* self,
+ gconstpointer data,
+ GFreeFunc func)
+{
+ GList* l = NULL;
+ GList* _tmp0_;
+ GList* _tmp1_;
+ GList* _tmp2_;
+ gboolean result = FALSE;
+ g_return_val_if_fail (self != NULL, FALSE);
+ _tmp0_ = self->head;
+ _tmp1_ = g_list_find (_tmp0_, data);
+ l = _tmp1_;
+ _tmp2_ = l;
+ if (_tmp2_ != NULL) {
+ GList* _tmp3_;
+ gconstpointer _tmp4_;
+ GList* _tmp5_;
+ _tmp3_ = l;
+ _tmp4_ = ((GList*) _tmp3_)->data;
+ func (_tmp4_);
+ _tmp5_ = l;
+ g_queue_delete_link (self, (GList*) _tmp5_);
+ result = TRUE;
+ return result;
+ } else {
+ result = FALSE;
+ return result;
+ }
+}
+
+static inline void
+_g_queue_free__g_object_unref0_ (GQueue* self)
+{
+ g_queue_free_full (self, (GDestroyNotify) _g_object_unref0_);
+}
+
+static guint
+vala_g_queue_remove_all_full (GQueue* self,
+ gconstpointer data,
+ GFreeFunc func)
+{
+ guint old_length = 0U;
+ GList* l = NULL;
+ GList* _tmp0_;
+ guint result = 0U;
+ g_return_val_if_fail (self != NULL, 0U);
+ old_length = self->length;
+ _tmp0_ = self->head;
+ l = _tmp0_;
+ while (TRUE) {
+ GList* _tmp1_;
+ GList* next = NULL;
+ GList* _tmp2_;
+ GList* _tmp3_;
+ GList* _tmp4_;
+ gconstpointer _tmp5_;
+ GList* _tmp9_;
+ _tmp1_ = l;
+ if (!(_tmp1_ != NULL)) {
+ break;
+ }
+ _tmp2_ = l;
+ _tmp3_ = ((GList*) _tmp2_)->next;
+ next = _tmp3_;
+ _tmp4_ = l;
+ _tmp5_ = ((GList*) _tmp4_)->data;
+ if (_tmp5_ == data) {
+ GList* _tmp6_;
+ gconstpointer _tmp7_;
+ GList* _tmp8_;
+ _tmp6_ = l;
+ _tmp7_ = ((GList*) _tmp6_)->data;
+ func (_tmp7_);
+ _tmp8_ = l;
+ g_queue_delete_link (self, (GList*) _tmp8_);
+ }
+ _tmp9_ = next;
+ l = _tmp9_;
+ }
+ result = old_length - self->length;
+ return result;
+}
+
+void
+test_gqueue (void)
+{
+ {
+ GQueue* queue = NULL;
+ GQueue* _tmp0_;
+ Foo* foo = NULL;
+ Foo* _tmp1_;
+ Foo* _tmp2_;
+ _tmp0_ = g_queue_new ();
+ queue = _tmp0_;
+ _tmp1_ = foo_new ();
+ foo = _tmp1_;
+ _tmp2_ = _g_object_ref0 (foo);
+ g_queue_push_head (queue, _tmp2_);
+ _vala_assert (queue->length == ((guint) 1), "queue.length == 1");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
2), "foo.ref_count == 2");
+ vala_g_queue_remove_full (queue, foo, _g_object_unref0_);
+ _vala_assert (queue->length == ((guint) 0), "queue.length == 0");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
1), "foo.ref_count == 1");
+ _g_object_unref0 (foo);
+ (queue == NULL) ? NULL : (queue = (_g_queue_free__g_object_unref0_ (queue), NULL));
+ }
+ {
+ GQueue* queue = NULL;
+ GQueue* _tmp3_;
+ Foo* foo = NULL;
+ Foo* _tmp4_;
+ Foo* _tmp5_;
+ Foo* _tmp6_;
+ _tmp3_ = g_queue_new ();
+ queue = _tmp3_;
+ _tmp4_ = foo_new ();
+ foo = _tmp4_;
+ _tmp5_ = _g_object_ref0 (foo);
+ g_queue_push_head (queue, _tmp5_);
+ _tmp6_ = _g_object_ref0 (foo);
+ g_queue_push_head (queue, _tmp6_);
+ _vala_assert (queue->length == ((guint) 2), "queue.length == 2");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
3), "foo.ref_count == 3");
+ vala_g_queue_remove_all_full (queue, foo, _g_object_unref0_);
+ _vala_assert (queue->length == ((guint) 0), "queue.length == 0");
+ _vala_assert (G_TYPE_CHECK_INSTANCE_CAST (foo, G_TYPE_OBJECT, GObject)->ref_count == ((guint)
1), "foo.ref_count == 1");
+ _g_object_unref0 (foo);
+ (queue == NULL) ? NULL : (queue = (_g_queue_free__g_object_unref0_ (queue), NULL));
+ }
+ {
+ GQueue* queue = NULL;
+ GQueue* _tmp7_;
+ const gchar* s = NULL;
+ _tmp7_ = g_queue_new ();
+ queue = _tmp7_;
+ s = "foo";
+ g_queue_push_head (queue, s);
+ _vala_assert (queue->length == ((guint) 1), "queue.length == 1");
+ g_queue_remove (queue, s);
+ _vala_assert (queue->length == ((guint) 0), "queue.length == 0");
+ g_queue_push_head (queue, s);
+ g_queue_remove_all (queue, s);
+ _vala_assert (queue->length == ((guint) 0), "queue.length == 0");
+ (queue == NULL) ? NULL : (queue = (g_queue_free (queue), NULL));
+ }
+}
+
+static void
+_vala_main (void)
+{
+ test_glist ();
+ test_gslist ();
+ test_gqueue ();
+}
+
+int
+main (int argc,
+ char ** argv)
+{
+ _vala_main ();
+ return 0;
+}
+
diff --git a/tests/basic-types/glists_remove.vala b/tests/basic-types/glists_remove.vala
new file mode 100644
index 000000000..8770f60f8
--- /dev/null
+++ b/tests/basic-types/glists_remove.vala
@@ -0,0 +1,113 @@
+class Foo : Object {
+}
+
+void test_glist () {
+ {
+ var list = new GLib.List<Foo> ();
+ var foo = new Foo ();
+ list.append (foo);
+ assert (list.length () == 1);
+ assert (foo.ref_count == 2);
+ list.remove (foo);
+ assert (list.length () == 0);
+ assert (foo.ref_count == 1);
+ }
+ {
+ var list = new GLib.List<Foo> ();
+ var foo = new Foo ();
+ list.append (foo);
+ list.append (foo);
+ assert (list.length () == 2);
+ assert (foo.ref_count == 3);
+ list.remove_all (foo);
+ assert (list.length () == 0);
+ assert (foo.ref_count == 1);
+ }
+ {
+ var list = new GLib.List<unowned string> ();
+ unowned var s = "foo";
+ list.append (s);
+ assert (list.length () == 1);
+ list.remove (s);
+ assert (list.length () == 0);
+ list.append (s);
+ list.remove_all (s);
+ assert (list.length () == 0);
+ }
+}
+
+void test_gslist () {
+ {
+ var list = new GLib.SList<Foo> ();
+ var foo = new Foo ();
+ list.append (foo);
+ assert (list.length () == 1);
+ assert (foo.ref_count == 2);
+ list.remove (foo);
+ assert (list.length () == 0);
+ assert (foo.ref_count == 1);
+ }
+ {
+ var list = new GLib.SList<Foo> ();
+ var foo = new Foo ();
+ list.append (foo);
+ list.append (foo);
+ assert (list.length () == 2);
+ assert (foo.ref_count == 3);
+ list.remove_all (foo);
+ assert (list.length () == 0);
+ assert (foo.ref_count == 1);
+ }
+ {
+ var list = new GLib.SList<unowned string> ();
+ unowned var s = "foo";
+ list.append (s);
+ assert (list.length () == 1);
+ list.remove (s);
+ assert (list.length () == 0);
+ list.append (s);
+ list.remove_all (s);
+ assert (list.length () == 0);
+ }
+}
+
+void test_gqueue () {
+ {
+ var queue = new GLib.Queue<Foo> ();
+ var foo = new Foo ();
+ queue.push_head (foo);
+ assert (queue.length == 1);
+ assert (foo.ref_count == 2);
+ queue.remove (foo);
+ assert (queue.length == 0);
+ assert (foo.ref_count == 1);
+ }
+ {
+ var queue = new GLib.Queue<Foo> ();
+ var foo = new Foo ();
+ queue.push_head (foo);
+ queue.push_head (foo);
+ assert (queue.length == 2);
+ assert (foo.ref_count == 3);
+ queue.remove_all (foo);
+ assert (queue.length == 0);
+ assert (foo.ref_count == 1);
+ }
+ {
+ var queue = new GLib.Queue<unowned string> ();
+ unowned var s = "foo";
+ queue.push_head (s);
+ assert (queue.length == 1);
+ queue.remove (s);
+ assert (queue.length == 0);
+ queue.push_head (s);
+ queue.remove_all (s);
+ assert (queue.length == 0);
+ }
+}
+
+void main () {
+ test_glist ();
+ test_gslist ();
+ test_gqueue ();
+}
diff --git a/vapi/glib-2.0.vapi b/vapi/glib-2.0.vapi
index 6d2d44ef5..86bdfa88c 100644
--- a/vapi/glib-2.0.vapi
+++ b/vapi/glib-2.0.vapi
@@ -5015,12 +5015,42 @@ namespace GLib {
public void insert_sorted (owned G data, CompareFunc<G> compare_func);
[ReturnsModifiedPointer ()]
public void remove (G data);
+ [CCode (cname = "vala_g_list_remove_full")]
+ [ReturnsModifiedPointer ()]
+ public unowned List<G> remove_full (G data, FreeFunc? func) {
+ unowned List<G>? l = this;
+ while (l != null) {
+ if (((!) l).data != data) {
+ l = ((!) l).next;
+ } else {
+ func (((!) l).data);
+ delete_link ((!) l);
+ break;
+ }
+ }
+ return this;
+ }
[ReturnsModifiedPointer ()]
public void remove_link (List<G> llink);
[ReturnsModifiedPointer ()]
public void delete_link (List<G> link_);
[ReturnsModifiedPointer ()]
public void remove_all (G data);
+ [CCode (cname = "vala_g_list_remove_all_full")]
+ [ReturnsModifiedPointer ()]
+ public unowned List<G> remove_all_full (G data, FreeFunc? func) {
+ unowned List<G>? l = this;
+ while (l != null) {
+ if (((!) l).data != data) {
+ l = ((!) l).next;
+ } else {
+ func (((!) l).data);
+ delete_link ((!) l);
+ l = this;
+ }
+ }
+ return this;
+ }
public uint length ();
public List<unowned G> copy ();
@@ -5082,12 +5112,42 @@ namespace GLib {
public void insert_sorted (owned G data, CompareFunc<G> compare_func);
[ReturnsModifiedPointer ()]
public void remove (G data);
+ [CCode (cname = "vala_g_slist_remove_full")]
+ [ReturnsModifiedPointer ()]
+ public unowned SList<G> remove_full (G data, FreeFunc? func) {
+ unowned SList<G>? l = this;
+ while (l != null) {
+ if (((!) l).data != data) {
+ l = ((!) l).next;
+ } else {
+ func (((!) l).data);
+ delete_link ((!) l);
+ break;
+ }
+ }
+ return this;
+ }
[ReturnsModifiedPointer ()]
public void remove_link (SList<G> llink);
[ReturnsModifiedPointer ()]
public void delete_link (SList<G> link_);
[ReturnsModifiedPointer ()]
public void remove_all (G data);
+ [CCode (cname = "vala_g_slist_remove_all_full")]
+ [ReturnsModifiedPointer ()]
+ public unowned SList<G> remove_all_full (G data, FreeFunc? func) {
+ unowned SList<G>? l = this;
+ while (l != null) {
+ if (((!) l).data != data) {
+ l = ((!) l).next;
+ } else {
+ func (((!) l).data);
+ delete_link ((!) l);
+ l = this;
+ }
+ }
+ return this;
+ }
public uint length ();
public SList<unowned G> copy ();
@@ -5186,8 +5246,33 @@ namespace GLib {
public int index (G data);
[Version (since = "2.4")]
public bool remove (G data);
+ [CCode (cname = "vala_g_queue_remove_full")]
+ public bool remove_full (G data, FreeFunc? func) {
+ unowned List<G>? l = head.find (data);
+ if (l != null) {
+ func (((!) l).data);
+ delete_link ((!) l);
+ return true;
+ } else {
+ return false;
+ }
+ }
[Version (since = "2.4")]
public uint remove_all (G data);
+ [CCode (cname = "vala_g_queue_remove_all_full")]
+ public uint remove_all_full (G data, FreeFunc? func) {
+ var old_length = length;
+ unowned List<G>? l = head;
+ while (l != null) {
+ unowned List<G>? next = ((!) l).next;
+ if (((!) l).data == data) {
+ func (((!) l).data);
+ delete_link ((!) l);
+ }
+ l = next;
+ }
+ return old_length - length;
+ }
[Version (since = "2.4")]
public void delete_link (List<G> link);
[Version (since = "2.4")]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]