File Coverage

blib/lib/SpecioX/XS.pm
Criterion Covered Total %
statement 54 56 96.4
branch 8 14 57.1
condition n/a
subroutine 15 15 100.0
pod 0 1 0.0
total 77 86 89.5


line stmt bran cond sub pod time code
1 35     35   114240 use 5.012;
  35         323  
2 35     35   187 use strict;
  35         61  
  35         717  
3 35     35   219 use warnings;
  35         70  
  35         3745  
4              
5              
6             our $AUTHORITY = 'cpan:TOBYINK';
7             our $VERSION = '0.001';
8              
9             use Type::Tiny::XS ();
10 35     35   15987  
  35         120842  
  35         10553  
11             my ( $specio_object, $xs_name, $tamper_inlined_too ) = @_;
12             $specio_object or return;
13 350     350 0 742
14 350 50       841 my $coderef = Type::Tiny::XS::get_coderef_for( $xs_name );
15             my $subname = Type::Tiny::XS::get_subname_for( $xs_name );
16 350         2019 $coderef or return;
17 350         3496
18 350 50       2239 $specio_object->{_xs_name} = $xs_name;
19             $specio_object->{_optimized_constraint} = $coderef;
20 350         887
21 350         608 if ( $tamper_inlined_too ) {
22             $specio_object->{_inline_generator} = sub {
23 350 100       722 my ( undef, $var ) = @_;
24             return "$subname($var)";
25 198     198   15290401 };
26 198         1418 }
27 140         637 }
28              
29             use Specio::Library::Builtins;
30             my $exported = Specio::Exporter::exportable_types_for_package( 'Specio::Library::Builtins' );
31 35     35   19047  
  35         3577420  
  35         434  
