diff --git a/ChangeLog b/ChangeLog index b55745a0..9c0f6df7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 19/4/12 started 7.28.6 - better resolution unit handling in deprecated im_vips2tiff() - use TIFF_CFLAGS output from pkg-config (thanks Jay) +- much faster vips_argument_map() 19/4/12 started 7.28.5 - ifthenelse blend mode was broken diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 42336dec..7590ac7f 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -328,15 +328,8 @@ int vips_object_get_argument_priority( VipsObject *object, const char *name ); VipsArgumentInstance *ARG_INSTANCE = \ vips__argument_get_instance( argument_class, \ VIPS_OBJECT( OBJECT ) ); \ - \ - /* We have many props on the arg table ... filter out the \ - * ones for this class. \ - */ \ - if( g_object_class_find_property( \ - G_OBJECT_CLASS( object_class ), \ - g_param_spec_get_name( PSPEC ) ) == PSPEC ) { -#define VIPS_ARGUMENT_FOR_ALL_END } } } +#define VIPS_ARGUMENT_FOR_ALL_END } } /* And some macros to collect args from a va list. */ @@ -494,13 +487,22 @@ struct _VipsObjectClass { */ const char *description; - /* Table of arguments for this class and any derived classes. Order - * is important, so keep a traverse list too. We can't rely on the - * ordering given by g_object_class_list_properties() since it comes - * from a hash :-( + /* Hash from pspec to VipsArgumentClass. + * + * This records the VipsArgumentClass for every pspec used in + * VipsObject and any subclass (ie. everywhere), so it's huge. Don't + * loop over this hash! Fine for lookups though. */ VipsArgumentTable *argument_table; + + /* A sorted (by priority) list of the VipsArgumentClass for this class + * and any superclasses. This is small and specific to this class. + * + * Use the stored GType to work out when to restart the list for a + * subclass. + */ GSList *argument_table_traverse; + GType argument_table_traverse_gtype; }; gboolean vips_value_is_null( GParamSpec *psoec, const GValue *value ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index c6513932..53e7c879 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -355,9 +355,11 @@ vips_argument_map( VipsObject *object, g_object_ref( object ); VIPS_ARGUMENT_FOR_ALL( object, - pspec, argument_class, argument_instance ) { + pspec, argument_class, argument_instance ) { void *result; + /* argument_instance should not be NULL. + */ g_assert( argument_instance ); if( (result = fn( object, pspec, @@ -388,19 +390,12 @@ vips_argument_class_map( VipsObjectClass *object_class, (VipsArgumentClass *) p->data; VipsArgument *argument = (VipsArgument *) arg_class; GParamSpec *pspec = argument->pspec; - - /* We have many props on the arg table ... filter out the - * ones for this class. - */ - if( g_object_class_find_property( - G_OBJECT_CLASS( object_class ), - g_param_spec_get_name( pspec ) ) == pspec ) { - void *result; - if( (result = - fn( object_class, pspec, arg_class, a, b )) ) - return( result ); - } + void *result; + + if( (result = + fn( object_class, pspec, arg_class, a, b )) ) + return( result ); } return( NULL ); @@ -749,15 +744,11 @@ vips_object_dispose( GObject *gobject ) /* Our subclasses should have already called this. Run it again, just * in case. */ - if( !object->preclose ) { -#ifdef VIPS_DEBUG - printf( "vips_object_dispose: no vips_object_preclose() " ); - vips_object_print_name( VIPS_OBJECT( gobject ) ); - printf( "\n" ); -#endif /*VIPS_DEBUG*/ - - vips_object_preclose( object ); - } +#ifdef DEBUG + if( !object->preclose ) + printf( "vips_object_dispose: pre-close missing!\n" ); +#endif /*DEBUG*/ + vips_object_preclose( object ); /* Clear all our arguments: they may be holding resources we should * drop. @@ -1377,7 +1368,8 @@ vips_object_class_install_argument( VipsObjectClass *object_class, VipsArgumentClass *argument_class = g_new( VipsArgumentClass, 1 ); #ifdef DEBUG - printf( "vips_object_class_install_argument: %s %s\n", + printf( "vips_object_class_install_argument: %p %s %s\n", + object_class, g_type_name( G_TYPE_FROM_CLASS( object_class ) ), g_param_spec_get_name( pspec ) ); #endif /*DEBUG*/ @@ -1401,10 +1393,46 @@ vips_object_class_install_argument( VipsObjectClass *object_class, vips_argument_table_replace( object_class->argument_table, (VipsArgument *) argument_class ); + + /* If this is the first argument for a new subclass, we need to clone + * the traverse list we inherit. + */ + if( object_class->argument_table_traverse_gtype != + G_TYPE_FROM_CLASS( object_class ) ) { +#ifdef DEBUG + printf( "vips_object_class_install_argument: " + "cloning traverse\n" ); +#endif /*DEBUG*/ + + object_class->argument_table_traverse = + g_slist_copy( object_class->argument_table_traverse ); + object_class->argument_table_traverse_gtype = + G_TYPE_FROM_CLASS( object_class ); + } + object_class->argument_table_traverse = g_slist_prepend( object_class->argument_table_traverse, argument_class ); object_class->argument_table_traverse = g_slist_sort( object_class->argument_table_traverse, traverse_sort ); + +#ifdef DEBUG +{ + GSList *p; + + printf( "%d items on traverse %p\n", + g_slist_length( object_class->argument_table_traverse ), + &object_class->argument_table_traverse ); + for( p = object_class->argument_table_traverse; p; p = p->next ) { + VipsArgumentClass *argument_class = + (VipsArgumentClass *) p->data; + + printf( "\t%p %s\n", + argument_class, + g_param_spec_get_name( + ((VipsArgument *) argument_class)->pspec ) ); + } +} +#endif /*DEBUG*/ } /* Set a named arg from a string.