miniobject: make queries a boxed type
[platform/upstream/gstreamer.git] / gst / gstminiobject.c
1 /* GStreamer
2  * Copyright (C) 2005 David Schleef <ds@schleef.org>
3  *
4  * gstminiobject.h: Header for GstMiniObject
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /**
22  * SECTION:gstminiobject
23  * @short_description: Lightweight base class for the GStreamer object hierarchy
24  *
25  * #GstMiniObject is a baseclass like #GObject, but has been stripped down of
26  * features to be fast and small.
27  * It offers sub-classing and ref-counting in the same way as #GObject does.
28  * It has no properties and no signal-support though.
29  *
30  * Last reviewed on 2005-11-23 (0.9.5)
31  */
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include "gst/gst_private.h"
37 #include "gst/gstminiobject.h"
38 #include "gst/gstinfo.h"
39 #include <gobject/gvaluecollector.h>
40
41 #ifndef GST_DISABLE_TRACE
42 #include "gsttrace.h"
43 static GstAllocTrace *_gst_mini_object_trace;
44 #endif
45
46 #define GST_MINI_OBJECT_GET_CLASS_UNCHECKED(obj) \
47     ((GstMiniObjectClass *) (((GTypeInstance*)(obj))->g_class))
48
49 /* boxed copy and free functions. Don't real copy or free but simply
50  * change the refcount */
51 static GstMiniObject *
52 _gst_mini_object_boxed_copy (GstMiniObject * mini_object)
53 {
54   if (mini_object)
55     return gst_mini_object_ref (mini_object);
56   else
57     return NULL;
58 }
59
60 static void
61 _gst_mini_object_boxed_free (GstMiniObject * mini_object)
62 {
63   if (mini_object)
64     gst_mini_object_unref (mini_object);
65 }
66
67 /**
68  * gst_mini_object_register:
69  * @name: name of the new boxed type
70  *
71  * This function creates a new G_TYPE_BOXED derived type id for a new boxed type
72  * with name @name. The default miniobject refcounting copy and free function
73  * are used for the boxed type.
74  *
75  * Returns: a new G_TYPE_BOXED derived type id for @name.
76  */
77 GType
78 gst_mini_object_register (const gchar * name)
79 {
80   GType type;
81
82   g_return_val_if_fail (name != NULL, 0);
83
84   type = g_boxed_type_register_static (name,
85       (GBoxedCopyFunc) _gst_mini_object_boxed_copy,
86       (GBoxedFreeFunc) _gst_mini_object_boxed_free);
87
88   return type;
89 }
90
91 /**
92  * gst_mini_object_init:
93  * @mini_object: a #GstMiniObject 
94  * @type: the #GType of the mini-object to create
95  * @size: the size of the data
96  *
97  * Initializes a mini-object with the desired type and size.
98  *
99  * MT safe
100  *
101  * Returns: (transfer full): the new mini-object.
102  */
103 void
104 gst_mini_object_init (GstMiniObject * mini_object, GType type, gsize size)
105 {
106   mini_object->type = type;
107   mini_object->refcount = 1;
108   mini_object->size = size;
109 }
110
111 /* FIXME 0.11: Current way of doing the copy makes it impossible
112  * to currectly chain to the parent classes and do a copy in a
113  * subclass without knowing all internals of the parent classes.
114  *
115  * For 0.11 we should do something like the following:
116  *  - The GstMiniObjectClass::copy() implementation of GstMiniObject
117  *    should call g_type_create_instance() with the type of the source
118  *    object.
119  *  - All GstMiniObjectClass::copy() implementations should as first
120  *    thing chain up to the parent class and then do whatever they need
121  *    to do to copy their type specific data. Note that this way the
122  *    instance_init() functions are called!
123  */
124
125 /**
126  * gst_mini_object_copy:
127  * @mini_object: the mini-object to copy
128  *
129  * Creates a copy of the mini-object.
130  *
131  * MT safe
132  *
133  * Returns: (transfer full): the new mini-object.
134  */
135 GstMiniObject *
136 gst_mini_object_copy (const GstMiniObject * mini_object)
137 {
138   GstMiniObject *copy;
139
140   g_return_val_if_fail (mini_object != NULL, NULL);
141
142   if (mini_object->copy)
143     copy = mini_object->copy (mini_object);
144   else
145     copy = NULL;
146
147   return copy;
148 }
149
150 /**
151  * gst_mini_object_is_writable:
152  * @mini_object: the mini-object to check
153  *
154  * Checks if a mini-object is writable.  A mini-object is writable
155  * if the reference count is one and the #GST_MINI_OBJECT_FLAG_READONLY
156  * flag is not set.  Modification of a mini-object should only be
157  * done after verifying that it is writable.
158  *
159  * MT safe
160  *
161  * Returns: TRUE if the object is writable.
162  */
163 gboolean
164 gst_mini_object_is_writable (const GstMiniObject * mini_object)
165 {
166   g_return_val_if_fail (mini_object != NULL, FALSE);
167
168   return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1) &&
169       ((mini_object->flags & GST_MINI_OBJECT_FLAG_READONLY) == 0);
170 }
171
172 /**
173  * gst_mini_object_make_writable:
174  * @mini_object: (transfer full): the mini-object to make writable
175  *
176  * Checks if a mini-object is writable.  If not, a writable copy is made and
177  * returned.  This gives away the reference to the original mini object,
178  * and returns a reference to the new object.
179  *
180  * MT safe
181  *
182  * Returns: (transfer full): a mini-object (possibly the same pointer) that
183  *     is writable.
184  */
185 GstMiniObject *
186 gst_mini_object_make_writable (GstMiniObject * mini_object)
187 {
188   GstMiniObject *ret;
189
190   g_return_val_if_fail (mini_object != NULL, NULL);
191
192   if (gst_mini_object_is_writable (mini_object)) {
193     ret = mini_object;
194   } else {
195     GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject",
196         g_type_name (G_TYPE_FROM_INSTANCE (mini_object)));
197     ret = gst_mini_object_copy (mini_object);
198     gst_mini_object_unref (mini_object);
199   }
200
201   return ret;
202 }
203
204 /**
205  * gst_mini_object_ref:
206  * @mini_object: the mini-object
207  *
208  * Increase the reference count of the mini-object.
209  *
210  * Note that the refcount affects the writeability
211  * of @mini-object, see gst_mini_object_is_writable(). It is
212  * important to note that keeping additional references to
213  * GstMiniObject instances can potentially increase the number
214  * of memcpy operations in a pipeline, especially if the miniobject
215  * is a #GstBuffer.
216  *
217  * Returns: the mini-object.
218  */
219 GstMiniObject *
220 gst_mini_object_ref (GstMiniObject * mini_object)
221 {
222   g_return_val_if_fail (mini_object != NULL, NULL);
223   /* we can't assert that the refcount > 0 since the _free functions
224    * increments the refcount from 0 to 1 again to allow resurecting
225    * the object
226    g_return_val_if_fail (mini_object->refcount > 0, NULL);
227    */
228   g_return_val_if_fail (GST_IS_MINI_OBJECT (mini_object), NULL);
229
230   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
231       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
232       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
233
234   g_atomic_int_inc (&mini_object->refcount);
235
236   return mini_object;
237 }
238
239 /**
240  * gst_mini_object_unref:
241  * @mini_object: the mini-object
242  *
243  * Decreases the reference count of the mini-object, possibly freeing
244  * the mini-object.
245  */
246 void
247 gst_mini_object_unref (GstMiniObject * mini_object)
248 {
249   g_return_if_fail (GST_IS_MINI_OBJECT (mini_object));
250   g_return_if_fail (mini_object->refcount > 0);
251
252   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
253       mini_object,
254       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
255       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
256
257   if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
258     /* At this point, the refcount of the object is 0. We increase the refcount
259      * here because if a subclass recycles the object and gives out a new
260      * reference we don't want to free the instance anymore. */
261     gst_mini_object_ref (mini_object);
262
263     if (mini_object->dispose)
264       mini_object->dispose (mini_object);
265
266     /* decrement the refcount again, if the subclass recycled the object we don't
267      * want to free the instance anymore */
268     if (G_LIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
269 #ifndef GST_DISABLE_TRACE
270       gst_alloc_trace_free (_gst_mini_object_trace, mini_object);
271 #endif
272       if (mini_object->free)
273         mini_object->free (mini_object);
274     }
275   }
276 }
277
278 /**
279  * gst_mini_object_replace:
280  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
281  *     be replaced
282  * @newdata: pointer to new mini-object
283  *
284  * Modifies a pointer to point to a new mini-object.  The modification
285  * is done atomically, and the reference counts are updated correctly.
286  * Either @newdata and the value pointed to by @olddata may be NULL.
287  */
288 void
289 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
290 {
291   GstMiniObject *olddata_val;
292
293   g_return_if_fail (olddata != NULL);
294
295   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
296       *olddata, *olddata ? (*olddata)->refcount : 0,
297       newdata, newdata ? newdata->refcount : 0);
298
299   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
300
301   if (olddata_val == newdata)
302     return;
303
304   if (newdata)
305     gst_mini_object_ref (newdata);
306
307   while (!g_atomic_pointer_compare_and_exchange ((gpointer *) olddata,
308           olddata_val, newdata)) {
309     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
310   }
311
312   if (olddata_val)
313     gst_mini_object_unref (olddata_val);
314 }