updated for core support
Brandon L Black [Tue, 3 Apr 2007 18:37:11 +0000 (18:37 +0000)]
lib/Class/C3.pm
lib/Class/C3/PurePerl.pm
t/10_Inconsistent_hierarchy.t
t/20_reinitialize.t

index 5c62422..f4e2554 100644 (file)
@@ -7,12 +7,10 @@ use warnings;
 our $VERSION = '0.15';
 
 BEGIN {
-    eval { require Class::C3::XS };
+    eval "require Class::C3::XS";
     if($@) {
-        eval { require Class::C3::PurePerl };
-        if($@) {
-            die 'Could not load Class::C3::XS or Class::C3::PurePerl!';
-        }
+        eval "require Class::C3::PurePerl";
+        die 'Could not load Class::C3::XS or Class::C3::PurePerl!' if $@;
     }
 }
 
index c05f8f2..c9618ce 100644 (file)
@@ -39,7 +39,20 @@ use strict;
 use warnings;
 
 use Scalar::Util 'blessed';
-use Algorithm::C3;
+
+our $VERSION = '0.15';
+our $C3_IN_CORE;
+
+BEGIN {
+    eval "require mro";
+    if($@) {
+        eval "require Algorithm::C3";
+        die "Could not load 'mro' or 'Algorithm::C3'!" if $@;
+    }
+    else {
+        $C3_IN_CORE = 1;
+    }
+}
 
 # this is our global stash of both 
 # MRO's and method dispatch tables
