libs/gst/controller/gstinterpolationcontrolsource.c: Optimize list handling. Use...
authorStefan Kost <ensonic@users.sourceforge.net>
Sun, 29 Jun 2008 16:11:24 +0000 (16:11 +0000)
committerStefan Kost <ensonic@users.sourceforge.net>
Sun, 29 Jun 2008 16:11:24 +0000 (16:11 +0000)
Original commit message from CVS:
* libs/gst/controller/gstinterpolationcontrolsource.c:
Optimize list handling. Use own find function. Exploit that fact that
the list is sorted. Also pass back the node before, so that we can
insert quickly. Have a fast path for append.

ChangeLog
libs/gst/controller/gstinterpolationcontrolsource.c

index 73a8f07..c0b2930 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2008-06-29  Stefan Kost  <ensonic@users.sf.net>
 
+       * libs/gst/controller/gstinterpolationcontrolsource.c:
+         Optimize list handling. Use own find function. Exploit that fact that
+         the list is sorted. Also pass back the node before, so that we can
+         insert quickly. Have a fast path for append.
+
+2008-06-29  Stefan Kost  <ensonic@users.sf.net>
+
        * docs/design/draft-framestep.txt:
        * docs/design/part-negotiation.txt:
          Fix two typos.
index 1263c9f..918ebf4 100644 (file)
@@ -415,34 +415,104 @@ gst_control_point_find (gconstpointer p1, gconstpointer p2)
   return ((ct1 < ct2) ? -1 : ((ct1 == ct2) ? 0 : 1));
 }
 
+/*
+ * _list_find_sorted_custom:
+ *
+ * This works like g_list_find_custom() with the difference that it expects the
+ * list to be sorted in ascending order (0->MAX), stops when it the list-values
+ * are bigger that what is searched for and optionaly delivers the last node
+ * back in the @prev_node argument. This can be used to quickly insert a new
+ * node at the correct position. 
+ */
+static GList *
+_list_find_sorted_custom (GList * list, gconstpointer data, GCompareFunc func,
+    GList ** prev_node)
+{
+  g_return_val_if_fail (func != NULL, list);
+  GList *prev = list;
+  gint cmp;
+
+  while (list) {
+    cmp = func (list->data, data);
+    switch (cmp) {
+      case -1:
+        prev = list;
+        list = list->next;
+        break;
+      case 0:
+        return list;
+      case 1:
+        if (prev_node)
+          *prev_node = prev;
+        return NULL;
+    }
+  }
+  if (prev_node)
+    *prev_node = prev;
+  return NULL;
+}
+
+static GstControlPoint *
+_make_new_cp (GstInterpolationControlSource * self, GstClockTime timestamp,
+    GValue * value)
+{
+  GstControlPoint *cp;
+
+  /* create a new GstControlPoint */
+  cp = g_slice_new0 (GstControlPoint);
+  cp->timestamp = timestamp;
+  g_value_init (&cp->value, self->priv->type);
+  g_value_copy (value, &cp->value);
+
+  return cp;
+}
+
 static void
 gst_interpolation_control_source_set_internal (GstInterpolationControlSource *
     self, GstClockTime timestamp, GValue * value)
 {
-  GstControlPoint *cp;
-  GList *node;
+  GList *node, *prev = self->priv->values;
+
+  /* check if we can shortcut and append */
+  if ((node = g_list_last (self->priv->values))) {
+    GstControlPoint *last_cp = node->data;
+
+    if (timestamp > last_cp->timestamp) {
+      /* pass 'node' instead of list, and also deliberately ignore the result */
+      node = g_list_append (node, _make_new_cp (self, timestamp, value));
+      self->priv->nvalues++;
+      goto done;
+    }
+  }
 
   /* check if a control point for the timestamp already exists */
-  if ((node = g_list_find_custom (self->priv->values, &timestamp,
-              gst_control_point_find))) {
-    cp = node->data;
+  if ((node = _list_find_sorted_custom (self->priv->values, &timestamp,
+              gst_control_point_find, &prev))) {
+    /* update control point */
+    GstControlPoint *cp = node->data;
     g_value_reset (&cp->value);
     g_value_copy (value, &cp->value);
   } else {
-    /* create a new GstControlPoint */
-    cp = g_slice_new0 (GstControlPoint);
-    cp->timestamp = timestamp;
-    g_value_init (&cp->value, self->priv->type);
-    g_value_copy (value, &cp->value);
-    /* and sort it into the prop->values list */
-    self->priv->values =
-        g_list_insert_sorted (self->priv->values, cp,
-        gst_control_point_compare);
+    /* sort new cp into the prop->values list */
+    if (self->priv->values) {
+      GList *new_list;
+
+      /* pass 'prev' instead of list */
+      new_list = g_list_insert_sorted (prev,
+          _make_new_cp (self, timestamp, value), gst_control_point_compare);
+      if (self->priv->values == prev)
+        self->priv->values = new_list;
+    } else {
+      self->priv->values = g_list_prepend (NULL,
+          _make_new_cp (self, timestamp, value));
+    }
     self->priv->nvalues++;
   }
+done:
   self->priv->valid_cache = FALSE;
 }
 
+
 /**
  * gst_interpolation_control_source_set:
  * @self: the #GstInterpolationControlSource object