basic support for 5.9.5 + c3 patches
Brandon L Black [Thu, 14 Dec 2006 06:16:39 +0000 (06:16 +0000)]
lib/Class/C3.pm
t/20_reinitialize.t

index a9158ed..79d728f 100644 (file)
@@ -6,8 +6,12 @@ use warnings;
 
 use Scalar::Util 'blessed';
 use Algorithm::C3;
+use B ();
 
 our $VERSION = '0.14';
+our $C3_IN_CORE;
+
+BEGIN { $C3_IN_CORE = ($] > 5.009004) }
 
 # this is our global stash of both 
 # MRO's and method dispatch tables
@@ -38,6 +42,9 @@ sub import {
     # since that is clearly not relevant
     return if $class eq 'main';
     return if $TURN_OFF_C3;
+    if($C3_IN_CORE) {
+        B::enable_c3mro($class);
+    }
     # make a note to calculate $class 
     # during INIT phase
     $MRO{$class} = undef unless exists $MRO{$class};
@@ -46,24 +53,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) {
+        B::enable_c3mro($_) 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) {
+        B::disable_c3mro($_) for keys %MRO;
+    }
+    else {
+        _remove_method_dispatch_tables();    
+        $_initialized = 0;
+    }
 }
 
 sub reinitialize { goto &initialize }
@@ -71,6 +88,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);
@@ -78,6 +96,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);
@@ -109,12 +128,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}
@@ -125,12 +146,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};    
@@ -145,10 +168,15 @@ sub _remove_method_dispatch_table {
 
 sub calculateMRO {
     my ($class, $merge_cache) = @_;
-    return Algorithm::C3::merge($class, sub { 
-        no strict 'refs'; 
-        @{$_[0] . '::ISA'};
-    }, $merge_cache);
+    if($C3_IN_CORE) {
+        return @{B::get_linear_isa_c3($class)};
+    }
+    else {
+        return Algorithm::C3::merge($class, sub { 
+            no strict 'refs'; 
+            @{$_[0] . '::ISA'};
+        }, $merge_cache);
+    }
 }
 
 package  # hide me from PAUSE
@@ -164,6 +192,8 @@ our $VERSION = '0.05';
 our %METHOD_CACHE;
 
 sub method {
+    my $self     = $_[0];
+    my $class    = blessed($self) || $self;
     my $indirect = caller() =~ /^(?:next|maybe::next)$/;
     my $level = $indirect ? 2 : 1;
      
@@ -175,29 +205,36 @@ sub method {
         $label eq '(eval)' ||
         $label eq '__ANON__';
     }
-    my $caller   = join '::' => @label;    
-    my $self     = $_[0];
-    my $class    = blessed($self) || $self;
+
+    my $method;
+
+    # You would think we could do this, but we can't apparently :(
+    #if($Class::C3::C3_IN_CORE && B::is_c3mro($class)) {
+    #    $method = $class->can('SUPER::' . $label);
+    #}
+    #else {
+        my $caller   = join '::' => @label;    
     
-    my $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
+        $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
         
-        my @MRO = Class::C3::calculateMRO($class);
+            my @MRO = Class::C3::calculateMRO($class);
         
-        my $current;
-        while ($current = shift @MRO) {
-            last if $caller eq $current;
-        }
+            my $current;
+            while ($current = shift @MRO) {
+                last if $caller eq $current;
+            }
         
-        no strict 'refs';
-        my $found;
-        foreach my $class (@MRO) {
-            next if (defined $Class::C3::MRO{$class} && 
-                     defined $Class::C3::MRO{$class}{methods}{$label});          
-            last if (defined ($found = *{$class . '::' . $label}{CODE}));
-        }
+            no strict 'refs';
+            my $found;
+            foreach my $class (@MRO) {
+                next if (defined $Class::C3::MRO{$class} && 
+                         defined $Class::C3::MRO{$class}{methods}{$label});          
+                last if (defined ($found = *{$class . '::' . $label}{CODE}));
+            }
         
-        $found;
-    };
+            $found;
+        };
+    #}
 
     return $method if $indirect;
 
index 7dce5d4..8d9c4c6 100644 (file)
@@ -81,7 +81,10 @@ 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');
+SKIP: {
+    skip "This test makes no sense with this perl", 1 if $Class::C3::C3_IN_CORE;
+    is(Diamond_D->hello, 'Diamond_C::hello', '... method still resolves with old MRO');
+}
 
 Class::C3::reinitialize();