[perl-Glib/gio-support: 11/12] [gio] Ditch AUTOLOAD in favor of pre-installing sub stubs



commit 410aea22039a67ce164bdbb327b65910218130c2
Author: Torsten Schönfeld <kaffeetisch gmx de>
Date:   Mon Apr 12 22:05:08 2010 +0200

    [gio] Ditch AUTOLOAD in favor of pre-installing sub stubs

 GObjectIntrospection.xs |  103 +++++++++++++++++++++++++++++++++------------
 lib/Glib.pm             |  105 ++++++++++++----------------------------------
 2 files changed, 103 insertions(+), 105 deletions(-)
---
diff --git a/GObjectIntrospection.xs b/GObjectIntrospection.xs
index f18552a..d17e1bb 100644
--- a/GObjectIntrospection.xs
+++ b/GObjectIntrospection.xs
@@ -1087,31 +1087,65 @@ release_callback (gpointer data)
 /* ------------------------------------------------------------------------- */
 
 static void
-clone_autoload (const gchar *base_package, const gchar *package)
+store_methods (HV *namespaced_functions, GIBaseInfo *info, GIInfoType info_type)
 {
-	gchar *autoload_name;
-	GV *autoload_glob;
-	CV *autoload_code;
-	gchar *package_autoload;
-	GV *gv;
-
-	/* FIXME: This would only need to be done once per register_types()
-	          call */
-	autoload_name = g_strconcat (base_package, "::AUTOLOAD", NULL);
-	autoload_glob = gv_fetchpv (autoload_name, GV_NOADD_NOINIT, SVt_PVCV);
-	autoload_code = GvCV (autoload_glob);
-	g_free (autoload_name);
-
-	package_autoload = g_strconcat (package, "::AUTOLOAD", NULL);
-	gv = gv_fetchpv (package_autoload, GV_ADDMULTI, SVt_PVCV);
-	g_free (package_autoload);
-
-	/* FIXME: Shouldn't we have to increase the CV's ref count?  Valgrind
-	          doesn't complain, though.
-	          SvREFCNT_inc (autoload_code); */
-	GvCV (gv) = autoload_code;
-	GvCVGEN (gv) = 0;
-	mro_method_changed_in (GvSTASH (gv)); /* FIXME: version checks */
+	const gchar *namespace;
+	AV *av;
+	gint i;
+
+	namespace = g_base_info_get_name (info);
+	av = newAV ();
+
+	switch (info_type) {
+	    case GI_INFO_TYPE_OBJECT:
+	    {
+		gint n_methods = g_object_info_get_n_methods (
+		                   (GIObjectInfo *) info);
+		for (i = 0; i < n_methods; i++) {
+			GIFunctionInfo *function_info =
+				g_object_info_get_method (
+					(GIObjectInfo *) info, i);
+			const gchar *function_name =
+				g_base_info_get_name (
+					(GIBaseInfo *) function_info);
+			av_push (av, newSVpv (function_name, PL_na));
+			g_base_info_unref ((GIBaseInfo *) function_info);
+		}
+		break;
+	    }
+
+	    case GI_INFO_TYPE_INTERFACE:
+	    {
+		gint n_methods = g_interface_info_get_n_methods (
+		                   (GIInterfaceInfo *) info);
+		for (i = 0; i < n_methods; i++) {
+			GIFunctionInfo *function_info =
+				g_interface_info_get_method (
+					(GIInterfaceInfo *) info, i);
+			const gchar *function_name =
+				g_base_info_get_name (
+					(GIBaseInfo *) function_info);
+			av_push (av, newSVpv (function_name, PL_na));
+			g_base_info_unref ((GIBaseInfo *) function_info);
+		}
+		break;
+		break;
+	    }
+
+	    case GI_INFO_TYPE_BOXED:
+	    case GI_INFO_TYPE_STRUCT:
+	    {
+		/* FIXME */
+		break;
+	    }
+
+	    case GI_INFO_TYPE_UNION:
+	    default:
+		croak ("store_methods: unsupported info type %d", info_type);
+	}
+
+	gperl_hv_take_sv (namespaced_functions, namespace, strlen (namespace),
+	                  newRV_noinc ((SV *) av));
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1129,13 +1163,18 @@ register_types (class, namespace, version, package)
 	GIRepository *repository;
 	GError *error = NULL;
 	gint number, i;
-    CODE:
+	AV *global_functions;
+	HV *namespaced_functions;
+    PPCODE:
 	repository = g_irepository_get_default ();
 	g_irepository_require (repository, namespace, version, 0, &error);
 	if (error) {
 		gperl_croak_gerror (NULL, error);
 	}
 
+	global_functions = newAV ();
+	namespaced_functions = newHV ();
+
 	number = g_irepository_get_n_infos (repository, namespace);
 	for (i = 0; i < number; i++) {
 		GIBaseInfo *info;
@@ -1148,6 +1187,10 @@ register_types (class, namespace, version, package)
 		info_type = g_base_info_get_type (info);
 		name = g_base_info_get_name (info);
 
+		if (info_type == GI_INFO_TYPE_FUNCTION) {
+			av_push (global_functions, newSVpv (name, PL_na));
+		}
+
 		if (info_type != GI_INFO_TYPE_OBJECT &&
 		    info_type != GI_INFO_TYPE_INTERFACE &&
 		    info_type != GI_INFO_TYPE_BOXED &&
@@ -1160,7 +1203,6 @@ register_types (class, namespace, version, package)
 
 		type = g_registered_type_info_get_g_type (
 			(GIRegisteredTypeInfo *) info);
-		g_base_info_unref ((GIBaseInfo *) info);
 		if (!type) {
 			croak ("Could not find GType for type %s::%s",
 			       namespace, name);
@@ -1180,7 +1222,7 @@ register_types (class, namespace, version, package)
 		    info_type == GI_INFO_TYPE_STRUCT ||
 		    info_type == GI_INFO_TYPE_UNION)
 		{
-			clone_autoload (package, full_package);
+			store_methods (namespaced_functions, info, info_type);
 		}
 
 		switch (info_type) {
@@ -1205,8 +1247,13 @@ register_types (class, namespace, version, package)
 		}
 
 		g_free (full_package);
+		g_base_info_unref ((GIBaseInfo *) info);
 	}
 
+	EXTEND (SP, 2);
+	PUSHs (sv_2mortal (newRV_noinc ((SV *) global_functions)));
+	PUSHs (sv_2mortal (newRV_noinc ((SV *) namespaced_functions)));
+
 =for apidoc __hide__
 =cut
 void
@@ -1370,7 +1417,7 @@ PPCODE:
 
 	/* prepare and call the function */
 	if (FFI_OK != ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args,
-	   	      		    return_type_ffi, arg_types))
+	                            return_type_ffi, arg_types))
 	{
 		g_base_info_unref ((GIBaseInfo *) return_type_info);
 		croak ("Could not prepare a call interface for %s", symbol);
diff --git a/lib/Glib.pm b/lib/Glib.pm
index 047d57f..349cc09 100644
--- a/lib/Glib.pm
+++ b/lib/Glib.pm
@@ -219,96 +219,47 @@ package Glib::Object::_Introspection;
 
 use strict;
 
-sub find_registered_ancestors {
-  my ($class, $namespace) = @_;
-
-  my @ancestors = ($namespace);
-  {
-    no strict 'refs';
-    my @parents = @{$namespace . '::ISA'};
-    foreach my $parent (@parents) {
-      push @ancestors, __PACKAGE__->find_registered_ancestors($parent);
-    }
-  }
+sub setup {
+  my ($class, %params) = @_;
+  my $basename = $params{basename};
+  my $version = $params{version};
+  my $package = $params{package};
+
+  my ($global_functions, $namespaced_functions) =
+    __PACKAGE__->register_types($basename, $version, $package);
 
-  my @registered_ancestors =
-    grep { !m/^Glib::Object::_Unregistered::/ } @ancestors;
+  no strict 'refs';
 
-  return @registered_ancestors;
+  foreach my $name (@{$global_functions}) {
+    # warn "${package}::$name => $name\n";
+    *{$package . '::' . $name} = sub {
+      __PACKAGE__->invoke($basename, undef, $name, @_);
+    };
+  }
+
+  foreach my $namespace (keys %{$namespaced_functions}) {
+    foreach my $name (@{$namespaced_functions->{$namespace}}) {
+      # warn "${package}::${namespace}::$name => $name\n";
+      *{$package . '::' . $namespace . '::' . $name} = sub {
+        __PACKAGE__->invoke($basename, $namespace, $name, @_);
+      };
+    }
+  }
 }
 
 package Glib::IO;
 
 use strict;
-use Carp;
 
 our $BASENAME = 'Gio';
 our $VERSION = '2.0';
 our $PACKAGE = 'Glib::IO';
 
-our $AUTOLOAD;
-
-sub AUTOLOAD {
-  my $symbol = $AUTOLOAD;
-  my (@args) = @_;
-
-  # 'namespace::method' or just 'method'
-  if ($symbol =~ m/(?:(.+)::)?(.+)/) {
-    my $symbol_namespace = $1;
-    my $symbol_method = $2;
-
-    # FIXME: we are effectively reimplementing method resolution here.
-    # consider ditching the AUTOLOAD clutch in favor of just installing sub
-    # stubs in the correct places for all methods and functions.
-    my @namespace_candidates = ();
-    if (defined $symbol_namespace) {
-      @namespace_candidates =
-        Glib::Object::_Introspection->find_registered_ancestors (
-          $symbol_namespace);
-
-      # strip off the normal prefix
-      foreach my $namespace (@namespace_candidates) {
-        # alter the array in-place
-        $namespace =~ s/^${PACKAGE}(?:::)?//;
-        $namespace = undef if $namespace eq '';
-      }
-    }
-
-    if (! namespace_candidates) {
-      @namespace_candidates = (undef);
-    }
-
-    # warn "namespace candidates for $symbol: (@namespace_candidates)\n";
-
-    my @errors;
-    my @results;
-    foreach my $namespace (@namespace_candidates) {
-      @results = eval {
-        Glib::Object::_Introspection->invoke(
-          $BASENAME, $namespace, $symbol_method, @args); };
-      if ($@) {
-        if ($ ->isa ('Glib::Error')) {
-          croak $@;
-        }
-        push @errors, $@;
-      } else {
-        @errors = ();
-        last;
-      }
-    }
-
-    if (! results && @errors) {
-      croak "Invalid invocation of $symbol:\n  ", join "\n  ", @errors;
-    }
-
-    return wantarray ? @results : $results[0];
-  }
-
-  croak "Invalid invocation: Cannot handle $symbol";
-}
-
 sub setup {
-  Glib::Object::_Introspection->register_types($BASENAME, $VERSION, $PACKAGE);
+  Glib::Object::_Introspection->setup(basename => $BASENAME,
+                                      version => $VERSION,
+                                      package => $PACKAGE);
+
 }
 
 package Glib;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]