* then do a lookup in the Tree to get the required value.
*/
-typedef struct _GstMemCacheFormatIndex {
+typedef struct {
GstFormat format;
gint offset;
GTree *tree;
} GstMemCacheFormatIndex;
-typedef struct _GstMemCacheId {
+typedef struct {
gint id;
GHashTable *format_index;
} GstMemCacheId;
{
GstMemCacheFormatIndex *index = user_data;
gint64 val1, val2;
+ gint64 diff;
val1 = GST_CACHE_ASSOC_VALUE (((GstCacheEntry *)a), index->offset);
val2 = GST_CACHE_ASSOC_VALUE (((GstCacheEntry *)b), index->offset);
- return val1 - val2;
+ diff = (val2 - val1);
+
+ return (diff == 0 ? 0 : (diff > 0 ? 1 : -1));
}
static void
}
}
+typedef struct {
+ gint64 value;
+ GstMemCacheFormatIndex *index;
+ gboolean exact;
+ GstCacheEntry *lower;
+ gint64 low_diff;
+ GstCacheEntry *higher;
+ gint64 high_diff;
+} GstMemCacheSearchData;
+
+static gint
+mem_cache_search (gconstpointer a,
+ gconstpointer b)
+{
+ GstMemCacheSearchData *data = (GstMemCacheSearchData *) b;
+ GstMemCacheFormatIndex *index = data->index;
+ gint64 val1, val2;
+ gint64 diff;
+
+ val1 = GST_CACHE_ASSOC_VALUE (((GstCacheEntry *)a), index->offset);
+ val2 = data->value;
+
+ diff = (val1 - val2);
+ if (diff == 0)
+ return 0;
+
+ /* exact matching, don't update low/high */
+ if (data->exact)
+ return (diff > 0 ? 1 : -1);
+
+ if (diff < 0) {
+ if (diff > data->low_diff) {
+ data->low_diff = diff;
+ data->lower = (GstCacheEntry *) a;
+ }
+ diff = -1;
+ }
+ else {
+ if (diff < data->high_diff) {
+ data->high_diff = diff;
+ data->higher = (GstCacheEntry *) a;
+ }
+ diff = 1;
+ }
+
+ return diff;
+}
+
static GstCacheEntry*
gst_mem_cache_get_assoc_entry (GstCache *cache, gint id,
GstCacheLookupMethod method,
gpointer user_data)
{
GstMemCache *memcache = GST_MEM_CACHE (cache);
- GList *walk = memcache->associations;
- GList *next;
-
- /* FIXME use GTree here */
- while (walk) {
- GstCacheEntry *entry = (GstCacheEntry *) walk->data;
-
- next = g_list_next (walk);
-
- if (entry->type == GST_CACHE_ENTRY_ASSOCIATION && entry->id == id) {
- gint64 got;
-
- if (gst_cache_entry_assoc_map (entry, format, &got)) {
- if (got == value && method == GST_CACHE_LOOKUP_EXACT)
- return entry;
- else {
- gint64 got_next = G_MININT64;
- GstCacheEntry *next_entry = NULL;
-
- if (next != NULL) {
- next_entry = (GstCacheEntry *) next->data;
-
- gst_cache_entry_assoc_map (next_entry, format, &got_next);
- }
-
- if ((got >= value) && (got_next <= value)) {
- if (method == GST_CACHE_LOOKUP_BEFORE)
- return next_entry;
- else if (method == GST_CACHE_LOOKUP_AFTER)
- return entry;
- }
- }
- }
+ GstMemCacheId *id_index;
+ GstMemCacheFormatIndex *index;
+ GstCacheEntry *entry;
+ GstMemCacheSearchData data;
+
+ id_index = g_hash_table_lookup (memcache->id_index, &id);
+ if (!id_index)
+ return NULL;
+
+ index = g_hash_table_lookup (id_index->format_index, &format);
+ if (!index)
+ return NULL;
+
+ data.value = value;
+ data.index = index;
+ data.exact = (method == GST_CACHE_LOOKUP_EXACT);
+
+ /* setup data for low/high checks if we are not looking
+ * for an exact match */
+ if (!data.exact) {
+ data.low_diff = G_MININT64;
+ data.lower = NULL;
+ data.high_diff = G_MAXINT64;
+ data.higher = NULL;
+ }
+
+ entry = g_tree_search (index->tree, mem_cache_search, &data);
+
+ /* get the low/high values if we're not exact */
+ if (entry == NULL && !data.exact) {
+ if (method == GST_CACHE_LOOKUP_BEFORE)
+ entry = data.lower;
+ else if (method == GST_CACHE_LOOKUP_AFTER) {
+ entry = data.higher;
}
-
- walk = next;
}
- return NULL;
+ return entry;
}
static gboolean
cache->resolver_user_data = user_data;
}
+void
+gst_cache_entry_free (GstCacheEntry *entry)
+{
+ g_free (entry);
+}
+
/**
* gst_cache_add_format:
* @cache: the cache to add the entry to
* @...: other format/value pairs or 0 to end the list
*
* Associate given format/value pairs with eachother.
+ * Be sure to pass gint64 values to this functions varargs,
+ * you might want to use a gint64 cast to be sure.
*
* Returns: a pointer to the newly added entry in the cache.
*/
GstCacheEntry*
gst_cache_add_association (GstCache *cache, gint id, GstAssocFlags flags,
- GstFormat format, gint64 value, ...)
+ GstFormat format, gint64 value, ...)
{
va_list args;
GstCacheAssociation *assoc;
gulong size;
gint nassocs = 0;
GstFormat cur_format;
- gint64 dummy;
+ volatile gint64 dummy;
g_return_val_if_fail (GST_IS_CACHE (cache), NULL);
g_return_val_if_fail (format != 0, NULL);
return entry;
}
+static gint
+gst_cache_compare_func (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
+{
+ return a - b;
+}
+
+GstCacheEntry*
+gst_cache_get_assoc_entry (GstCache *cache, gint id,
+ GstCacheLookupMethod method,
+ GstFormat format, gint64 value)
+{
+ g_return_val_if_fail (GST_IS_CACHE (cache), NULL);
+
+ return gst_cache_get_assoc_entry_full (cache, id, method, format, value,
+ gst_cache_compare_func, NULL);
+}
+
+GstCacheEntry*
+gst_cache_get_assoc_entry_full (GstCache *cache, gint id,
+ GstCacheLookupMethod method,
+ GstFormat format, gint64 value,
+ GCompareDataFunc func,
+ gpointer user_data)
+{
+ g_return_val_if_fail (GST_IS_CACHE (cache), NULL);
+
+ if (CLASS(cache)->get_assoc_entry)
+ return CLASS (cache)->get_assoc_entry (cache, id, method, format, value, func, user_data);
+
+ return NULL;
+}
+
+gboolean
+gst_cache_entry_assoc_map (GstCacheEntry *entry,
+ GstFormat format, gint64 *value)
+{
+ gint i;
+
+ g_return_val_if_fail (entry != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ for (i = 0; i < GST_CACHE_NASSOCS (entry); i++) {
+ if (GST_CACHE_ASSOC_FORMAT (entry, i) == format) {
+ *value = GST_CACHE_ASSOC_VALUE (entry, i);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
static void gst_cache_factory_class_init (GstCacheFactoryClass *klass);
static void gst_cache_factory_init (GstCacheFactory *factory);
GST_CACHE_ENTRY_FORMAT,
} GstCacheEntryType;
+typedef enum {
+ GST_CACHE_LOOKUP_EXACT,
+ GST_CACHE_LOOKUP_BEFORE,
+ GST_CACHE_LOOKUP_AFTER,
+} GstCacheLookupMethod;
+
#define GST_CACHE_NASSOCS(entry) ((entry)->data.assoc.nassocs)
#define GST_CACHE_ASSOC_FLAGS(entry) ((entry)->data.assoc.flags)
#define GST_CACHE_ASSOC_FORMAT(entry,i) ((entry)->data.assoc.assocs[(i)].format)
/* abstract methods */
void (*add_entry) (GstCache *cache, GstCacheEntry *entry);
- GstCacheEntry* (*get_entry) (GstCache *cache);
-
+ GstCacheEntry* (*get_assoc_entry) (GstCache *cache, gint id,
+ GstCacheLookupMethod method,
+ GstFormat format, gint64 value,
+ GCompareDataFunc func,
+ gpointer user_data);
/* signals */
void (*entry_added) (GstCache *cache, GstCacheEntry *entry);
};
GstCacheEntry* gst_cache_add_id (GstCache *cache, gint id,
gchar *description);
+GstCacheEntry* gst_cache_get_assoc_entry (GstCache *cache, gint id,
+ GstCacheLookupMethod method,
+ GstFormat format, gint64 value);
+GstCacheEntry* gst_cache_get_assoc_entry_full (GstCache *cache, gint id,
+ GstCacheLookupMethod method,
+ GstFormat format, gint64 value,
+ GCompareDataFunc func,
+ gpointer user_data);
+
+/* working with cache entries */
+void gst_cache_entry_free (GstCacheEntry *entry);
+gboolean gst_cache_entry_assoc_map (GstCacheEntry *entry,
+ GstFormat format, gint64 *value);
/*
* creating caches
*