1 /*
2  * libInstPatch
3  * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; version 2.1
8  * of the License only.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA or on the web at http://www.gnu.org.
19  */
20 /**
21  * SECTION: IpatchList
22  * @short_description: An object containing a list of object pointers
23  * @see_also:
24  * @stability: Stable
25  *
26  * An object which defines a list of object pointers.  A #GObject reference
27  * is held to all objects until the #IpatchList itself is released.
28  */
29 #include <glib.h>
30 #include <glib-object.h>
31 #include "IpatchList.h"
32 
33 static void ipatch_list_class_init(IpatchListClass *klass);
34 static void ipatch_list_finalize(GObject *gobject);
35 
36 static GObjectClass *parent_class = NULL;
37 
38 
39 GType
ipatch_list_get_type(void)40 ipatch_list_get_type(void)
41 {
42     static GType item_type = 0;
43 
44     if(!item_type)
45     {
46         static const GTypeInfo item_info =
47         {
48             sizeof(IpatchListClass), NULL, NULL,
49             (GClassInitFunc) ipatch_list_class_init, NULL, NULL,
50             sizeof(IpatchList), 0,
51             (GInstanceInitFunc) NULL,
52         };
53 
54         item_type = g_type_register_static(G_TYPE_OBJECT, "IpatchList",
55                                            &item_info, 0);
56     }
57 
58     return (item_type);
59 }
60 
61 static void
ipatch_list_class_init(IpatchListClass * klass)62 ipatch_list_class_init(IpatchListClass *klass)
63 {
64     GObjectClass *obj_class = G_OBJECT_CLASS(klass);
65     parent_class = g_type_class_peek_parent(klass);
66     obj_class->finalize = ipatch_list_finalize;
67 }
68 
69 static void
ipatch_list_finalize(GObject * gobject)70 ipatch_list_finalize(GObject *gobject)
71 {
72     IpatchList *list = IPATCH_LIST(gobject);
73     GList *p;
74 
75     p = list->items;
76 
77     while(p)	   /* unref all objects in list and destroy the list */
78     {
79         g_object_unref(p->data);
80         p = g_list_delete_link(p, p);
81     }
82 
83     list->items = NULL;
84 
85     if(parent_class->finalize)
86     {
87         parent_class->finalize(gobject);
88     }
89 }
90 
91 /**
92  * ipatch_list_new:
93  *
94  * Create a new object list object. #IpatchList objects are often used to
95  * duplicate multi-thread sensitive object lists, so they can be iterated over
96  * at one's own leasure.
97  *
98  * Returns: New object list container object.
99  */
100 IpatchList *
ipatch_list_new(void)101 ipatch_list_new(void)
102 {
103     return (IPATCH_LIST(g_object_new(IPATCH_TYPE_LIST, NULL)));
104 }
105 
106 /**
107  * ipatch_list_duplicate:
108  * @list: Object list to duplicate
109  *
110  * Duplicate an object list.
111  *
112  * Returns: (transfer full): New duplicate object list with a ref count of one which the
113  *   caller owns.
114  */
115 IpatchList *
ipatch_list_duplicate(IpatchList * list)116 ipatch_list_duplicate(IpatchList *list)
117 {
118     IpatchList *newlist;
119     GList *p;
120 
121     g_return_val_if_fail(IPATCH_IS_LIST(list), NULL);
122 
123     newlist = ipatch_list_new();	/* ++ ref new list */
124     p = list->items;
125 
126     while(p)
127     {
128         if(p->data)
129         {
130             g_object_ref(p->data);    /* ++ ref object for new list */
131         }
132 
133         newlist->items = g_list_prepend(newlist->items, p->data);
134         p = g_list_next(p);
135     }
136 
137     newlist->items = g_list_reverse(newlist->items);
138 
139     return (newlist);	   /* !! caller owns the new list reference */
140 }
141 
142 /**
143  * ipatch_list_get_items:
144  * @list: List object
145  *
146  * Get the items list in a #IpatchList object. Mainly for the benefit of
147  * GObject Introspection, since it is common practice to just access the
148  * <structfield>items</structfield> field directly.
149  *
150  * Returns: (element-type GObject) (transfer none): The list of items in
151  *   the @list object, which is owned by the @list and should not be
152  *   modified or freed directly.
153  *
154  * Since: 1.1.0
155  */
156 GList *
ipatch_list_get_items(IpatchList * list)157 ipatch_list_get_items(IpatchList *list)
158 {
159     g_return_val_if_fail(IPATCH_IS_LIST(list), NULL);
160 
161     return list->items;
162 }
163 
164 /**
165  * ipatch_list_set_items:
166  * @list: List object
167  * @items: (element-type GObject) (transfer full): List of #GObject pointers to assign,
168  *   @list takes over ownership, each object should be referenced already for the list
169  *
170  * Set the items list in a #IpatchList object. Mainly for the benefit of
171  * GObject Introspection, since it is common practice to just access the
172  * <structfield>items</structfield> field directly.  Replaces existing items
173  * (list if any).
174  *
175  * Since: 1.1.0
176  */
177 void
ipatch_list_set_items(IpatchList * list,GList * items)178 ipatch_list_set_items(IpatchList *list, GList *items)
179 {
180     GList *p;
181 
182     g_return_if_fail(IPATCH_IS_LIST(list));
183 
184     for(p = list->items; p; p = g_list_delete_link(p, p))
185     {
186         g_object_unref(p->data);
187     }
188 
189     list->items = items;  // !! list takes over items
190 }
191 
192 /**
193  * ipatch_list_append:
194  * @list: List object
195  * @object: Object to append to the list
196  *
197  * Append an object to an #IpatchList.
198  *
199  * Since: 1.1.0
200  */
201 void
ipatch_list_append(IpatchList * list,GObject * object)202 ipatch_list_append(IpatchList *list, GObject *object)
203 {
204     g_return_if_fail(IPATCH_IS_LIST(list));
205     g_return_if_fail(G_IS_OBJECT(object));
206 
207     g_object_ref(object);         // ++ ref for list
208     list->items = g_list_append(list->items, object);
209 }
210 
211 /**
212  * ipatch_list_prepend:
213  * @list: List object
214  * @object: Object to prepend to the list
215  *
216  * Prepend an object to an #IpatchList.
217  *
218  * Since: 1.1.0
219  */
220 void
ipatch_list_prepend(IpatchList * list,GObject * object)221 ipatch_list_prepend(IpatchList *list, GObject *object)
222 {
223     g_return_if_fail(IPATCH_IS_LIST(list));
224     g_return_if_fail(G_IS_OBJECT(object));
225 
226     g_object_ref(object);         // ++ ref for list
227     list->items = g_list_prepend(list->items, object);
228 }
229 
230 /**
231  * ipatch_list_insert:
232  * @list: List object
233  * @object: Object to insert into the list
234  * @pos: Position to insert into (0 for start of list, -1 to append)
235  *
236  * Append an object to an #IpatchList.
237  *
238  * Since: 1.1.0
239  */
240 void
ipatch_list_insert(IpatchList * list,GObject * object,int pos)241 ipatch_list_insert(IpatchList *list, GObject *object, int pos)
242 {
243     g_return_if_fail(IPATCH_IS_LIST(list));
244     g_return_if_fail(G_IS_OBJECT(object));
245 
246     g_object_ref(object);         // ++ ref for list
247     list->items = g_list_insert(list->items, object, pos);
248 }
249 
250 /**
251  * ipatch_list_remove:
252  * @list: List object
253  * @object: Object to remove from the list
254  *
255  * Remove an object from an #IpatchList.
256  *
257  * Returns: %TRUE if found and removed, %FALSE otherwise
258  *
259  * Since: 1.1.0
260  */
261 gboolean
ipatch_list_remove(IpatchList * list,GObject * object)262 ipatch_list_remove(IpatchList *list, GObject *object)
263 {
264     GList *p;
265 
266     g_return_val_if_fail(IPATCH_IS_LIST(list), FALSE);
267     g_return_val_if_fail(G_IS_OBJECT(object), FALSE);
268 
269     p = g_list_find(list->items, object);
270 
271     if(!p)
272     {
273         return (FALSE);
274     }
275 
276     g_object_unref(p->data);      // -- unref object
277     list->items = g_list_delete_link(list->items, p);
278 
279     return (TRUE);
280 }
281 
282 /**
283  * ipatch_list_init_iter: (skip)
284  * @list: List object
285  * @iter: Iterator to initialize
286  *
287  * Initializes a user supplied iterator (usually stack allocated) to iterate
288  * over the object @list. Further operations on @iter will use the @list.
289  */
290 void
ipatch_list_init_iter(IpatchList * list,IpatchIter * iter)291 ipatch_list_init_iter(IpatchList *list, IpatchIter *iter)
292 {
293     g_return_if_fail(IPATCH_IS_LIST(list));
294     g_return_if_fail(iter != NULL);
295 
296     ipatch_iter_GList_init(iter, &list->items);
297 }
298