BABL fishing patch
This discussion is connected to the gegl-developer-list.gnome.org mailing list which is provided by the GIMP developers and not related to gimpusers.com.
This is a read-only list on gimpusers.com so this discussion thread is read-only, too.
BABL fishing patch | Jan Heller | 07 Apr 18:31 |
BABL fishing patch | Øyvind Kolås | 08 Apr 19:11 |
BABL fishing patch
Hi,
attached is a patch that improves logic of go_fishing code in babl-fish.c. The current code searches list of all fishes while looking for suitable preexistent BABL_FISH_PATH instance. The new code only searches relevant part of database's hash table. Further, the current code searches for fish path every time such a babl fish is requested, even though the same fish path has been requested before and not found. The new code creates dummy BABL_FISH instance with appropriate source/destination formats and inserts it into the fish database to indicate that fish path has been searched for and not found. See comments in the patch for details.
Regards, Jan
Index: babl/babl-internal.h
===================================================================
--- babl/babl-internal.h (revision 302)
+++ babl/babl-internal.h (working copy)
@@ -88,6 +88,8 @@ long babl_fish_path_process
void *source,
void *destination,
long n);
+int babl_fish_get_id (const Babl *source,
+ const Babl *destination);
double babl_format_loss (Babl *babl);
Babl * babl_image_from_linear (char *buffer,
Index: babl/babl-fish-path.c
===================================================================
--- babl/babl-fish-path.c (revision 302)
+++ babl/babl-fish-path.c (working copy)
@@ -193,9 +193,10 @@ Babl *
babl_fish_path (const Babl *source,
const Babl *destination)
{
- Babl *babl = NULL;
- char *name = create_name (source, destination, 1);
+ Babl *babl = NULL;
+ char *name;
+ name = create_name (source, destination, 1);
babl = babl_db_exist_by_name (babl_fish_db (), name);
if (babl)
{
@@ -205,17 +206,11 @@ babl_fish_path (const Babl *source,
return babl;
}
- babl_assert (BABL_IS_BABL (source));
- babl_assert (BABL_IS_BABL (destination));
-
- babl_assert (source->class_type == BABL_FORMAT);
- babl_assert (destination->class_type == BABL_FORMAT);
-
babl = babl_calloc (1, sizeof (BablFishPath) +
strlen (name) + 1);
babl->class_type = BABL_FISH_PATH;
- babl->instance.id = 0;
+ babl->instance.id = babl_fish_get_id (source, destination);
babl->instance.name = ((char *) babl) + sizeof (BablFishPath);
strcpy (babl->instance.name, name);
babl->fish.source = source;
Index: babl/babl-fish-simple.c
===================================================================
--- babl/babl-fish-simple.c (revision 302)
+++ babl/babl-fish-simple.c (working copy)
@@ -33,7 +33,6 @@ babl_fish_simple (BablConversion *conver
babl_assert (BABL_IS_BABL (conversion));
name = create_name (conversion);
-
babl = babl_db_exist_by_name (babl_fish_db (), name);
if (babl)
{
@@ -46,7 +45,7 @@ babl_fish_simple (BablConversion *conver
babl = babl_malloc (sizeof (BablFishSimple) +
strlen (name) + 1);
babl->class_type = BABL_FISH_SIMPLE;
- babl->instance.id = 0;
+ babl->instance.id = babl_fish_get_id (conversion->source, conversion->destination);
babl->instance.name = ((char *) babl) + sizeof (BablFishSimple);
strcpy (babl->instance.name, name);
babl->fish.source = conversion->source;
Index: babl/babl-fish-reference.c
===================================================================
--- babl/babl-fish-reference.c (revision 302)
+++ babl/babl-fish-reference.c (working copy)
@@ -69,7 +69,7 @@ babl_fish_reference (const Babl *source,
babl = babl_malloc (sizeof (BablFishReference) +
strlen (name) + 1);
babl->class_type = BABL_FISH_REFERENCE;
- babl->instance.id = 0;
+ babl->instance.id = babl_fish_get_id (source, destination);
babl->instance.name = ((char *) babl) + sizeof (BablFishReference);
strcpy (babl->instance.name, name);
babl->fish.source = source;
Index: babl/babl-fish.c
===================================================================
--- babl/babl-fish.c (revision 302)
+++ babl/babl-fish.c (working copy)
@@ -20,6 +20,87 @@
#include
#include
+typedef struct _BablFindFish BablFindFish;
+
+typedef struct _BablFindFish
+{
+ Babl *fish_path;
+ Babl *fish_ref;
+ Babl *fish_fish;
+ int fishes;
+ const Babl *source;
+ const Babl *destination;
+} _BablFishFish;
+
+
+static int
+match_conversion (Babl *conversion,
+ void *inout);
+
+static int
+find_fish_path (Babl *item,
+ void *data);
+
+static int
+find_memcpy_fish (Babl *item,
+ void *data);
+
+static int
+each_babl_fish_destroy (Babl *babl,
+ void *data);
+
+
+/* ====================================== */
+
+
+static int
+find_fish_path (Babl *item,
+ void *data)
+{
+ BablFindFish *ffish = (BablFindFish *) data;
+ if ((item->fish.source == ffish->source) &&
+ (item->fish.destination == ffish->destination))
+ {
+ if (item->instance.class_type == BABL_FISH_REFERENCE)
+ {
+ ffish->fish_ref = item;
+ ffish->fishes++;
+ }
+ else if (item->instance.class_type == BABL_FISH_PATH)
+ {
+ ffish->fish_path = item;
+ ffish->fishes++;
+ }
+ else if (item->instance.class_type == BABL_FISH)
+ {
+ ffish->fish_fish = item;
+ ffish->fishes++;
+ }
+ if (ffish->fishes == 3)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+find_memcpy_fish (Babl *item,
+ void *data)
+{
+ BablFindFish *ffish = (BablFindFish *) data;
+ if ((item->fish.source == ffish->source) &&
+ (item->fish.destination == ffish->destination))
+ {
+ if ((item->fish.source == item->fish.destination) &&
+ (item->instance.class_type == BABL_FISH_REFERENCE))
+ {
+ ffish->fish_ref = item;
+ return 1;
+ }
+ }
+
+ return 0;
+}
static int
match_conversion (Babl *conversion,
@@ -47,6 +128,20 @@ babl_conversion_find (const void *source
return data;
}
+int
+babl_fish_get_id (const Babl *source,
+ const Babl *destination)
+{
+ /* value of 'id' will be used as argument for hash function,
+ * substraction serves as simple combination of
+ * source/destination values. */
+ int id = (int) source - (int) destination;
+ /* instances with id 0 won't be inserted into database */
+ if (id == 0)
+ id = 1;
+ return id;
+}
+
BablDb *
babl_fish_db (void)
{
@@ -55,28 +150,6 @@ babl_fish_db (void)
return db;
}
-static inline Babl *
-go_fishing (const Babl *source,
- const Babl *destination)
-{
- BablDb *db = babl_fish_db ();
- int i;
-
- for (i = 0; i < db->babl_list->count; i++)
- {
- Babl *item = db->babl_list->items[i];
- if ((void *) source == (void *) item->fish.source &&
- (void *) destination == (void *) item->fish.destination &&
- (item->class_type == BABL_FISH_PATH || /* accept only paths */
- source == destination) /* or memcpy */
- )
- {
- return item;
- }
- }
- return NULL;
-}
-
Babl *
babl_fish (const void *source,
const void *destination,
@@ -89,14 +162,10 @@ babl_fish (const void *source,
babl_assert (destination);
if (BABL_IS_BABL (source))
- {
- source_format = source;
- }
+ source_format = source;
if (!source_format)
- {
- source_format = babl_format ((char *) source);
- }
+ source_format = babl_format ((char *) source);
if (!source_format)
{
@@ -105,14 +174,10 @@ babl_fish (const void *source,
}
if (BABL_IS_BABL (destination))
- {
- destination_format = destination;
- }
+ destination_format = destination;
if (!destination_format)
- {
- destination_format = babl_format ((char *) destination);
- }
+ destination_format = babl_format ((char *) destination);
if (!destination_format)
{
@@ -121,41 +186,90 @@ babl_fish (const void *source,
}
{
- Babl *lucky;
- lucky = go_fishing (source_format, destination_format);
- if (lucky)
- return lucky;
- }
-
- if (0) /* do not accept shortcut conversions, since there might be
- a faster path, besides the shortcut conversion might
- have a too large error, let's rely on the paths for
- error checking.
- */
- {
- Babl *shortcut_conversion;
+ int hashval;
+ BablHashTable *id_htable;
+ BablFindFish ffish = {(Babl *) NULL,
+ (Babl *) NULL,
+ (Babl *) NULL,
+ 0,
+ source_format,
+ destination_format};
- shortcut_conversion = babl_conversion_find (
- source_format, destination_format);
+ id_htable = (babl_fish_db ())->id_hash;
+ hashval = babl_hash_by_int (id_htable, babl_fish_get_id (source_format, destination_format));
- if (shortcut_conversion)
- {
- return babl_fish_simple (&(shortcut_conversion->conversion));
- }
- }
+ if (source_format == destination_format)
+ {
+ /* In the case of equal source and destination formats
+ * we will search through the fish database for reference fish
+ * to handle the memcpy */
+ id_htable->find_func = find_memcpy_fish;
+ babl_hash_table_find (id_htable, hashval, (void *) &ffish);
+ }
+ else
+ {
+ /* In the case of different source and destination formats
+ * we will search through the fish database for appropriate fish path
+ * to handle the conversion. In the case that preexistent
+ * fish path is found, we'll return it. In the case BABL_FISH
+ * instance with the same source/destination is found, we'll
+ * return reference fish.
+ * In the case neither fish path nor BABL_FISH path are found,
+ * we'll try to construct new fish path for requested
+ * source/destination. In the case new fish path is found, we'll
+ * return it, otherwise we'll create dummy BABL_FISH instance and
+ * insert it into the fish database to indicate non-existent fish
+ * path.
+ */
+ id_htable->find_func = find_fish_path;
+ babl_hash_table_find (id_htable, hashval, (void *) &ffish);
- {
- Babl *fish_path;
+ if (ffish.fish_path)
+ {
+ /* we have found suitable fish path in the database */
+ return ffish.fish_path;
+ }
+ if (!ffish.fish_fish)
+ {
+ /* we haven't tried to search for suitable path yet */
+ Babl *fish_path = babl_fish_path (source_format, destination_format);
- fish_path = babl_fish_path (source_format, destination_format);
+ if (fish_path)
+ {
+ return fish_path;
+ }
+ else
+ {
+ /* there isn't a suitable path for requested formats,
+ * let's create a dummy BABL_FISH instance and insert
+ * it into the fish database to indicate that such path
+ * does not exist.
+ */
+ char *name = "X"; /* name does not matter */
+ Babl *fish = babl_calloc (1, sizeof (BablFish) + strlen (name) + 1);
+
+ fish->class_type = BABL_FISH;
+ fish->instance.id = babl_fish_get_id (source_format, destination_format);
+ fish->instance.name = ((char *) fish) + sizeof (BablFish);
+ strcpy (fish->instance.name, name);
+ fish->fish.source = source_format;
+ fish->fish.destination = destination_format;
+ babl_db_insert (babl_fish_db (), fish);
+ }
+ }
+ }
- if (fish_path)
+ if (ffish.fish_ref)
+ {
+ /* we have already found suitable reference fish */
+ return ffish.fish_ref;
+ }
+ else
{
- return fish_path;
+ /* we have to create new reference fish */
+ return babl_fish_reference (source_format, destination_format);
}
}
-
- return babl_fish_reference (source_format, destination_format);
}
long
@@ -164,7 +278,7 @@ babl_fish_process (Babl *babl,
void *destination,
long n)
{
- long ret = 0;
+ long ret = 0;
switch (babl->class_type)
{
BABL fishing patch
On Mon, Apr 7, 2008 at 5:31 PM, Jan Heller wrote:
attached is a patch that improves logic of go_fishing code in babl-fish.c. The current code searches list of all fishes while looking for suitable preexistent BABL_FISH_PATH instance. The new code only searches relevant part of database's hash table. Further, the current code searches for fish path every time such a babl fish is requested, even though the same fish path has been requested before and not found. The new code creates dummy BABL_FISH instance with appropriate source/destination formats and inserts it into the fish database to indicate that fish path has been searched for and not found. See comments in the patch for details.
One thing you could do to improve the process of applying your already excellent patches for babl is to provide a draft ChangeLog entry as well. If you continue at this pace we might have to start working on getting you commit access to the svn repository.
Thanks a lot for the good work thus far.
/Øyvind K.