32             # Many similarly named types differ between Specio and Types::Common,
33             # and only these seem to be exactly equivalent. This is mostly because
34             # Specio accepts overloaded objects in place of primatives everywhere.
35             #
36             tamper $exported->{'Item'}, 'Any';
37             tamper $exported->{'Defined'}, 'Defined';
38             tamper $exported->{'Undef'}, 'Undef';
39             tamper $exported->{'Ref'}, 'Ref';
40             tamper $exported->{'Value'}, 'Value';
41             tamper $exported->{'Object'}, 'Object';
42             tamper $exported->{'ArrayRef'}, 'ArrayLike', !!1;
43             tamper $exported->{'HashRef'}, 'HashLike', !!1;
44             tamper $exported->{'CodeRef'}, 'CodeLike', !!1;
45             tamper $exported->{'Str'}, 'StringLike', !!1;
46              
47             # You thought that was bad? It's about to get worse!
48             #
49              
50             do {
51             my $orig = $exported->{'ArrayRef'}{_parameterized_inline_generator};
52             $exported->{'ArrayRef'}{_parameterized_inline_generator} = sub {
53             my ( $type, $parameter, $var ) = @_;
54             my $param_check = $parameter->_optimized_constraint;
55             if ( my $name = Type::Tiny::XS::is_known($param_check) ) {
56             my $xsub = Type::Tiny::XS::get_coderef_for( "ArrayLike[$name]" );
57             if ( $xsub ) {
58             $type->{_optimized_constraint} = $xsub;
59             my $xsubname = Type::Tiny::XS::get_subname_for( "ArrayLike[$name]" );
60             return "$xsubname($var)" if $xsubname;
61             }
62             }
63             goto $orig;
64             };
65             };
66              
67             do {
68             my $orig = $exported->{'HashRef'}{_parameterized_inline_generator};
69             $exported->{'HashRef'}{_parameterized_inline_generator} = sub {
70             my ( $type, $parameter, $var ) = @_;
71             my $param_check = $parameter->_optimized_constraint;
72             if ( my $name = Type::Tiny::XS::is_known($param_check) ) {
73             my $xsub = Type::Tiny::XS::get_coderef_for( "HashLike[$name]" );
74             if ( $xsub ) {
75             $type->{_optimized_constraint} = $xsub;
76             my $xsubname = Type::Tiny::XS::get_subname_for( "HashLike[$name]" );
77             return "$xsubname($var)" if $xsubname;
78             }
79             }
80             goto $orig;
81             };
82             };
83              
84             do {
85             use Specio::Constraint::ObjectIsa ();
86             no warnings 'redefine';
87 35     35   364815 my $orig = \&Specio::Constraint::ObjectIsa::_build_inline_generator;
  35         666809  
  35         1100  
88 35     35   270 *Specio::Constraint::ObjectIsa::_build_inline_generator = sub {
  35         77  
  35         6033  
89             return sub {
90             my ( $type, $var ) = @_;
91             my $class = $type->class;
92 5     5   9244 my $xsub = Type::Tiny::XS::get_coderef_for("InstanceOf[$class]");
93 5         19 if ( $xsub ) {
94 5         43 $type->{_optimized_constraint} = $xsub;
95 5 50       264 my $xsubname = Type::Tiny::XS::get_subname_for("InstanceOf[$class]");
96 5         20 return "$xsubname($var)" if $xsubname;
97 5         23 }
98 5 50       66 goto $orig;
99             };
100 0         0 };
101 4     4   1338058 };
102              
103             do {
104             use Specio::Constraint::ObjectCan ();
105             no warnings 'redefine';
106 35     35   16193 my $orig = \&Specio::Constraint::ObjectCan::_build_inline_generator;
  35         674820  
  35         1113  
107 35     35   269 *Specio::Constraint::ObjectCan::_build_inline_generator = sub {
  35         94  
  35         9206  
108             return sub {
109             my ( $type, $var ) = @_;
110             my $methods = join q{,}, @{ $type->methods };
111 9     9   17086 my $xsub = Type::Tiny::XS::get_coderef_for("HasMethods[$methods]");
112 9         21 if ( $xsub ) {
  9         27  
113 9         75 $type->{_optimized_constraint} = $xsub;
114 9 50       367 my $xsubname = Type::Tiny::XS::get_subname_for("HasMethods[$methods]");
115 9         44 return "$xsubname($var)" if $xsubname;
116 9         40 }
117 9 50       101 goto $orig;
118             };
119 0         0 };
120 5     5   1527964 };
121              
122             1;
123              
124              
125             =pod
126              
127             =encoding utf-8
128              
129             =head1 NAME
130              
131             SpecioX::XS - [PROOF OF CONCEPT] speed boost for Specio using Type::Tiny::XS
132              
133             =head1 SYNOPSIS
134              
135             A rather contrived benchmark, using a type constraint which in L<Types::Common>
136             would be called B<< ArrayLike[HashLike[StringLike]] >>, so an arrayref of
137             hashrefs of strings, but which allows objects overloading C<< %{} >>,
138             C<< @{} >>, and C<< "" >>.
139              
140             # bin/benchmark.pl
141             #
142             use Benchmark;
143            
144             timethis( -3, q{
145             use Specio::Library::Builtins;
146             my $type = t( 'ArrayRef', of => t( 'HashRef', of => t( 'Str' ) ) );
147             my $arr = [ map { foo => $_ }, 1 .. 100 ];
148             for ( 0 .. 100 ) {
149             $type->check( $arr ) or die;
150             }
151             } );
152              
153             And running the benchmarks:
154              
155             $ perl -Ilib bin/benchmark.pl
156             timethis for 3: 3 wallclock secs ( 3.20 usr + 0.00 sys = 3.20 CPU) @ 271.25/s (n=868)
157             $ perl -Ilib -MSpecioX::XS bin/benchmark.pl
158             timethis for 3: 4 wallclock secs ( 3.48 usr + 0.01 sys = 3.49 CPU) @ 918.91/s (n=3207)
159              
160             On my laptop, the check runs more than three times faster with L<SpecioX::XS>.
161              
162             =head1 DESCRIPTION
163              
164             This module pokes around in Specio internals quite badly.
165             Do not use it in production situations.
166              
167             =head1 BUGS
168              
169             Please report any bugs to
170             L<http://rt.cpan.org/Dist/Display.html?Queue=SpecioX-XS>.
171              
172             =head1 SEE ALSO
173              
174             L<Specio>, L<Type::Tiny::XS>.
175              
176             =head1 AUTHOR
177              
178             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
179              
180             =head1 COPYRIGHT AND LICENCE
181              
182             This software is copyright (c) 2022 by Toby Inkster.
183              
184             This is free software; you can redistribute it and/or modify it under
185             the same terms as the Perl 5 programming language system itself.
186              
187             =head1 DISCLAIMER OF WARRANTIES
188              
189             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
190             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
191             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.