turn on seq mode automatically in cli

cli operations turn on seq mode automatically when they can

vips_operation_get_flags() added: lets you attach a set of flags to an
operation

flags for now are "nocache" (replacing the old nocache system) and "seqential"

if vips_object_set_argument_from_string() from string sees "seq" flag on the
object for which it is setting the arg, it enables sequential mode

all operations which can run sequentially have been tagged

the operation printer knows about flags and can display them
This commit is contained in:
John Cupitt 2012-07-10 10:51:40 +01:00
parent af1f2b47c1
commit 643dc28950
24 changed files with 178 additions and 34 deletions

View File

@ -12,6 +12,11 @@
- better thread safety for vips8 operation dispatch
- better thread safety for upstream / downstream image linking
- added "rs" open mode, removed "rd"
- added vips_operation_get_flags() ... system for attaching sets of flags to
operations
- added VIPS_OPERATION_SEQUENTIAL flag
- vips8 command-line interface uses this to turn sequential mode on
automatically when possible
18/6/12 started 7.28.9
- slightly more memory debugging output

1
TODO
View File

@ -1,4 +1,3 @@
- test "rs" mode
can't see the code for "rd" mode?

View File

@ -370,6 +370,7 @@ vips_arithmetic_class_init( VipsArithmeticClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -378,6 +379,8 @@ vips_arithmetic_class_init( VipsArithmeticClass *class )
vobject_class->description = _( "arithmetic operations" );
vobject_class->build = vips_arithmetic_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
_( "Output image" ),

View File

@ -163,6 +163,7 @@ vips_bandary_class_init( VipsBandaryClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_bandary_class_init\n" );
@ -173,6 +174,7 @@ vips_bandary_class_init( VipsBandaryClass *class )
vobject_class->description = _( "operations on image bands" );
vobject_class->build = vips_bandary_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
}
static void

View File

@ -462,6 +462,7 @@ vips_cast_class_init( VipsCastClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_cast_class_init\n" );
@ -472,6 +473,8 @@ vips_cast_class_init( VipsCastClass *class )
vobject_class->description = _( "cast an image" );
vobject_class->build = vips_cast_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),

View File

@ -304,6 +304,7 @@ vips_copy_class_init( VipsCopyClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_copy_class_init\n" );
@ -314,6 +315,8 @@ vips_copy_class_init( VipsCopyClass *class )
vobject_class->description = _( "copy an image" );
vobject_class->build = vips_copy_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),

View File

@ -507,6 +507,7 @@ vips_embed_class_init( VipsEmbedClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_embed_class_init\n" );
@ -517,6 +518,8 @@ vips_embed_class_init( VipsEmbedClass *class )
vobject_class->description = _( "embed an image in a larger image" );
vobject_class->build = vips_embed_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", -1,
_( "Input" ),
_( "Input image" ),

View File

@ -180,6 +180,7 @@ vips_extract_area_class_init( VipsExtractAreaClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_extract_area_class_init\n" );
@ -190,6 +191,8 @@ vips_extract_area_class_init( VipsExtractAreaClass *class )
vobject_class->description = _( "extract an area from an image" );
vobject_class->build = vips_extract_area_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "input", 0,
_( "Input" ),
_( "Input image" ),

View File

@ -358,6 +358,7 @@ vips_flatten_class_init( VipsFlattenClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_flatten_class_init\n" );
@ -368,6 +369,8 @@ vips_flatten_class_init( VipsFlattenClass *class )
vobject_class->description = _( "flatten alpha out of an image" );
vobject_class->build = vips_flatten_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),

View File

@ -458,6 +458,7 @@ vips_ifthenelse_class_init( VipsIfthenelseClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_ifthenelse_class_init\n" );
@ -468,6 +469,8 @@ vips_ifthenelse_class_init( VipsIfthenelseClass *class )
vobject_class->description = _( "ifthenelse an image" );
vobject_class->build = vips_ifthenelse_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "cond", -2,
_( "Condition" ),
_( "Condition input image" ),

View File

@ -339,6 +339,7 @@ vips_insert_class_init( VipsInsertClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_insert_class_init\n" );
@ -349,6 +350,8 @@ vips_insert_class_init( VipsInsertClass *class )
vobject_class->description = _( "insert an image" );
vobject_class->build = vips_insert_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "main", -1,
_( "Main" ),
_( "Main input image" ),

View File

@ -200,6 +200,7 @@ vips_join_class_init( VipsJoinClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_join_class_init\n" );
@ -210,6 +211,8 @@ vips_join_class_init( VipsJoinClass *class )
vobject_class->description = _( "join a pair of images" );
vobject_class->build = vips_join_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in1", -1,
_( "in1" ),
_( "First input image" ),

View File

@ -188,6 +188,7 @@ vips_recomb_class_init( VipsRecombClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -196,6 +197,8 @@ vips_recomb_class_init( VipsRecombClass *class )
object_class->description = _( "linear recombination with matrix" );
object_class->build = vips_recomb_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 0,
_( "Input" ),
_( "Input image argument" ),

View File

@ -702,7 +702,7 @@ vips_foreign_load_temp( VipsForeignLoad *load )
/* You can't reuse sequential operations.
*/
vips_operation_set_nocache( VIPS_OPERATION( load ), TRUE );
load->nocache = TRUE;
return( vips_image_new() );
}
@ -889,11 +889,26 @@ vips_foreign_load_build( VipsObject *object )
return( 0 );
}
static VipsOperationFlags
vips_foreign_load_real_get_flags( VipsOperation *operation )
{
VipsForeignLoad *load = VIPS_FOREIGN_LOAD( operation );
VipsOperationFlags flags;
flags = VIPS_OPERATION_CLASS( vips_foreign_load_parent_class )->
get_flags( operation );
if( load->nocache )
flags |= VIPS_OPERATION_NOCACHE;
return( flags );
}
static void
vips_foreign_load_class_init( VipsForeignLoadClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = (VipsOperationClass *) class;
gobject_class->dispose = vips_foreign_load_dispose;
gobject_class->set_property = vips_object_set_property;
@ -905,6 +920,8 @@ vips_foreign_load_class_init( VipsForeignLoadClass *class )
object_class->nickname = "fileload";
object_class->description = _( "file loaders" );
operation_class->get_flags = vips_foreign_load_real_get_flags;
VIPS_ARG_IMAGE( class, "out", 2,
_( "Output" ),
_( "Output image" ),

View File

@ -63,6 +63,7 @@ vips_scan_headers = \
${top_srcdir}/libvips/include/vips/conversion.h \
${top_srcdir}/libvips/include/vips/util.h \
${top_srcdir}/libvips/include/vips/image.h \
${top_srcdir}/libvips/include/vips/operation.h \
${top_srcdir}/libvips/include/vips/object.h
enumtypes.h: $(vips_scan_headers) Makefile

View File

@ -57,6 +57,9 @@ GType vips_band_format_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_BAND_FORMAT (vips_band_format_get_type())
GType vips_coding_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_CODING (vips_coding_get_type())
/* enumerations from "../../../libvips/include/vips/operation.h" */
GType vips_operation_flags_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_OPERATION_FLAGS (vips_operation_flags_get_type())
/* enumerations from "../../../libvips/include/vips/object.h" */
GType vips_argument_flags_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_ARGUMENT_FLAGS (vips_argument_flags_get_type())

View File

@ -136,6 +136,10 @@ typedef struct _VipsForeignLoad {
* disc foreign or a memory buffer. This must be set by ->load().
*/
VipsImage *real;
/* Set this to tag the operation as nocache.
*/
gboolean nocache;
} VipsForeignLoad;
typedef struct _VipsForeignLoadClass {

View File

@ -36,6 +36,27 @@ extern "C" {
#include <vips/vips.h>
/**
* VipsOperationFlags:
* @VIPS_OPERATION_NONE: no flags
* @VIPS_OPERATION_SEQUENTIAL: can work sequentially
* @VIPS_OPERATION_NOCACHE: must not be cached
*
* Flags we associate with an operation.
*
* @VIPS_OPERATION_SEQUENTIAL means that the operation works like vips_copy:
* it can happily process images top-to-bottom with only small non-local
* references.
*
* @VIPS_OPERATION_NOCACHE means that the operation must not be cached by
* vips.
*/
typedef enum /*< flags >*/ {
VIPS_OPERATION_NONE = 0,
VIPS_OPERATION_SEQUENTIAL = 1,
VIPS_OPERATION_NOCACHE = 2
} VipsOperationFlags;
#define VIPS_TYPE_OPERATION (vips_operation_get_type())
#define VIPS_OPERATION( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
@ -66,12 +87,6 @@ typedef struct _VipsOperation {
guint hash;
gboolean found_hash;
/* Set this before the end of _build() to stop this operation from
* being cached. Some things, like sequential read from a TIFF file,
* can't be reused.
*/
gboolean nocache;
} VipsOperation;
typedef struct _VipsOperationClass {
@ -80,10 +95,17 @@ typedef struct _VipsOperationClass {
/* Print the usage message.
*/
void (*usage)( struct _VipsOperationClass *, VipsBuf * );
/* Return a set of operation flags. If @get_flags is NULL, just use
* flags.
*/
VipsOperationFlags (*get_flags)( VipsOperation * );
VipsOperationFlags flags;
} VipsOperationClass;
GType vips_operation_get_type( void );
VipsOperationFlags vips_operation_get_flags( VipsOperation *operation );
void vips_operation_class_print_usage( VipsOperationClass *operation_class );
int vips_operation_call_valist( VipsOperation *operation, va_list ap );
@ -96,7 +118,6 @@ void vips_call_options( GOptionGroup *group, VipsOperation *operation );
int vips_call_argv( VipsOperation *operation, int argc, char **argv );
void vips_cache_drop_all( void );
void vips_operation_set_nocache( VipsOperation *operation, gboolean nocache );
int vips_cache_operation_buildp( VipsOperation **operation );
VipsOperation *vips_cache_operation_build( VipsOperation *operation );
void vips_cache_print( void );

View File

@ -46,6 +46,7 @@ vips_scan_headers = \
${top_srcdir}/libvips/include/vips/arithmetic.h \
${top_srcdir}/libvips/include/vips/util.h \
${top_srcdir}/libvips/include/vips/image.h \
${top_srcdir}/libvips/include/vips/operation.h \
${top_srcdir}/libvips/include/vips/object.h
enumtypes.c: $(vips_scan_headers) Makefile

View File

@ -693,7 +693,8 @@ vips_cache_operation_buildp( VipsOperation **operation )
if( !hit ) {
if( vips__cache_trace ) {
if( (*operation)->nocache )
if( vips_operation_get_flags( *operation ) &
VIPS_OPERATION_NOCACHE )
printf( "vips cache: uncacheable %p\n ",
*operation );
else
@ -706,7 +707,8 @@ vips_cache_operation_buildp( VipsOperation **operation )
g_mutex_lock( vips_cache_lock );
if( !(*operation)->nocache ) {
if( !(vips_operation_get_flags( *operation ) &
VIPS_OPERATION_NOCACHE) ) {
vips_cache_ref( *operation );
g_hash_table_insert( vips_cache_table,
*operation, *operation );

View File

@ -492,6 +492,25 @@ vips_coding_get_type( void )
return( etype );
}
/* enumerations from "../../libvips/include/vips/operation.h" */
GType
vips_operation_flags_get_type( void )
{
static GType etype = 0;
if( etype == 0 ) {
static const GFlagsValue values[] = {
{VIPS_OPERATION_NONE, "VIPS_OPERATION_NONE", "none"},
{VIPS_OPERATION_SEQUENTIAL, "VIPS_OPERATION_SEQUENTIAL", "sequential"},
{VIPS_OPERATION_NOCACHE, "VIPS_OPERATION_NOCACHE", "nocache"},
{0, NULL, NULL}
};
etype = g_flags_register_static( "VipsOperationFlags", values );
}
return( etype );
}
/* enumerations from "../../libvips/include/vips/object.h" */
GType
vips_argument_flags_get_type( void )

View File

@ -1466,12 +1466,27 @@ vips_object_set_argument_from_string( VipsObject *object,
if( g_type_is_a( otype, VIPS_TYPE_IMAGE ) ) {
VipsImage *out;
VipsOperationFlags flags;
flags = 0;
if( VIPS_IS_OPERATION( object ) )
flags = vips_operation_get_flags(
VIPS_OPERATION( object ) );
/* Read the filename. vips_foreign_load_options()
* handles embedded options.
*/
if( vips_foreign_load_options( value, &out, NULL ) )
return( -1 );
if( flags & VIPS_OPERATION_SEQUENTIAL ) {
if( vips_foreign_load_options( value, &out,
"sequential", TRUE,
NULL ) )
return( -1 );
}
else {
if( vips_foreign_load_options( value, &out,
NULL ) )
return( -1 );
}
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
g_value_set_object( &gvalue, out );

View File

@ -148,6 +148,24 @@ vips_operation_usage( VipsOperationClass *class, VipsBuf *buf )
vips_argument_class_map( object_class,
(VipsArgumentClassMapFn) vips_operation_class_usage_arg,
buf, &usage );
/* Show flags.
*/
if( class->flags ) {
GFlagsValue *value;
VipsOperationFlags flags;
GFlagsClass *flags_class =
g_type_class_ref( VIPS_TYPE_OPERATION_FLAGS );
vips_buf_appendf( buf, "operation flags: " );
flags = class->flags;
while( flags && (value =
g_flags_get_first_value( flags_class, flags )) ) {
vips_buf_appendf( buf, "%s ", value->value_nick );
flags &= ~value->value;
}
vips_buf_appends( buf, "\n" );
}
}
static void *
@ -233,6 +251,14 @@ vips_operation_summary( VipsObject *object, VipsBuf *buf )
summary( object, buf );
}
static VipsOperationFlags
vips_operation_real_get_flags( VipsOperation *operation )
{
VipsOperationClass *class = VIPS_OPERATION_GET_CLASS( operation );
return( class->flags );
}
static void
vips_operation_class_init( VipsOperationClass *class )
{
@ -248,6 +274,7 @@ vips_operation_class_init( VipsOperationClass *class )
vobject_class->dump = vips_operation_dump;
class->usage = vips_operation_usage;
class->get_flags = vips_operation_real_get_flags;
}
static void
@ -257,6 +284,22 @@ vips_operation_init( VipsOperation *operation )
*/
}
/**
* vips_operation_get_flags:
* @operation: operation to fetch flags from
*
* Returns the set of flags for this operation.
*
* Returns: 0 on success, or -1 on error.
*/
VipsOperationFlags
vips_operation_get_flags( VipsOperation *operation )
{
VipsOperationClass *class = VIPS_OPERATION_GET_CLASS( operation );
return( class->get_flags( operation ) );
}
/**
* vips_operation_class_print_usage: (skip)
* @operation_class: class to print usage for
@ -913,24 +956,3 @@ vips_call_argv( VipsOperation *operation, int argc, char **argv )
return( 0 );
}
/**
* vips_operation_set_nocache:
* @operation: operation to set
* @nocache: TRUE means don't cache this operation
*
* Set this before the end of _build() to stop this operation being cached.
* Some operations, like sequential read from a TIFF file, for example, cannot
* be reused.
*/
void
vips_operation_set_nocache( VipsOperation *operation, gboolean nocache )
{
#ifdef VIPS_DEBUG
printf( "vips_operation_set_nocache: " );
vips_object_print_name( VIPS_OBJECT( operation ) );
printf( " %d\n", nocache );
#endif /*VIPS_DEBUG*/
operation->nocache = nocache;
}

View File

@ -360,6 +360,7 @@ vips_shrink_class_init( VipsShrinkClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
VIPS_DEBUG_MSG( "vips_shrink_class_init\n" );
@ -370,6 +371,8 @@ vips_shrink_class_init( VipsShrinkClass *class )
vobject_class->description = _( "shrink an image" );
vobject_class->build = vips_shrink_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_DOUBLE( class, "xshrink", 8,
_( "Xshrink" ),
_( "Horizontal shrink factor" ),