From: Brandon L Black Date: Thu, 14 Dec 2006 06:16:39 +0000 (+0000) Subject: basic support for 5.9.5 + c3 patches X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=27195a451d378128376e450f8e8f05f0836d852c;p=gitmo%2FClass-C3.git basic support for 5.9.5 + c3 patches --- diff --git a/lib/Class/C3.pm b/lib/Class/C3.pm index a9158ed..79d728f 100644 --- a/lib/Class/C3.pm +++ b/lib/Class/C3.pm @@ -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; diff --git a/t/20_reinitialize.t b/t/20_reinitialize.t index 7dce5d4..8d9c4c6 100644 --- a/t/20_reinitialize.t +++ b/t/20_reinitialize.t @@ -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();