From 66445c359db25bc9b5fc0202284a23ebdda31121 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 24 Oct 2014 14:57:01 +0100 Subject: [PATCH] more cpp tinkering --- cplusplus/try93.cc | 450 ++++++++++++++++++++++++++++++++------------- 1 file changed, 318 insertions(+), 132 deletions(-) diff --git a/cplusplus/try93.cc b/cplusplus/try93.cc index 99126c90..9837dc51 100644 --- a/cplusplus/try93.cc +++ b/cplusplus/try93.cc @@ -6,8 +6,36 @@ */ #include +#include +#include +#include #include +#include + +class VError : public std::exception { + std::string _what; + +public: + VError( std::string what ) : _what( what ) {} + VError() : _what( vips_error_buffer() ) {} + virtual ~VError() throw() {} + + // Extract string + virtual const char *what() const throw() { return _what.c_str(); } + void ostream_print( std::ostream & ) const; +}; + +inline std::ostream &operator<<( std::ostream &file, const VError &err ) +{ + err.ostream_print( file ); + return( file ); +} + +void VError::ostream_print( std::ostream &file ) const +{ + file << _what; +} enum VSteal { NOSTEAL = 0, @@ -17,80 +45,120 @@ enum VSteal { class VObject { private: - GObject *gobject; + // can be NULL, see eg. VObject() + VipsObject *vobject; public: - VObject( GObject *new_gobject, VSteal steal = STEAL ) : - gobject( new_gobject ) + VObject( VipsObject *new_vobject, VSteal steal = STEAL ) : + vobject( new_vobject ) { + g_assert( new_vobject && + VIPS_IS_OBJECT( new_vobject ) ); + printf( "VObject constructor, obj = %p, steal = %d\n", - new_gobject, steal ); + new_vobject, steal ); if( !steal ) { printf( " reffing object\n" ); - g_object_ref( gobject ); + g_object_ref( vobject ); } } - // copy constructor - VObject( const VObject &vobject ) : - gobject( vobject.gobject ) + VObject() : + vobject( 0 ) { + } + + // copy constructor + VObject( const VObject &a ) : + vobject( a.vobject ) + { + g_assert( VIPS_IS_OBJECT( a.vobject ) ); + printf( "VObject copy constructor, obj = %p\n", - gobject ); - g_object_ref( gobject ); + vobject ); + g_object_ref( vobject ); printf( " reffing object\n" ); } // assignment ... we must delete the old ref + // old can be NULL, new must not be NULL VObject &operator=( const VObject &a ) { - GObject *old_gobject; + VipsObject *old_vobject; printf( "VObject assignment\n" ); - printf( " reffing %p\n", a.gobject ); - printf( " unreffing %p\n", gobject ); + printf( " reffing %p\n", a.vobject ); + printf( " unreffing %p\n", vobject ); + + g_assert( !vobject || + VIPS_IS_OBJECT( vobject ) ); + g_assert( a.vobject && + VIPS_IS_OBJECT( a.vobject ) ); // delete the old ref at the end ... otherwise "a = a;" could // unref before reffing again - old_gobject = gobject; - gobject = a.gobject; - g_object_ref( gobject ); - g_object_unref( old_gobject ); + old_vobject = vobject; + vobject = a.vobject; + g_object_ref( vobject ); + if( old_vobject ) + g_object_unref( old_vobject ); return( *this ); } + // this mustn't be virtual: we want this class to only be a pointer ~VObject() { printf( "VObject destructor\n" ); - printf( " unreffing %p\n", gobject ); + printf( " unreffing %p\n", vobject ); + + g_assert( !vobject || + VIPS_IS_OBJECT( vobject ) ); - g_object_unref( gobject ); + if( vobject ) + g_object_unref( vobject ); } - GObject *get_object() + VipsObject *get_object() { - return( gobject ); + g_assert( !vobject || + VIPS_IS_OBJECT( vobject ) ); + + return( vobject ); } }; +class VImage; +class VOption; + class VOption { private: struct Pair { const char *name; - GValue value = {0, }; - Pair( const char *name ) : name( name ) + // the thing we pass to VipsOperation + GValue value; + + // we need to box and unbox VImage ... keep a pointer to the + // VImage from C++ here + VImage *vimage; + + // keep a VipsImage pointer from VipsOperation here + VipsImage *vips_image; + + Pair( const char *name ) : + name( name ), vimage( 0 ), vips_image( 0 ) { + G_VALUE_TYPE( &value ) = 0; } ~Pair() { - g_value_unset( &value ) + g_value_unset( &value ); } - } + }; std::list options; @@ -99,65 +167,29 @@ public: { } - ~VOption() - { - std::list::iterator i; + virtual ~VOption(); - for( i = options.begin(); i != options.end(); i++ ) - delete *i; - } + VOption set( const char *name, const char *value ); + VOption set( const char *name, int value ); + VOption set( const char *name, VImage value ); + VOption set( const char *name, VImage *value ); - VOption set( const char *name, const char *value ) - { - Pair *pair = new Pair( name ); + int set_operation( VipsOperation *operation ); + int get_operation( VipsOperation *operation ); - g_value_init( &pair->value, G_TYPE_STRING ); - g_value_set_string( &pair->value, value ); - options.push_back( pair ); - - return( this ); - } - - VOption set( const char *name, int value ) - { - Pair *pair = new Pair( name ); - - g_value_init( &pair->value, G_TYPE_INT ); - g_value_set_int( &pair->value, value ); - options.push_back( pair ); - - return( this ); - } - - VOption set( const char *name, VImage value ) - { - Pair *pair = new Pair( name ); - - g_value_init( &pair->value, G_TYPE_OBJECT ); - g_value_set_object( &pair->value, value ); - options.push_back( pair ); - - return( this ); - } - - VOption set( const char *name, VImage *value ) - { - Pair *pair = new Pair( name ); - - g_value_init( &pair->value, G_TYPE_POINTER ); - g_value_set_pointer( &pair->value, value ); - options.push_back( pair ); - - return( this ); - } - -} +}; class VImage : VObject { public: VImage( VipsImage *image, VSteal steal = STEAL ) : - VObject( (GObject *) image, steal ) + VObject( (VipsObject *) image, steal ) + { + } + + // an empty (NULL) VImage, eg. "VImage a;" + VImage() : + VObject( 0 ) { } @@ -166,74 +198,228 @@ public: return( (VipsImage *) VObject::get_object() ); } - VImage::VOption *option() + static VOption *option() { return( new VOption() ); } + void call_option_string( const char *operation_name, + const char *option_string, VOption *options = 0 ) + throw( VError ); + void call( const char *operation_name, VOption *options = 0 ) + throw( VError ); + VImage new_from_file( const char *name, VOption *options = 0 ) - { - char filename[VIPS_PATH_MAX]; - char option_string[VIPS_PATH_MAX]; - const char *operation_name; - - VImage out; - - vips__filename_split8( name, filename, option_string ); - if( !(operation_name = vips_foreign_find_load( filename )) ) { - delete options; - throw VError(); - } - - if( call_option_string( operation_name, option_string, - options.set( "filename", filename ). - set( "out", &out ) ) ) { - delete options; - throw VError(); - } - - delete options; - } + throw( VError ); void write_to_file( const char *name, VOption *options = 0 ) - { - char filename[VIPS_PATH_MAX]; - char option_string[VIPS_PATH_MAX]; - const char *operation_name; - - vips__filename_split8( name, filename, option_string ); - if( !(operation_name = vips_foreign_find_save( filename )) ) { - delete options; - throw VError(); - } - - if( call_option_string( operation_name, option_string, - options.set( "in", this ). - set( "filename", filename ) ) ) { - delete options; - throw VError(); - } - - delete options; - } + throw( VError ); VImage invert( VOption *options = 0 ) - { - VImage out; - - if( call( "invert", - options.set( "in", this ). - set( "out", &out ) ) ) { - delete options; - throw VError(); - } - delete options; - - return( out ); - } + throw( VError ); }; +VOption::~VOption() +{ + std::list::iterator i; + + for( i = options.begin(); i != options.end(); i++ ) + delete *i; +} + +VOption VOption::set( const char *name, const char *value ) +{ + Pair *pair = new Pair( name ); + + g_value_init( &pair->value, G_TYPE_STRING ); + g_value_set_string( &pair->value, value ); + options.push_back( pair ); + + return( *this ); +} + +VOption VOption::set( const char *name, int value ) +{ + Pair *pair = new Pair( name ); + + g_value_init( &pair->value, G_TYPE_INT ); + g_value_set_int( &pair->value, value ); + options.push_back( pair ); + + return( *this ); +} + +VOption VOption::set( const char *name, VImage value ) +{ + Pair *pair = new Pair( name ); + + // we need to unbox + g_value_init( &pair->value, G_TYPE_OBJECT ); + g_value_set_pointer( &pair->value, value.get_image() ); + options.push_back( pair ); + + return( *this ); +} + +VOption VOption::set( const char *name, VImage *value ) +{ + Pair *pair = new Pair( name ); + + // where we will write the VImage on success + pair->vimage = value; + + // get VipsOperation to write the VipsImage * here + g_value_init( &pair->value, G_TYPE_POINTER ); + g_value_set_pointer( &pair->value, &pair->vips_image ); + options.push_back( pair ); + + return( *this ); +} + +// walk the options and set props on the operation +int VOption::set_operation( VipsOperation *operation ) +{ + std::list::iterator i; + + for( i = options.begin(); i != options.end(); i++ ) + if( vips_object_set( VIPS_OBJECT( operation ), + (*i)->name, &(*i)->value, + NULL ) ) + return( -1 ); + + return( 0 ); +} + +// walk the options and do any processing needed for output objects +int VOption::get_operation( VipsOperation *operation ) +{ + std::list::iterator i; + + for( i = options.begin(); i != options.end(); i++ ) + if( (*i)->vimage ) + *((*i)->vimage) = VImage( (*i)->vips_image ); + + return( 0 ); +} + +void VImage::call_option_string( const char *operation_name, + const char *option_string, VOption *options ) + throw( VError ) +{ + VipsOperation *operation; + + VIPS_DEBUG_MSG( "vips_call_by_name: starting for %s ...\n", + operation_name ); + + if( !(operation = vips_operation_new( operation_name )) ) { + if( options ) + delete options; + throw( VError() ); + } + + /* Set str options before vargs options, so the user can't + * override things we set deliberately. + */ + if( option_string && + vips_object_set_from_string( VIPS_OBJECT( operation ), + option_string ) ) { + vips_object_unref_outputs( VIPS_OBJECT( operation ) ); + g_object_unref( operation ); + delete options; + throw( VError() ); + } + + if( options && + options->set_operation( operation ) ) { + g_object_unref( operation ); + delete options; + throw( VError() ); + } + + /* Build from cache. + */ + if( vips_cache_operation_buildp( &operation ) ) { + vips_object_unref_outputs( VIPS_OBJECT( operation ) ); + delete options; + throw( VError() ); + } + + /* Walk args again, writing output. + */ + if( options && + options->get_operation( operation ) ) { + vips_object_unref_outputs( VIPS_OBJECT( operation ) ); + delete options; + throw( VError() ); + } + + /* The operation we have built should now have been reffed by + * one of its arguments or have finished its work. Either + * way, we can unref. + */ + g_object_unref( operation ); +} + +void VImage::call( const char *operation_name, VOption *options ) + throw( VError ) +{ + call_option_string( operation_name, NULL, options ); +} + +VImage VImage::new_from_file( const char *name, VOption *options ) + throw( VError ) +{ + char filename[VIPS_PATH_MAX]; + char option_string[VIPS_PATH_MAX]; + const char *operation_name; + + VImage out; + + vips__filename_split8( name, filename, option_string ); + if( !(operation_name = vips_foreign_find_load( filename )) ) { + delete options; + throw VError(); + } + + call_option_string( operation_name, option_string, + (options ? options : VImage::option())-> + set( "filename", filename )-> + set( "out", &out ) ); +} + +void VImage::write_to_file( const char *name, VOption *options ) + throw( VError ) +{ + char filename[VIPS_PATH_MAX]; + char option_string[VIPS_PATH_MAX]; + const char *operation_name; + + vips__filename_split8( name, filename, option_string ); + if( !(operation_name = vips_foreign_find_save( filename )) ) { + delete options; + throw VError(); + } + + call_option_string( operation_name, option_string, + (options ? options : VImage::option())-> + set( "in", this )-> + set( "filename", filename ) ); +} + +VImage VImage::invert( VOption *options ) + throw( VError ) +{ + VImage out; + + call( "invert", + (options ? options : VImage::option())-> + set( "in", this )-> + set( "out", &out ) ); + + return( out ); +} + int main( int argc, char **argv ) {