mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 20:05:38 +00:00
gstvalue: Optimize some list<=>list functions
For subtracting a list from another, the previous implementation would do a double subtraction of one from another (which would create temporary arrays/values which would then be discarded). Instead iterate and do the comparision directly. For intersecting a list with another, we can directly iterate both at once and therefore avoid doing a *full* check of all values of the list against all other values of the list.
This commit is contained in:
parent
917dd0881c
commit
34b6929a0f
1 changed files with 148 additions and 0 deletions
148
gst/gstvalue.c
148
gst/gstvalue.c
|
@ -4258,6 +4258,39 @@ gst_value_is_subset_structure_structure (const GValue * value1,
|
|||
return gst_structure_is_subset (s1, s2);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_value_is_subset_list_list (const GValue * value1, const GValue * value2)
|
||||
{
|
||||
GstValueList *vlist1 = VALUE_LIST_ARRAY (value1);
|
||||
GstValueList *vlist2 = VALUE_LIST_ARRAY (value2);
|
||||
gint it1, len1, it2, len2;
|
||||
|
||||
len1 = vlist1->len;
|
||||
len2 = vlist2->len;
|
||||
|
||||
/* A list can't be a subset of a smaller list */
|
||||
if (len1 > len2)
|
||||
return FALSE;
|
||||
|
||||
/* Check if all elements of the first list are within the 2nd list */
|
||||
for (it1 = 0; it1 < len1; it1++) {
|
||||
const GValue *child1 = &vlist1->fields[it1];
|
||||
gboolean seen = FALSE;
|
||||
|
||||
for (it2 = 0; it2 < len2; it2++) {
|
||||
const GValue *child2 = &vlist2->fields[it2];
|
||||
if (gst_value_compare (child1, child2) == GST_VALUE_EQUAL) {
|
||||
seen = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!seen)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_value_is_subset:
|
||||
* @value1: a #GValue
|
||||
|
@ -4285,6 +4318,8 @@ gst_value_is_subset (const GValue * value1, const GValue * value2)
|
|||
} else if (GST_VALUE_HOLDS_STRUCTURE (value1)
|
||||
&& GST_VALUE_HOLDS_STRUCTURE (value2)) {
|
||||
return gst_value_is_subset_structure_structure (value1, value2);
|
||||
} else if (GST_VALUE_HOLDS_LIST (value1) && GST_VALUE_HOLDS_LIST (value2)) {
|
||||
return gst_value_is_subset_list_list (value1, value2);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4722,6 +4757,114 @@ gst_value_intersect_double_range_double_range (GValue * dest,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_value_intersect_list_list (GValue * dest, const GValue * value1,
|
||||
const GValue * value2)
|
||||
{
|
||||
guint8 tmpfield[16]; /* Check up to 128 values */
|
||||
guint8 *bitfield;
|
||||
gboolean alloc_bitfield = FALSE;
|
||||
gboolean res = FALSE;
|
||||
GValue *tmp;
|
||||
GType type1, type2;
|
||||
guint it1, len1, it2, len2, itar;
|
||||
GstValueList *vlist = NULL;
|
||||
|
||||
/* If they don't have the same basic type, all bets are off :) */
|
||||
if (!gst_value_list_or_array_get_basic_type (value1, &type1) ||
|
||||
!gst_value_list_or_array_get_basic_type (value2, &type2) ||
|
||||
type1 != type2)
|
||||
return FALSE;
|
||||
|
||||
len1 = VALUE_LIST_SIZE (value1);
|
||||
len2 = VALUE_LIST_SIZE (value2);
|
||||
|
||||
/* Fast-path with no dest (i.e. only interested in knowing whether
|
||||
* both lists intersected without wanting the result) */
|
||||
if (!dest) {
|
||||
for (it1 = 0; it1 < len1; it1++) {
|
||||
const GValue *item1 = VALUE_LIST_GET_VALUE (value1, it1);
|
||||
for (it2 = 0; it2 < len2; it2++) {
|
||||
const GValue *item2 = VALUE_LIST_GET_VALUE (value2, it2);
|
||||
if (gst_value_intersect (NULL, item1, item2)) {
|
||||
res = TRUE;
|
||||
goto beach;
|
||||
}
|
||||
}
|
||||
}
|
||||
goto beach;
|
||||
}
|
||||
#define is_visited(idx) (bitfield[(idx) >> 3] & (1 << ((idx) & 0x7)))
|
||||
#define mark_visited(idx) (bitfield[(idx) >> 3] |= (1 << ((idx) & 0x7)))
|
||||
|
||||
/* Bitfield to avoid double-visiting */
|
||||
if (G_UNLIKELY (len2 > 128)) {
|
||||
alloc_bitfield = TRUE;
|
||||
bitfield = g_malloc0 ((len2 / 8) + 1);
|
||||
GST_CAT_LOG (GST_CAT_PERFORMANCE,
|
||||
"Allocation for GstValueList with more than 128 members");
|
||||
} else {
|
||||
bitfield = &tmpfield[0];
|
||||
memset (bitfield, 0, 16);
|
||||
}
|
||||
|
||||
|
||||
/* When doing list<->list intersections, there is a greater
|
||||
* probability of ending up with a list than with a single value.
|
||||
* Furthermore, the biggest that list can be will the smallest list
|
||||
* (i.e. intersects fully).
|
||||
* Therefore we pre-allocate a GstValueList of that size. */
|
||||
vlist = _gst_value_list_new (MIN (len1, len2));
|
||||
|
||||
itar = 0;
|
||||
tmp = &vlist->fields[0];
|
||||
|
||||
for (it1 = 0; it1 < len1; it1++) {
|
||||
const GValue *item1 = VALUE_LIST_GET_VALUE (value1, it1);
|
||||
for (it2 = 0; it2 < len2; it2++) {
|
||||
const GValue *item2;
|
||||
if (is_visited (it2))
|
||||
continue;
|
||||
item2 = VALUE_LIST_GET_VALUE (value2, it2);
|
||||
|
||||
if (gst_value_intersect (tmp, item1, item2)) {
|
||||
res = TRUE;
|
||||
mark_visited (it2);
|
||||
|
||||
/* Move our collection value */
|
||||
itar += 1;
|
||||
tmp = &vlist->fields[itar];
|
||||
vlist->len += 1;
|
||||
|
||||
/* We can stop iterating the second part now that we've matched */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef is_visited
|
||||
#undef mark_visited
|
||||
|
||||
if (res) {
|
||||
/* If we end up with a single value in the list, just use that
|
||||
* value. Else use the list */
|
||||
if (vlist->len == 1) {
|
||||
gst_value_move (dest, &vlist->fields[0]);
|
||||
g_free (vlist);
|
||||
} else {
|
||||
dest->g_type = GST_TYPE_LIST;
|
||||
dest->data[0].v_pointer = vlist;
|
||||
}
|
||||
} else {
|
||||
g_free (vlist);
|
||||
}
|
||||
|
||||
beach:
|
||||
if (alloc_bitfield)
|
||||
g_free (bitfield);
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_value_intersect_list (GValue * dest, const GValue * value1,
|
||||
const GValue * value2)
|
||||
|
@ -4730,6 +4873,11 @@ gst_value_intersect_list (GValue * dest, const GValue * value1,
|
|||
GValue intersection = { 0, };
|
||||
gboolean ret = FALSE;
|
||||
|
||||
/* Use optimized list-list intersection */
|
||||
if (G_VALUE_TYPE (value2) == GST_TYPE_LIST) {
|
||||
return gst_value_intersect_list_list (dest, value1, value2);
|
||||
}
|
||||
|
||||
size = VALUE_LIST_SIZE (value1);
|
||||
for (i = 0; i < size; i++) {
|
||||
const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
|
||||
|
|
Loading…
Reference in a new issue