@@ -69,7 +82,10 @@ sub import {
     # skip if the caller is main::
     # since that is clearly not relevant
     return if $class eq 'main';
+
     return if $TURN_OFF_C3;
+    mro::set_mro_c3($class) if $C3_IN_CORE;
+
     # make a note to calculate $class 
     # during INIT phase
     $MRO{$class} = undef unless exists $MRO{$class};
@@ -78,24 +94,34 @@ sub import {
 ## initializers
 
 sub initialize {
+    %next::METHOD_CACHE = ();
     # why bother if we don't have anything ...
     return unless keys %MRO;
-    if($_initialized) {
-        uninitialize();
-        $MRO{$_} = undef foreach keys %MRO;
+    if($C3_IN_CORE) {
+        mro::set_mro_c3($_) for keys %MRO;
+    }
+    else {
+        if($_initialized) {
+            uninitialize();
+            $MRO{$_} = undef foreach keys %MRO;
+        }
+        _calculate_method_dispatch_tables();
+        _apply_method_dispatch_tables();
+        $_initialized = 1;
     }
-    _calculate_method_dispatch_tables();
-    _apply_method_dispatch_tables();
-    %next::METHOD_CACHE = ();
-    $_initialized = 1;
 }
 
 sub uninitialize {
     # why bother if we don't have anything ...
-    return unless keys %MRO;    
-    _remove_method_dispatch_tables();    
     %next::METHOD_CACHE = ();
-    $_initialized = 0;
+    return unless keys %MRO;    
+    if($C3_IN_CORE) {
+        mro::set_mro_dfs($_) for keys %MRO;
+    }
+    else {
+        _remove_method_dispatch_tables();    
+        $_initialized = 0;
+    }
 }
 
 sub reinitialize { goto &initialize }
@@ -103,6 +129,7 @@ sub reinitialize { goto &initialize }
 ## functions for applying C3 to classes
 
 sub _calculate_method_dispatch_tables {
+    return if $C3_IN_CORE;
     my %merge_cache;
     foreach my $class (keys %MRO) {
         _calculate_method_dispatch_table($class, \%merge_cache);
@@ -110,6 +137,7 @@ sub _calculate_method_dispatch_tables {
 }
 
 sub _calculate_method_dispatch_table {
+    return if $C3_IN_CORE;
     my ($class, $merge_cache) = @_;
     no strict 'refs';
     my @MRO = calculateMRO($class, $merge_cache);
@@ -141,12 +169,14 @@ sub _calculate_method_dispatch_table {
 }
 
 sub _apply_method_dispatch_tables {
+    return if $C3_IN_CORE;
     foreach my $class (keys %MRO) {
         _apply_method_dispatch_table($class);
     }     
 }
 
 sub _apply_method_dispatch_table {
+    return if $C3_IN_CORE;
     my $class = shift;
     no strict 'refs';
     ${"${class}::()"} = $MRO{$class}->{has_overload_fallback}
@@ -157,12 +187,14 @@ sub _apply_method_dispatch_table {
 }
 
 sub _remove_method_dispatch_tables {
+    return if $C3_IN_CORE;
     foreach my $class (keys %MRO) {
         _remove_method_dispatch_table($class);
     }       
 }
 
 sub _remove_method_dispatch_table {
+    return if $C3_IN_CORE;
     my $class = shift;
     no strict 'refs';
     delete ${"${class}::"}{"()"} if $MRO{$class}->{has_overload_fallback};    
@@ -177,6 +209,9 @@ sub _remove_method_dispatch_table {
 
 sub calculateMRO {
     my ($class, $merge_cache) = @_;
+
+    return @{mro::get_mro_linear_c3($class)} if $C3_IN_CORE;
+
     return Algorithm::C3::merge($class, sub { 
         no strict 'refs'; 
         @{$_[0] . '::ISA'};
@@ -189,13 +224,15 @@ package  # hide me from PAUSE
 use strict;
 use warnings;
 
-our $VERSION = 0.15;
-
 use Scalar::Util 'blessed';
 
+our $VERSION = '0.06';
+
 our %METHOD_CACHE;
 
 sub method {
+    my $self     = $_[0];
+    my $class    = blessed($self) || $self;
     my $indirect = caller() =~ /^(?:next|maybe::next)$/;
     my $level = $indirect ? 2 : 1;
      
@@ -207,11 +244,12 @@ sub method {
         $label eq '(eval)' ||
         $label eq '__ANON__';
     }
+
+    my $method;
+
     my $caller   = join '::' => @label;    
-    my $self     = $_[0];
-    my $class    = blessed($self) || $self;
     
-    my $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
+    $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
         
         my @MRO = Class::C3::calculateMRO($class);
         
@@ -227,7 +265,7 @@ sub method {
                      defined $Class::C3::MRO{$class}{methods}{$label});          
             last if (defined ($found = *{$class . '::' . $label}{CODE}));
         }
-        
+    
         $found;
     };
 
@@ -246,7 +284,7 @@ package  # hide me from PAUSE
 use strict;
 use warnings;
 
-our $VERSION = 0.15;
+our $VERSION = '0.02';
 
 sub method { (next::method($_[0]) || return)->(@_) }
 
index 2378ea3..453d002 100644 (file)
@@ -54,4 +54,4 @@ eval {
     Class::C3::calculateMRO('Z') 
 };
 #diag $@;
-like($@, qr/^Inconsistent hierarchy/, '... got the right error with an inconsistent hierarchy');
+like($@, qr/^Inconsistent inheritance hierarchy/, '... got the right error with an inconsistent hierarchy');
index 7dce5d4..0912cb4 100644 (file)
@@ -81,7 +81,13 @@ is_deeply(
     [ qw(Diamond_D Diamond_B Diamond_E Diamond_C Diamond_A) ],
     '... got the new MRO for Diamond_D');
 
-is(Diamond_D->hello, 'Diamond_C::hello', '... method still resolves with old MRO');
+# Doesn't work with core support, since reinit is not neccesary and the change
+#  takes effect immediately
+SKIP: {
+    skip "This test does not work with a c3-patched perl interpreter", 1
+        if $Class::C3::C3_IN_CORE;
+    is(Diamond_D->hello, 'Diamond_C::hello', '... method still resolves with old MRO');
+}
 
 Class::C3::reinitialize();