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
# 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};
## 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 }
## 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);
}
sub _calculate_method_dispatch_table {
+ return if $C3_IN_CORE;
my ($class, $merge_cache) = @_;
no strict 'refs';
my @MRO = calculateMRO($class, $merge_cache);
}
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}
}
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};
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
our %METHOD_CACHE;
sub method {
+ my $self = $_[0];
+ my $class = blessed($self) || $self;
my $indirect = caller() =~ /^(?:next|maybe::next)$/;
my $level = $indirect ? 2 : 1;
$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;