-
package Class::C3::XS;
-our $VERSION = '0.15';
+use 5.006_000;
+use strict;
+use warnings;
+
+our $VERSION = '0.11';
=pod
=head1 NAME
-Class::C3::XS - The XS implementation of Class::C3
+Class::C3::XS - XS speedups for Class::C3
-=head1 DESCRIPTION
+=head1 SUMMARY
-This is the XS implementation of L<Class::C3>. The main L<Class::C3> package will
-first attempt to load L<Class::C3::XS>, and then failing that, will fall back to
-L<Class::C3::PurePerl>. Do not use this package directly, use L<Class::C3> instead.
+ use Class::C3; # Automatically loads Class::C3::XS
+ # if it's installed locally
-=head1 AUTHOR
+=head1 DESCRIPTION
-Stevan Little, E<lt>stevan@iinteractive.comE<gt>
+This contains XS performance enhancers for L<Class::C3> version
+0.16 and higher. The main L<Class::C3> package will use this
+package automatically if it can find it. Do not use this
+package directly, use L<Class::C3> instead.
-Brandon L. Black, E<lt>blblack@gmail.comE<gt>
+The test suite here is not complete, although it does verify
+a few basic things. The best testing comes from running the
+L<Class::C3> test suite *after* this module is installed.
+
+This module won't do anything for you if you're running a
+version of L<Class::C3> older than 0.16. (It's not a
+dependency because it would be circular with the optional
+dep from that package to this one).
-=head1 COPYRIGHT AND LICENSE
+=head1 AUTHOR
-Copyright 2005, 2006 by Infinity Interactive, Inc.
+Brandon L. Black, E<lt>blblack@gmail.comE<gt>
-L<http://www.iinteractive.com>
+=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
-package # hide me from PAUSE
- Class::C3;
-
-use strict;
-use warnings;
-
-use Scalar::Util 'blessed';
-use Algorithm::C3;
-
-# this is our global stash of both
-# MRO's and method dispatch tables
-# the structure basically looks like
-# this:
-#
-# $MRO{$class} = {
-# MRO => [ <class precendence list> ],
-# methods => {
-# orig => <original location of method>,
-# code => \&<ref to original method>
-# },
-# has_overload_fallback => (1 | 0)
-# }
-#
-our %MRO;
-
-# use these for debugging ...
-sub _dump_MRO_table { %MRO }
-our $TURN_OFF_C3 = 0;
-
-# state tracking for initialize()/uninitialize()
-our $_initialized = 0;
-
-sub import {
- my $class = caller();
- # skip if the caller is main::
- # since that is clearly not relevant
- return if $class eq 'main';
- return if $TURN_OFF_C3;
- # make a note to calculate $class
- # during INIT phase
- $MRO{$class} = undef unless exists $MRO{$class};
-}
-
-## initializers
-
-sub initialize {
- # why bother if we don't have anything ...
- return unless keys %MRO;
- if($_initialized) {
- uninitialize();
- $MRO{$_} = undef foreach keys %MRO;
- }
- _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;
-}
-
-sub reinitialize { goto &initialize }
-
-## functions for applying C3 to classes
-
-sub _calculate_method_dispatch_tables {
- my %merge_cache;
- foreach my $class (keys %MRO) {
- _calculate_method_dispatch_table($class, \%merge_cache);
- }
-}
-
-sub _calculate_method_dispatch_table {
- my ($class, $merge_cache) = @_;
- no strict 'refs';
- my @MRO = calculateMRO($class, $merge_cache);
- $MRO{$class} = { MRO => \@MRO };
- my $has_overload_fallback = 0;
- my %methods;
- # NOTE:
- # we do @MRO[1 .. $#MRO] here because it
- # makes no sense to interogate the class
- # which you are calculating for.
- foreach my $local (@MRO[1 .. $#MRO]) {
- # if overload has tagged this module to
- # have use "fallback", then we want to
- # grab that value
- $has_overload_fallback = ${"${local}::()"}
- if defined ${"${local}::()"};
- foreach my $method (grep { defined &{"${local}::$_"} } keys %{"${local}::"}) {
- # skip if already overriden in local class
- next unless !defined *{"${class}::$method"}{CODE};
- $methods{$method} = {
- orig => "${local}::$method",
- code => \&{"${local}::$method"}
- } unless exists $methods{$method};
- }
- }
- # now stash them in our %MRO table
- $MRO{$class}->{methods} = \%methods;
- $MRO{$class}->{has_overload_fallback} = $has_overload_fallback;
-}
-
-sub _apply_method_dispatch_tables {
- foreach my $class (keys %MRO) {
- _apply_method_dispatch_table($class);
- }
-}
+require XSLoader;
+XSLoader::load('Class::C3::XS', $VERSION);
-sub _apply_method_dispatch_table {
- my $class = shift;
- no strict 'refs';
- ${"${class}::()"} = $MRO{$class}->{has_overload_fallback}
- if $MRO{$class}->{has_overload_fallback};
- foreach my $method (keys %{$MRO{$class}->{methods}}) {
- *{"${class}::$method"} = $MRO{$class}->{methods}->{$method}->{code};
- }
-}
-
-sub _remove_method_dispatch_tables {
- foreach my $class (keys %MRO) {
- _remove_method_dispatch_table($class);
- }
-}
-
-sub _remove_method_dispatch_table {
- my $class = shift;
- no strict 'refs';
- delete ${"${class}::"}{"()"} if $MRO{$class}->{has_overload_fallback};
- foreach my $method (keys %{$MRO{$class}->{methods}}) {
- delete ${"${class}::"}{$method}
- if defined *{"${class}::${method}"}{CODE} &&
- (*{"${class}::${method}"}{CODE} eq $MRO{$class}->{methods}->{$method}->{code});
- }
-}
+package # hide me from PAUSE
+ next;
-## functions for calculating C3 MRO
+sub can { Class::C3::XS::_nextcan($_[0], 0) }
-sub calculateMRO {
- my ($class, $merge_cache) = @_;
- return Algorithm::C3::merge($class, sub {
- no strict 'refs';
- @{$_[0] . '::ISA'};
- }, $merge_cache);
+sub method {
+ my $method = Class::C3::XS::_nextcan($_[0], 1);
+ goto &$method;
}
-package # hide me from PAUSE
- next;
-
-use strict;
-use warnings;
-
-our $VERSION = 0.15;
-
-use Scalar::Util 'blessed';
-
-our %METHOD_CACHE;
+package # hide me from PAUSE
+ maybe::next;
sub method {
- my $indirect = caller() =~ /^(?:next|maybe::next)$/;
- my $level = $indirect ? 2 : 1;
-
- my ($method_caller, $label, @label);
- while ($method_caller = (caller($level++))[3]) {
- @label = (split '::', $method_caller);
- $label = pop @label;
- last unless
- $label eq '(eval)' ||
- $label eq '__ANON__';
- }
- my $caller = join '::' => @label;
- my $self = $_[0];
- my $class = blessed($self) || $self;
-
- my $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
-
- my @MRO = Class::C3::calculateMRO($class);
-
- 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}));
- }
-
- $found;
- };
-
- return $method if $indirect;
-
- die "No next::method '$label' found for $self" if !$method;
-
- goto &{$method};
+ my $method = Class::C3::XS::_nextcan($_[0], 0);
+ goto &$method if defined $method;
+ return;
}
-sub can { method($_[0]) }
-
-package # hide me from PAUSE
- maybe::next;
-
-use strict;
-use warnings;
-
-our $VERSION = 0.15;
-
-sub method { (next::method($_[0]) || return)->(@_) }
-
1;